aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/c.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2024-04-29 19:58:09 -0700
committerAndrew Kelley <andrew@ziglang.org>2024-04-30 10:00:53 -0700
commit1c9bb6a79de3ca52d819177fea32ce7993634e31 (patch)
treeb417567646e316854043f775ce6d5c01793153c3 /src/codegen/c.zig
parent956f53beb09c07925970453d4c178c6feb53ba70 (diff)
downloadzig-1c9bb6a79de3ca52d819177fea32ce7993634e31.tar.gz
zig-1c9bb6a79de3ca52d819177fea32ce7993634e31.zip
C backend: avoid memcpy when len=0
As of Clang 18, calling memcpy() with a misaligned pointer trips UBSAN, even if the length is zero. This unfortunately includes any call to `@memcpy` when source or destination are undefined and the length is zero. This patch makes the C backend avoid calling memcpy when the length is zero, thereby avoiding undefined behavior. A zig1.wasm update will be needed in the llvm18 branch to activate this code.
Diffstat (limited to 'src/codegen/c.zig')
-rw-r--r--src/codegen/c.zig22
1 files changed, 16 insertions, 6 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 8e999a418a..dac7e30b5f 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -6799,11 +6799,27 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
const src_ty = f.typeOf(bin_op.rhs);
const writer = f.object.writer();
+ if (dest_ty.ptrSize(zcu) != .One) {
+ try writer.writeAll("if (");
+ try writeArrayLen(f, writer, dest_ptr, dest_ty);
+ try writer.writeAll(" != 0) ");
+ }
try writer.writeAll("memcpy(");
try writeSliceOrPtr(f, writer, dest_ptr, dest_ty);
try writer.writeAll(", ");
try writeSliceOrPtr(f, writer, src_ptr, src_ty);
try writer.writeAll(", ");
+ try writeArrayLen(f, writer, dest_ptr, dest_ty);
+ try writer.writeAll(" * sizeof(");
+ try f.renderType(writer, dest_ty.elemType2(zcu));
+ try writer.writeAll("));\n");
+
+ try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
+ return .none;
+}
+
+fn writeArrayLen(f: *Function, writer: ArrayListWriter, dest_ptr: CValue, dest_ty: Type) !void {
+ const zcu = f.object.dg.zcu;
switch (dest_ty.ptrSize(zcu)) {
.One => try writer.print("{}", .{
try f.fmtIntLiteral(try zcu.intValue(Type.usize, dest_ty.childType(zcu).arrayLen(zcu))),
@@ -6811,12 +6827,6 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
.Many, .C => unreachable,
.Slice => try f.writeCValueMember(writer, dest_ptr, .{ .identifier = "len" }),
}
- try writer.writeAll(" * sizeof(");
- try f.renderType(writer, dest_ty.elemType2(zcu));
- try writer.writeAll("));\n");
-
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
}
fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {