mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
Sema: fix memcpy alias safety incorrect math
Previously it was not multiplying by the element ABI size. Now, it uses ptr_add instructions which do math based on the element type.
This commit is contained in:
parent
5378fdffdc
commit
792bbfa301
@ -5548,7 +5548,7 @@ pub fn toPosixPath(file_path: []const u8) ![MAX_PATH_BYTES - 1:0]u8 {
|
||||
var path_with_null: [MAX_PATH_BYTES - 1:0]u8 = undefined;
|
||||
// >= rather than > to make room for the null byte
|
||||
if (file_path.len >= MAX_PATH_BYTES) return error.NameTooLong;
|
||||
mem.copy(u8, &path_with_null, file_path);
|
||||
@memcpy(path_with_null[0..file_path.len], file_path);
|
||||
path_with_null[file_path.len] = 0;
|
||||
return path_with_null;
|
||||
}
|
||||
|
||||
@ -138,12 +138,14 @@ pub const Inst = struct {
|
||||
/// The offset is in element type units, not bytes.
|
||||
/// Wrapping is undefined behavior.
|
||||
/// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.
|
||||
/// The pointer may be a slice.
|
||||
/// Uses the `ty_pl` field. Payload is `Bin`.
|
||||
ptr_add,
|
||||
/// Subtract an offset from a pointer, returning a new pointer.
|
||||
/// The offset is in element type units, not bytes.
|
||||
/// Wrapping is undefined behavior.
|
||||
/// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.
|
||||
/// The pointer may be a slice.
|
||||
/// Uses the `ty_pl` field. Payload is `Bin`.
|
||||
ptr_sub,
|
||||
/// Given two operands which can be floats, integers, or vectors, returns the
|
||||
|
||||
27
src/Sema.zig
27
src/Sema.zig
@ -21950,12 +21950,19 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
|
||||
new_src_ptr = try upgradeToArrayPtr(sema, block, src_ptr, len);
|
||||
}
|
||||
|
||||
if (dest_len != .none) {
|
||||
// Change the src from slice to a many pointer, to avoid multiple ptr
|
||||
// slice extractions in AIR instructions.
|
||||
const new_src_ptr_ty = sema.typeOf(new_src_ptr);
|
||||
if (new_src_ptr_ty.isSlice()) {
|
||||
new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty);
|
||||
}
|
||||
}
|
||||
|
||||
try sema.requireRuntimeBlock(block, src, runtime_src);
|
||||
|
||||
// Aliasing safety check.
|
||||
if (block.wantSafety()) {
|
||||
const dest_int = try block.addUnOp(.ptrtoint, new_dest_ptr);
|
||||
const src_int = try block.addUnOp(.ptrtoint, new_src_ptr);
|
||||
const len = if (len_val) |v|
|
||||
try sema.addConstant(Type.usize, v)
|
||||
else if (dest_len != .none)
|
||||
@ -21963,12 +21970,20 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
|
||||
else
|
||||
src_len;
|
||||
|
||||
// Extract raw pointer from dest slice. The AIR instructions could support them, but
|
||||
// it would cause redundant machine code instructions.
|
||||
const new_dest_ptr_ty = sema.typeOf(new_dest_ptr);
|
||||
const raw_dest_ptr = if (new_dest_ptr_ty.isSlice())
|
||||
try sema.analyzeSlicePtr(block, dest_src, new_dest_ptr, new_dest_ptr_ty)
|
||||
else
|
||||
new_dest_ptr;
|
||||
|
||||
// ok1: dest >= src + len
|
||||
// ok2: src >= dest + len
|
||||
const src_plus_len = try block.addBinOp(.add, src_int, len);
|
||||
const dest_plus_len = try block.addBinOp(.add, dest_int, len);
|
||||
const ok1 = try block.addBinOp(.cmp_gte, dest_int, src_plus_len);
|
||||
const ok2 = try block.addBinOp(.cmp_gte, src_int, dest_plus_len);
|
||||
const src_plus_len = try sema.analyzePtrArithmetic(block, src, new_src_ptr, len, .ptr_add, src_src, src);
|
||||
const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src);
|
||||
const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len);
|
||||
const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len);
|
||||
const ok = try block.addBinOp(.bit_or, ok1, ok2);
|
||||
try sema.addSafetyCheck(block, ok, .memcpy_alias);
|
||||
}
|
||||
|
||||
@ -7293,39 +7293,53 @@ pub const FuncGen = struct {
|
||||
fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
const base_ptr = try self.resolveInst(bin_op.lhs);
|
||||
const ptr = try self.resolveInst(bin_op.lhs);
|
||||
const offset = try self.resolveInst(bin_op.rhs);
|
||||
const ptr_ty = self.air.typeOf(bin_op.lhs);
|
||||
const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType());
|
||||
if (ptr_ty.ptrSize() == .One) {
|
||||
// It's a pointer to an array, so according to LLVM we need an extra GEP index.
|
||||
const indices: [2]*llvm.Value = .{
|
||||
self.context.intType(32).constNull(), offset,
|
||||
};
|
||||
return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
|
||||
} else {
|
||||
const indices: [1]*llvm.Value = .{offset};
|
||||
return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
|
||||
switch (ptr_ty.ptrSize()) {
|
||||
.One => {
|
||||
// It's a pointer to an array, so according to LLVM we need an extra GEP index.
|
||||
const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), offset };
|
||||
return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
|
||||
},
|
||||
.C, .Many => {
|
||||
const indices: [1]*llvm.Value = .{offset};
|
||||
return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
|
||||
},
|
||||
.Slice => {
|
||||
const base = self.builder.buildExtractValue(ptr, 0, "");
|
||||
const indices: [1]*llvm.Value = .{offset};
|
||||
return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, "");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
const base_ptr = try self.resolveInst(bin_op.lhs);
|
||||
const ptr = try self.resolveInst(bin_op.lhs);
|
||||
const offset = try self.resolveInst(bin_op.rhs);
|
||||
const negative_offset = self.builder.buildNeg(offset, "");
|
||||
const ptr_ty = self.air.typeOf(bin_op.lhs);
|
||||
const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType());
|
||||
if (ptr_ty.ptrSize() == .One) {
|
||||
// It's a pointer to an array, so according to LLVM we need an extra GEP index.
|
||||
const indices: [2]*llvm.Value = .{
|
||||
self.context.intType(32).constNull(), negative_offset,
|
||||
};
|
||||
return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
|
||||
} else {
|
||||
const indices: [1]*llvm.Value = .{negative_offset};
|
||||
return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
|
||||
switch (ptr_ty.ptrSize()) {
|
||||
.One => {
|
||||
// It's a pointer to an array, so according to LLVM we need an extra GEP index.
|
||||
const indices: [2]*llvm.Value = .{
|
||||
self.context.intType(32).constNull(), negative_offset,
|
||||
};
|
||||
return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
|
||||
},
|
||||
.C, .Many => {
|
||||
const indices: [1]*llvm.Value = .{negative_offset};
|
||||
return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
|
||||
},
|
||||
.Slice => {
|
||||
const base = self.builder.buildExtractValue(ptr, 0, "");
|
||||
const indices: [1]*llvm.Value = .{negative_offset};
|
||||
return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, "");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user