Commit 1ba72bcf9a

Andrew Kelley <andrew@ziglang.org>
2023-04-25 02:31:07
update test cases for new memcpy/memset semantics
1 parent 747f583
lib/std/zig/c_builtins.zig
@@ -171,10 +171,10 @@ pub inline fn __builtin_memcpy(
     noalias src: ?*const anyopaque,
     len: usize,
 ) ?*anyopaque {
-    const dst_cast = @ptrCast([*c]u8, dst);
-    const src_cast = @ptrCast([*c]const u8, src);
-
-    @memcpy(dst_cast[0..len], src_cast);
+    if (len > 0) @memcpy(
+        @ptrCast([*]u8, dst.?)[0..len],
+        @ptrCast([*]const u8, src.?),
+    );
     return dst;
 }
 
src/Sema.zig
@@ -20424,22 +20424,6 @@ fn checkPtrType(
     return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(sema.mod)});
 }
 
-fn checkSliceOrArrayType(
-    sema: *Sema,
-    block: *Block,
-    ty_src: LazySrcLoc,
-    ty: Type,
-) CompileError!void {
-    if (ty.zigTypeTag() == .Pointer) {
-        switch (ty.ptrSize()) {
-            .Slice => return,
-            .One => if (ty.childType().zigTypeTag() == .Array) return,
-            else => {},
-        }
-    }
-    return sema.fail(block, ty_src, "expected slice or array pointer; found '{}'", .{ty.fmt(sema.mod)});
-}
-
 fn checkVectorElemType(
     sema: *Sema,
     block: *Block,
@@ -21993,7 +21977,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
     const dest_ptr = try sema.resolveInst(extra.lhs);
     const uncoerced_elem = try sema.resolveInst(extra.rhs);
     const dest_ptr_ty = sema.typeOf(dest_ptr);
-    try checkSliceOrArrayType(sema, block, dest_src, dest_ptr_ty);
+    try checkIndexable(sema, block, dest_src, dest_ptr_ty);
 
     const dest_elem_ty = dest_ptr_ty.elemType2();
     const target = sema.mod.getTarget();
test/behavior/builtin_functions_returning_void_or_noreturn.zig
@@ -17,8 +17,8 @@ test {
     try testing.expectEqual(void, @TypeOf(@breakpoint()));
     try testing.expectEqual({}, @export(x, .{ .name = "x" }));
     try testing.expectEqual({}, @fence(.Acquire));
-    try testing.expectEqual({}, @memcpy(@intToPtr([*]u8, 1), @intToPtr([*]u8, 1), 0));
-    try testing.expectEqual({}, @memset(@intToPtr([*]u8, 1), undefined, 0));
+    try testing.expectEqual({}, @memcpy(@intToPtr([*]u8, 1)[0..0], @intToPtr([*]u8, 1)[0..0]));
+    try testing.expectEqual({}, @memset(@intToPtr([*]u8, 1)[0..0], undefined));
     try testing.expectEqual(noreturn, @TypeOf(if (true) @panic("") else {}));
     try testing.expectEqual({}, @prefetch(&val, .{}));
     try testing.expectEqual({}, @setAlignStack(16));
test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig
@@ -2,18 +2,35 @@ pub export fn entry() void {
     var buf: [5]u8 = .{ 1, 2, 3, 4, 5 };
     var slice: []u8 = &buf;
     const a: u32 = 1234;
-    @memcpy(slice, @ptrCast([*]const u8, &a));
+    @memcpy(slice.ptr, @ptrCast([*]const u8, &a));
 }
 pub export fn entry1() void {
     var buf: [5]u8 = .{ 1, 2, 3, 4, 5 };
     var ptr: *u8 = &buf[0];
     @memcpy(ptr, 0);
 }
+pub export fn entry2() void {
+    var buf: [5]u8 = .{ 1, 2, 3, 4, 5 };
+    var ptr: *u8 = &buf[0];
+    @memset(ptr, 0);
+}
+pub export fn non_matching_lengths() void {
+    var buf1: [5]u8 = .{ 1, 2, 3, 4, 5 };
+    var buf2: [6]u8 = .{ 1, 2, 3, 4, 5, 6 };
+    @memcpy(&buf2, &buf1);
+}
 
 // error
 // backend=stage2
 // target=native
 //
-// :5:13: error: expected type '[*]u8', found '[]u8'
-// :10:13: error: expected type '[*]u8', found '*u8'
-// :10:13: note: a single pointer cannot cast into a many pointer
+// :5:5: error: unknown @memcpy length
+// :5:18: note: destination type [*]u8 provides no length
+// :5:24: note: source type [*]align(4) const u8 provides no length
+// :10:13: error: type 'u8' does not support indexing
+// :10:13: note: for loop operand must be an array, slice, tuple, or vector
+// :15:13: error: type '*u8' does not support indexing
+// :15:13: note: for loop operand must be an array, slice, tuple, or vector
+// :20:5: error: non-matching @memcpy lengths
+// :20:13: note: length 6 here
+// :20:20: note: length 5 here
test/cases/safety/memcpy_alias.zig
@@ -0,0 +1,17 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+    _ = stack_trace;
+    if (std.mem.eql(u8, message, "@memcpy arguments alias")) {
+        std.process.exit(0);
+    }
+    std.process.exit(1);
+}
+pub fn main() !void {
+    var buffer = [2]u8{ 1, 2 } ** 5;
+    var len: usize = 5;
+    @memcpy(buffer[0..len], buffer[4 .. 4 + len]);
+}
+// run
+// backend=llvm
+// target=native
test/cases/safety/memcpy_len_mismatch.zig
@@ -0,0 +1,17 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+    _ = stack_trace;
+    if (std.mem.eql(u8, message, "@memcpy arguments have non-equal lengths")) {
+        std.process.exit(0);
+    }
+    std.process.exit(1);
+}
+pub fn main() !void {
+    var buffer = [2]u8{ 1, 2 } ** 5;
+    var len: usize = 5;
+    @memcpy(buffer[0..len], buffer[len .. len + 4]);
+}
+// run
+// backend=llvm
+// target=native
test/cases/safety/memset_array_undefined_bytes.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+    _ = stack_trace;
+    if (std.mem.eql(u8, message, "integer overflow")) {
+        std.process.exit(0);
+    }
+    std.process.exit(1);
+}
+pub fn main() !void {
+    var buffer = [6]u8{ 1, 2, 3, 4, 5, 6 };
+    @memset(&buffer, undefined);
+    var x: u8 = buffer[1];
+    x += buffer[2];
+}
+// run
+// backend=llvm
+// target=native
test/cases/safety/memset_array_undefined_large.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+    _ = stack_trace;
+    if (std.mem.eql(u8, message, "integer overflow")) {
+        std.process.exit(0);
+    }
+    std.process.exit(1);
+}
+pub fn main() !void {
+    var buffer = [6]i32{ 1, 2, 3, 4, 5, 6 };
+    @memset(&buffer, undefined);
+    var x: i32 = buffer[1];
+    x += buffer[2];
+}
+// run
+// backend=llvm
+// target=native
test/cases/safety/memset_slice_undefined_bytes.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+    _ = stack_trace;
+    if (std.mem.eql(u8, message, "integer overflow")) {
+        std.process.exit(0);
+    }
+    std.process.exit(1);
+}
+pub fn main() !void {
+    var buffer = [6]u8{ 1, 2, 3, 4, 5, 6 };
+    var len = buffer.len;
+    @memset(buffer[0..len], undefined);
+    var x: u8 = buffer[1];
+    x += buffer[2];
+}
+// run
+// backend=llvm
+// target=native
test/cases/safety/memset_slice_undefined_large.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+    _ = stack_trace;
+    if (std.mem.eql(u8, message, "integer overflow")) {
+        std.process.exit(0);
+    }
+    std.process.exit(1);
+}
+pub fn main() !void {
+    var buffer = [6]i32{ 1, 2, 3, 4, 5, 6 };
+    var len = buffer.len;
+    @memset(buffer[0..len], undefined);
+    var x: i32 = buffer[1];
+    x += buffer[2];
+}
+// run
+// backend=llvm
+// target=native
test/cases/safety/switch on corrupted union value.zig
@@ -15,7 +15,7 @@ const U = union(enum(u32)) {
 
 pub fn main() !void {
     var u: U = undefined;
-    @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
+    @memset(@ptrCast([*]u8, &u)[0..@sizeOf(U)], 0x55);
     switch (u) {
         .X, .Y => @breakpoint(),
     }