authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-04-29 19:58:09-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-04-30 10:00:53-07:00
log1c9bb6a79de3ca52d819177fea32ce7993634e31
treeb417567646e316854043f775ce6d5c01793153c3
parent956f53beb09c07925970453d4c178c6feb53ba70

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.

1 files changed, 16 insertions(+), 6 deletions(-)

src/codegen/c.zig+16-6
......@@ -6799,11 +6799,27 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
67996799 const src_ty = f.typeOf(bin_op.rhs);
68006800 const writer = f.object.writer();
68016801
6802 if (dest_ty.ptrSize(zcu) != .One) {
6803 try writer.writeAll("if (");
6804 try writeArrayLen(f, writer, dest_ptr, dest_ty);
6805 try writer.writeAll(" != 0) ");
6806 }
68026807 try writer.writeAll("memcpy(");
68036808 try writeSliceOrPtr(f, writer, dest_ptr, dest_ty);
68046809 try writer.writeAll(", ");
68056810 try writeSliceOrPtr(f, writer, src_ptr, src_ty);
68066811 try writer.writeAll(", ");
6812 try writeArrayLen(f, writer, dest_ptr, dest_ty);
6813 try writer.writeAll(" * sizeof(");
6814 try f.renderType(writer, dest_ty.elemType2(zcu));
6815 try writer.writeAll("));\n");
6816
6817 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6818 return .none;
6819}
6820
6821fn writeArrayLen(f: *Function, writer: ArrayListWriter, dest_ptr: CValue, dest_ty: Type) !void {
6822 const zcu = f.object.dg.zcu;
68076823 switch (dest_ty.ptrSize(zcu)) {
68086824 .One => try writer.print("{}", .{
68096825 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 {
68116827 .Many, .C => unreachable,
68126828 .Slice => try f.writeCValueMember(writer, dest_ptr, .{ .identifier = "len" }),
68136829 }
6814 try writer.writeAll(" * sizeof(");
6815 try f.renderType(writer, dest_ty.elemType2(zcu));
6816 try writer.writeAll("));\n");
6817
6818 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6819 return .none;
68206830}
68216831
68226832fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {