Skip to content

Commit

Permalink
C backend: avoid memcpy when len=0
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
andrewrk committed Apr 30, 2024
1 parent 956f53b commit 1c9bb6a
Showing 1 changed file with 16 additions and 6 deletions.
22 changes: 16 additions & 6 deletions src/codegen/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6799,24 +6799,34 @@ 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))),
}),
.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 {
Expand Down

0 comments on commit 1c9bb6a

Please sign in to comment.