zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 1c9bb6a79de3ca52d819177fea32ce7993634e31 (tree)
parent 956f53beb09c07925970453d4c178c6feb53ba70
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Mon, 29 Apr 2024 19:58:09 -0700

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:
Msrc/codegen/c.zig | 22++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)

diff --git 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 {