diff --git a/lib/std/zig/c_builtins.zig b/lib/std/zig/c_builtins.zig index ea6559d4571277d9f4bb4e3e9c5e048f5d693a68..b28134c7cd8c3b68cf2d4edcdc0103c00e2df3d6 100644 --- a/lib/std/zig/c_builtins.zig +++ b/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; } diff --git a/src/Sema.zig b/src/Sema.zig index 69b09f63eadc1876c669a8d0f6f018afe168aa7c..a2d667fd78d36cad9f6f164d907ad37b13ec2e1b 100644 --- a/src/Sema.zig +++ b/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(); diff --git a/test/behavior/builtin_functions_returning_void_or_noreturn.zig b/test/behavior/builtin_functions_returning_void_or_noreturn.zig index 0d4598bd09bfd31f9d16554b8fc3c53aaed48b09..d32215c964db7a588fa77b6dd5db13c85461b922 100644 --- a/test/behavior/builtin_functions_returning_void_or_noreturn.zig +++ b/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)); diff --git a/test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig b/test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig index 37d0b8d323542f427f25b69d69569adaead70e2d..910ec807a8c73d73c7472717caa6e605e8bb8d85 100644 --- a/test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig +++ b/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 diff --git a/test/cases/safety/memcpy_alias.zig b/test/cases/safety/memcpy_alias.zig new file mode 100644 index 0000000000000000000000000000000000000000..cf2da08f0cd006586b18f48a382b4e6239fbb588 --- /dev/null +++ b/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 diff --git a/test/cases/safety/memcpy_len_mismatch.zig b/test/cases/safety/memcpy_len_mismatch.zig new file mode 100644 index 0000000000000000000000000000000000000000..b5cb887c31d7fb58a1f06a62b27c13b74c993b30 --- /dev/null +++ b/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 diff --git a/test/cases/safety/memset_array_undefined_bytes.zig b/test/cases/safety/memset_array_undefined_bytes.zig new file mode 100644 index 0000000000000000000000000000000000000000..e0ce2dac0443a75062abba0f053a3aa5cd5344ed --- /dev/null +++ b/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 diff --git a/test/cases/safety/memset_array_undefined_large.zig b/test/cases/safety/memset_array_undefined_large.zig new file mode 100644 index 0000000000000000000000000000000000000000..dbc1cf4420243a89e8253079a5939b5aa355dfda --- /dev/null +++ b/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 diff --git a/test/cases/safety/memset_slice_undefined_bytes.zig b/test/cases/safety/memset_slice_undefined_bytes.zig new file mode 100644 index 0000000000000000000000000000000000000000..70acc5fa6522369775da8b399486b7c56d78649b --- /dev/null +++ b/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 diff --git a/test/cases/safety/memset_slice_undefined_large.zig b/test/cases/safety/memset_slice_undefined_large.zig new file mode 100644 index 0000000000000000000000000000000000000000..66298993c091a0aafd5e69dae60c89b9ddb7055a --- /dev/null +++ b/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 diff --git a/test/cases/safety/switch on corrupted union value.zig b/test/cases/safety/switch on corrupted union value.zig index bfb755514a8444a2d868e5f08f26497cf9661970..745a3fd037eec5329e388ac1625635912c74eb0a 100644 --- a/test/cases/safety/switch on corrupted union value.zig +++ b/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(), }