diff --git a/lib/ubsan.zig b/lib/ubsan.zig index 5b94649cd7..05950299f9 100644 --- a/lib/ubsan.zig +++ b/lib/ubsan.zig @@ -42,19 +42,15 @@ const TypeDescriptor = extern struct { } }; -const ValueHandle = *const opaque { - fn getValue(handle: ValueHandle, data: anytype) Value { - return .{ .handle = handle, .type_descriptor = data.type_descriptor }; - } -}; +const ValueHandle = *const opaque {}; const Value = extern struct { - type_descriptor: *const TypeDescriptor, + td: *const TypeDescriptor, handle: ValueHandle, fn getUnsignedInteger(value: Value) u128 { - assert(!value.type_descriptor.isSigned()); - const size = value.type_descriptor.getIntegerSize(); + assert(!value.td.isSigned()); + const size = value.td.getIntegerSize(); const max_inline_size = @bitSizeOf(ValueHandle); if (size <= max_inline_size) { return @intFromPtr(value.handle); @@ -68,8 +64,8 @@ const Value = extern struct { } fn getSignedInteger(value: Value) i128 { - assert(value.type_descriptor.isSigned()); - const size = value.type_descriptor.getIntegerSize(); + assert(value.td.isSigned()); + const size = value.td.getIntegerSize(); const max_inline_size = @bitSizeOf(ValueHandle); if (size <= max_inline_size) { const extra_bits: std.math.Log2Int(usize) = @intCast(max_inline_size - size); @@ -84,8 +80,8 @@ const Value = extern struct { } fn getFloat(value: Value) c_longdouble { - assert(value.type_descriptor.kind == .float); - const size = value.type_descriptor.info.float; + assert(value.td.kind == .float); + const size = value.td.info.float; const max_inline_size = @bitSizeOf(ValueHandle); if (size <= max_inline_size) { return @bitCast(@intFromPtr(value.handle)); @@ -99,17 +95,17 @@ const Value = extern struct { } fn isMinusOne(value: Value) bool { - return value.type_descriptor.isSigned() and + return value.td.isSigned() and value.getSignedInteger() == -1; } fn isNegative(value: Value) bool { - return value.type_descriptor.isSigned() and + return value.td.isSigned() and value.getSignedInteger() < 0; } fn getPositiveInteger(value: Value) u128 { - if (value.type_descriptor.isSigned()) { + if (value.td.isSigned()) { const signed = value.getSignedInteger(); assert(signed >= 0); return @intCast(signed); @@ -126,9 +122,9 @@ const Value = extern struct { ) !void { comptime assert(fmt.len == 0); - switch (value.type_descriptor.kind) { + switch (value.td.kind) { .integer => { - if (value.type_descriptor.isSigned()) { + if (value.td.isSigned()) { try writer.print("{}", .{value.getSignedInteger()}); } else { try writer.print("{}", .{value.getUnsignedInteger()}); @@ -142,7 +138,7 @@ const Value = extern struct { const OverflowData = extern struct { loc: SourceLocation, - type_descriptor: *const TypeDescriptor, + td: *const TypeDescriptor, }; fn overflowHandler( @@ -155,10 +151,10 @@ fn overflowHandler( lhs_handle: ValueHandle, rhs_handle: ValueHandle, ) callconv(.c) noreturn { - const lhs = lhs_handle.getValue(data); - const rhs = rhs_handle.getValue(data); + const lhs: Value = .{ .handle = lhs_handle, .td = data.td }; + const rhs: Value = .{ .handle = rhs_handle, .td = data.td }; - const is_signed = data.type_descriptor.isSigned(); + const is_signed = data.td.isSigned(); const fmt = "{s} integer overflow: " ++ "{} " ++ operator ++ " {} cannot be represented in type {s}"; @@ -166,7 +162,7 @@ fn overflowHandler( if (is_signed) "signed" else "unsigned", lhs, rhs, - data.type_descriptor.getName(), + data.td.getName(), }); } }; @@ -176,12 +172,12 @@ fn overflowHandler( fn negationHandler( data: *const OverflowData, - old_value_handle: ValueHandle, + value_handle: ValueHandle, ) callconv(.c) noreturn { - const old_value = old_value_handle.getValue(data); + const value: Value = .{ .handle = value_handle, .td = data.td }; logMessage( "negation of {} cannot be represented in type {s}", - .{ old_value, data.type_descriptor.getName() }, + .{ value, data.td.getName() }, ); } @@ -190,13 +186,13 @@ fn divRemHandler( lhs_handle: ValueHandle, rhs_handle: ValueHandle, ) callconv(.c) noreturn { - const lhs = lhs_handle.getValue(data); - const rhs = rhs_handle.getValue(data); + const lhs: Value = .{ .handle = lhs_handle, .td = data.lhs_type }; + const rhs: Value = .{ .handle = rhs_handle, .td = data.rhs_type }; if (rhs.isMinusOne()) { logMessage( "division of {} by -1 cannot be represented in type {s}", - .{ lhs, data.type_descriptor.getName() }, + .{ lhs, data.td.getName() }, ); } else logMessage("division by zero", .{}); } @@ -204,29 +200,30 @@ fn divRemHandler( const AlignmentAssumptionData = extern struct { loc: SourceLocation, assumption_loc: SourceLocation, - type_descriptor: *const TypeDescriptor, + td: *const TypeDescriptor, }; fn alignmentAssumptionHandler( data: *const AlignmentAssumptionData, pointer: ValueHandle, - alignment: ValueHandle, + alignment_handle: ValueHandle, maybe_offset: ?ValueHandle, ) callconv(.c) noreturn { const real_pointer = @intFromPtr(pointer) - @intFromPtr(maybe_offset); const lsb = @ctz(real_pointer); const actual_alignment = @as(u64, 1) << @intCast(lsb); - const mask = @intFromPtr(alignment) - 1; + const mask = @intFromPtr(alignment_handle) - 1; const misalignment_offset = real_pointer & mask; + const alignment: Value = .{ .handle = alignment_handle, .td = data.td }; if (maybe_offset) |offset| { logMessage( "assumption of {} byte alignment (with offset of {} byte) for pointer of type {s} failed\n" ++ "offset address is {} aligned, misalignment offset is {} bytes", .{ - alignment.getValue(data), + alignment, @intFromPtr(offset), - data.type_descriptor.getName(), + data.td.getName(), actual_alignment, misalignment_offset, }, @@ -236,8 +233,8 @@ fn alignmentAssumptionHandler( "assumption of {} byte alignment for pointer of type {s} failed\n" ++ "address is {} aligned, misalignment offset is {} bytes", .{ - alignment.getValue(data), - data.type_descriptor.getName(), + alignment, + data.td.getName(), actual_alignment, misalignment_offset, }, @@ -256,8 +253,8 @@ fn shiftOob( lhs_handle: ValueHandle, rhs_handle: ValueHandle, ) callconv(.c) noreturn { - const lhs: Value = .{ .handle = lhs_handle, .type_descriptor = data.lhs_type }; - const rhs: Value = .{ .handle = rhs_handle, .type_descriptor = data.rhs_type }; + const lhs: Value = .{ .handle = lhs_handle, .td = data.lhs_type }; + const rhs: Value = .{ .handle = rhs_handle, .td = data.rhs_type }; if (rhs.isNegative() or rhs.getPositiveInteger() >= data.lhs_type.getIntegerSize()) @@ -289,7 +286,7 @@ const OutOfBoundsData = extern struct { }; fn outOfBounds(data: *const OutOfBoundsData, index_handle: ValueHandle) callconv(.c) noreturn { - const index: Value = .{ .handle = index_handle, .type_descriptor = data.index_type }; + const index: Value = .{ .handle = index_handle, .td = data.index_type }; logMessage( "index {} out of bounds for type {s}", .{ index, data.array_type.getName() }, @@ -344,7 +341,7 @@ fn pointerOverflow( const TypeMismatchData = extern struct { loc: SourceLocation, - type_descriptor: *const TypeDescriptor, + td: *const TypeDescriptor, log_alignment: u8, kind: enum(u8) { load, @@ -388,17 +385,17 @@ fn typeMismatch( if (pointer == null) { logMessage( "{s} null pointer of type {s}", - .{ data.kind.getName(), data.type_descriptor.getName() }, + .{ data.kind.getName(), data.td.getName() }, ); } else if (!std.mem.isAligned(handle, alignment)) { logMessage( "{s} misaligned address 0x{x} for type {s}, which requires {} byte alignment", - .{ data.kind.getName(), handle, data.type_descriptor.getName(), alignment }, + .{ data.kind.getName(), handle, data.td.getName(), alignment }, ); } else { logMessage( "{s} address 0x{x} with insufficient space for an object of type {s}", - .{ data.kind.getName(), handle, data.type_descriptor.getName() }, + .{ data.kind.getName(), handle, data.td.getName() }, ); } } @@ -438,16 +435,18 @@ fn nonNullArg(data: *const NonNullArgData) callconv(.c) noreturn { const InvalidValueData = extern struct { loc: SourceLocation, - type_descriptor: *const TypeDescriptor, + td: *const TypeDescriptor, }; fn loadInvalidValue( data: *const InvalidValueData, value_handle: ValueHandle, ) callconv(.c) noreturn { - logMessage("load of value {}, which is not valid for type {s}", .{ - value_handle.getValue(data), data.type_descriptor.getName(), - }); + const value: Value = .{ .handle = value_handle, .td = data.td }; + logMessage( + "load of value {}, which is not valid for type {s}", + .{ value, data.td.getName() }, + ); } const InvalidBuiltinData = extern struct { @@ -467,16 +466,18 @@ fn invalidBuiltin(data: *const InvalidBuiltinData) callconv(.c) noreturn { const VlaBoundNotPositive = extern struct { loc: SourceLocation, - type_descriptor: *const TypeDescriptor, + td: *const TypeDescriptor, }; fn vlaBoundNotPositive( data: *const VlaBoundNotPositive, bound_handle: ValueHandle, ) callconv(.c) noreturn { - logMessage("variable length array bound evaluates to non-positive value {}", .{ - bound_handle.getValue(data), - }); + const bound: Value = .{ .handle = bound_handle, .td = data.td }; + logMessage( + "variable length array bound evaluates to non-positive value {}", + .{bound}, + ); } const FloatCastOverflowData = extern struct { @@ -499,13 +500,13 @@ fn floatCastOverflow( const ptr: [*]const u8 = @ptrCast(data_handle); if (@as(u16, ptr[0]) + @as(u16, ptr[1]) < 2 or ptr[0] == 0xFF or ptr[1] == 0xFF) { const data: *const FloatCastOverflowData = @ptrCast(data_handle); - const from_value: Value = .{ .handle = from_handle, .type_descriptor = data.from }; + const from_value: Value = .{ .handle = from_handle, .td = data.from }; logMessage("{} is outside the range of representable values of type {s}", .{ from_value, data.to.getName(), }); } else { const data: *const FloatCastOverflowDataV2 = @ptrCast(data_handle); - const from_value: Value = .{ .handle = from_handle, .type_descriptor = data.from }; + const from_value: Value = .{ .handle = from_handle, .td = data.from }; logMessage("{} is outside the range of representable values of type {s}", .{ from_value, data.to.getName(), });