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-05-01 12:05:12-07:00
logfa5011aa3166ace57a1c02158b04e8025900bb56
tree9a989a26fc3b7dd40c0a5178ac7abe56dd1496fd
parent595a7f8b0839d272a4cef738354fb13fe96e1db9

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 {...@@ -6799,11 +6799,27 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
6799 const src_ty = f.typeOf(bin_op.rhs);6799 const src_ty = f.typeOf(bin_op.rhs);
6800 const writer = f.object.writer();6800 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 }
6802 try writer.writeAll("memcpy(");6807 try writer.writeAll("memcpy(");
6803 try writeSliceOrPtr(f, writer, dest_ptr, dest_ty);6808 try writeSliceOrPtr(f, writer, dest_ptr, dest_ty);
6804 try writer.writeAll(", ");6809 try writer.writeAll(", ");
6805 try writeSliceOrPtr(f, writer, src_ptr, src_ty);6810 try writeSliceOrPtr(f, writer, src_ptr, src_ty);
6806 try writer.writeAll(", ");6811 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;
6807 switch (dest_ty.ptrSize(zcu)) {6823 switch (dest_ty.ptrSize(zcu)) {
6808 .One => try writer.print("{}", .{6824 .One => try writer.print("{}", .{
6809 try f.fmtIntLiteral(try zcu.intValue(Type.usize, dest_ty.childType(zcu).arrayLen(zcu))),6825 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 {...@@ -6811,12 +6827,6 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
6811 .Many, .C => unreachable,6827 .Many, .C => unreachable,
6812 .Slice => try f.writeCValueMember(writer, dest_ptr, .{ .identifier = "len" }),6828 .Slice => try f.writeCValueMember(writer, dest_ptr, .{ .identifier = "len" }),
6813 }6829 }
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;
6820}6830}
68216831
6822fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {6832fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {