authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-05-14 12:48:11+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-05-15 10:31:24+03:00
logab5a72f6ca9446820f3f516873e1b5d1aeefb5a8
tree9c0320b0a067d6ea8fd3b7831cc6e1de55dfc5fa
parent2ce9122a009efa0a5d2857a0d29ad3d77a81dff1

Sema: ensure dest ptr of memcpy has length

Closes #15513

2 files changed, 33 insertions(+), 0 deletions(-)

src/Sema.zig+12
...@@ -22130,6 +22130,14 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -22130,6 +22130,14 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
22130 const ok = try block.addBinOp(.cmp_eq, dest_len, src_len);22130 const ok = try block.addBinOp(.cmp_eq, dest_len, src_len);
22131 try sema.addSafetyCheck(block, ok, .memcpy_len_mismatch);22131 try sema.addSafetyCheck(block, ok, .memcpy_len_mismatch);
22132 }22132 }
22133 } else if (dest_len != .none) {
22134 if (try sema.resolveDefinedValue(block, dest_src, dest_len)) |dest_len_val| {
22135 len_val = dest_len_val;
22136 }
22137 } else if (src_len != .none) {
22138 if (try sema.resolveDefinedValue(block, src_src, src_len)) |src_len_val| {
22139 len_val = src_len_val;
22140 }
22133 }22141 }
2213422142
22135 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: {22143 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: {
...@@ -22213,6 +22221,10 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -22213,6 +22221,10 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
22213 if (new_src_ptr_ty.isSlice()) {22221 if (new_src_ptr_ty.isSlice()) {
22214 new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty);22222 new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty);
22215 }22223 }
22224 } else if (dest_len == .none and len_val == null) {
22225 // Change the dest to a slice, since its type must have the length.
22226 const dest_ptr_ptr = try sema.analyzeRef(block, dest_src, new_dest_ptr);
22227 new_dest_ptr = try sema.analyzeSlice(block, dest_src, dest_ptr_ptr, .zero, src_len, .none, .unneeded, dest_src, dest_src, dest_src, false);
22216 }22228 }
2221722229
22218 try sema.requireRuntimeBlock(block, src, runtime_src);22230 try sema.requireRuntimeBlock(block, src, runtime_src);
test/behavior/memcpy.zig+21
...@@ -44,3 +44,24 @@ fn testMemcpyBothSinglePtrArrayOneIsNullTerminated() !void {...@@ -44,3 +44,24 @@ fn testMemcpyBothSinglePtrArrayOneIsNullTerminated() !void {
44 try expect(buf[98] == 'l');44 try expect(buf[98] == 'l');
45 try expect(buf[99] == 'o');45 try expect(buf[99] == 'o');
46}46}
47
48test "@memcpy dest many pointer" {
49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
51 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
52 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
53
54 try testMemcpyDestManyPtr();
55 try comptime testMemcpyDestManyPtr();
56}
57
58fn testMemcpyDestManyPtr() !void {
59 var str = "hello".*;
60 var buf: [5]u8 = undefined;
61 @memcpy(@ptrCast([*]u8, &buf), @ptrCast([*]const u8, &str)[0..5]);
62 try expect(buf[0] == 'h');
63 try expect(buf[1] == 'e');
64 try expect(buf[2] == 'l');
65 try expect(buf[3] == 'l');
66 try expect(buf[4] == 'o');
67}