authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-12-26 17:46:28-08:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2025-02-25 11:22:33-08:00
logd669b9520b85aa5e892fe073b2c485f1bf1afef5
treed5c776bf671626f710a738058b422837c9f74507
parent14178475e35674122c65d11c8f0957c89e10506c

ubsan: clean-up a bit more


1 files changed, 53 insertions(+), 52 deletions(-)

lib/ubsan.zig+53-52
...@@ -42,19 +42,15 @@ const TypeDescriptor = extern struct {...@@ -42,19 +42,15 @@ const TypeDescriptor = extern struct {
42 }42 }
43};43};
4444
45const ValueHandle = *const opaque {45const ValueHandle = *const opaque {};
46 fn getValue(handle: ValueHandle, data: anytype) Value {
47 return .{ .handle = handle, .type_descriptor = data.type_descriptor };
48 }
49};
5046
51const Value = extern struct {47const Value = extern struct {
52 type_descriptor: *const TypeDescriptor,48 td: *const TypeDescriptor,
53 handle: ValueHandle,49 handle: ValueHandle,
5450
55 fn getUnsignedInteger(value: Value) u128 {51 fn getUnsignedInteger(value: Value) u128 {
56 assert(!value.type_descriptor.isSigned());52 assert(!value.td.isSigned());
57 const size = value.type_descriptor.getIntegerSize();53 const size = value.td.getIntegerSize();
58 const max_inline_size = @bitSizeOf(ValueHandle);54 const max_inline_size = @bitSizeOf(ValueHandle);
59 if (size <= max_inline_size) {55 if (size <= max_inline_size) {
60 return @intFromPtr(value.handle);56 return @intFromPtr(value.handle);
...@@ -68,8 +64,8 @@ const Value = extern struct {...@@ -68,8 +64,8 @@ const Value = extern struct {
68 }64 }
6965
70 fn getSignedInteger(value: Value) i128 {66 fn getSignedInteger(value: Value) i128 {
71 assert(value.type_descriptor.isSigned());67 assert(value.td.isSigned());
72 const size = value.type_descriptor.getIntegerSize();68 const size = value.td.getIntegerSize();
73 const max_inline_size = @bitSizeOf(ValueHandle);69 const max_inline_size = @bitSizeOf(ValueHandle);
74 if (size <= max_inline_size) {70 if (size <= max_inline_size) {
75 const extra_bits: std.math.Log2Int(usize) = @intCast(max_inline_size - size);71 const extra_bits: std.math.Log2Int(usize) = @intCast(max_inline_size - size);
...@@ -84,8 +80,8 @@ const Value = extern struct {...@@ -84,8 +80,8 @@ const Value = extern struct {
84 }80 }
8581
86 fn getFloat(value: Value) c_longdouble {82 fn getFloat(value: Value) c_longdouble {
87 assert(value.type_descriptor.kind == .float);83 assert(value.td.kind == .float);
88 const size = value.type_descriptor.info.float;84 const size = value.td.info.float;
89 const max_inline_size = @bitSizeOf(ValueHandle);85 const max_inline_size = @bitSizeOf(ValueHandle);
90 if (size <= max_inline_size) {86 if (size <= max_inline_size) {
91 return @bitCast(@intFromPtr(value.handle));87 return @bitCast(@intFromPtr(value.handle));
...@@ -99,17 +95,17 @@ const Value = extern struct {...@@ -99,17 +95,17 @@ const Value = extern struct {
99 }95 }
10096
101 fn isMinusOne(value: Value) bool {97 fn isMinusOne(value: Value) bool {
102 return value.type_descriptor.isSigned() and98 return value.td.isSigned() and
103 value.getSignedInteger() == -1;99 value.getSignedInteger() == -1;
104 }100 }
105101
106 fn isNegative(value: Value) bool {102 fn isNegative(value: Value) bool {
107 return value.type_descriptor.isSigned() and103 return value.td.isSigned() and
108 value.getSignedInteger() < 0;104 value.getSignedInteger() < 0;
109 }105 }
110106
111 fn getPositiveInteger(value: Value) u128 {107 fn getPositiveInteger(value: Value) u128 {
112 if (value.type_descriptor.isSigned()) {108 if (value.td.isSigned()) {
113 const signed = value.getSignedInteger();109 const signed = value.getSignedInteger();
114 assert(signed >= 0);110 assert(signed >= 0);
115 return @intCast(signed);111 return @intCast(signed);
...@@ -126,9 +122,9 @@ const Value = extern struct {...@@ -126,9 +122,9 @@ const Value = extern struct {
126 ) !void {122 ) !void {
127 comptime assert(fmt.len == 0);123 comptime assert(fmt.len == 0);
128124
129 switch (value.type_descriptor.kind) {125 switch (value.td.kind) {
130 .integer => {126 .integer => {
131 if (value.type_descriptor.isSigned()) {127 if (value.td.isSigned()) {
132 try writer.print("{}", .{value.getSignedInteger()});128 try writer.print("{}", .{value.getSignedInteger()});
133 } else {129 } else {
134 try writer.print("{}", .{value.getUnsignedInteger()});130 try writer.print("{}", .{value.getUnsignedInteger()});
...@@ -142,7 +138,7 @@ const Value = extern struct {...@@ -142,7 +138,7 @@ const Value = extern struct {
142138
143const OverflowData = extern struct {139const OverflowData = extern struct {
144 loc: SourceLocation,140 loc: SourceLocation,
145 type_descriptor: *const TypeDescriptor,141 td: *const TypeDescriptor,
146};142};
147143
148fn overflowHandler(144fn overflowHandler(
...@@ -155,10 +151,10 @@ fn overflowHandler(...@@ -155,10 +151,10 @@ fn overflowHandler(
155 lhs_handle: ValueHandle,151 lhs_handle: ValueHandle,
156 rhs_handle: ValueHandle,152 rhs_handle: ValueHandle,
157 ) callconv(.c) noreturn {153 ) callconv(.c) noreturn {
158 const lhs = lhs_handle.getValue(data);154 const lhs: Value = .{ .handle = lhs_handle, .td = data.td };
159 const rhs = rhs_handle.getValue(data);155 const rhs: Value = .{ .handle = rhs_handle, .td = data.td };
160156
161 const is_signed = data.type_descriptor.isSigned();157 const is_signed = data.td.isSigned();
162 const fmt = "{s} integer overflow: " ++ "{} " ++158 const fmt = "{s} integer overflow: " ++ "{} " ++
163 operator ++ " {} cannot be represented in type {s}";159 operator ++ " {} cannot be represented in type {s}";
164160
...@@ -166,7 +162,7 @@ fn overflowHandler(...@@ -166,7 +162,7 @@ fn overflowHandler(
166 if (is_signed) "signed" else "unsigned",162 if (is_signed) "signed" else "unsigned",
167 lhs,163 lhs,
168 rhs,164 rhs,
169 data.type_descriptor.getName(),165 data.td.getName(),
170 });166 });
171 }167 }
172 };168 };
...@@ -176,12 +172,12 @@ fn overflowHandler(...@@ -176,12 +172,12 @@ fn overflowHandler(
176172
177fn negationHandler(173fn negationHandler(
178 data: *const OverflowData,174 data: *const OverflowData,
179 old_value_handle: ValueHandle,175 value_handle: ValueHandle,
180) callconv(.c) noreturn {176) callconv(.c) noreturn {
181 const old_value = old_value_handle.getValue(data);177 const value: Value = .{ .handle = value_handle, .td = data.td };
182 logMessage(178 logMessage(
183 "negation of {} cannot be represented in type {s}",179 "negation of {} cannot be represented in type {s}",
184 .{ old_value, data.type_descriptor.getName() },180 .{ value, data.td.getName() },
185 );181 );
186}182}
187183
...@@ -190,13 +186,13 @@ fn divRemHandler(...@@ -190,13 +186,13 @@ fn divRemHandler(
190 lhs_handle: ValueHandle,186 lhs_handle: ValueHandle,
191 rhs_handle: ValueHandle,187 rhs_handle: ValueHandle,
192) callconv(.c) noreturn {188) callconv(.c) noreturn {
193 const lhs = lhs_handle.getValue(data);189 const lhs: Value = .{ .handle = lhs_handle, .td = data.lhs_type };
194 const rhs = rhs_handle.getValue(data);190 const rhs: Value = .{ .handle = rhs_handle, .td = data.rhs_type };
195191
196 if (rhs.isMinusOne()) {192 if (rhs.isMinusOne()) {
197 logMessage(193 logMessage(
198 "division of {} by -1 cannot be represented in type {s}",194 "division of {} by -1 cannot be represented in type {s}",
199 .{ lhs, data.type_descriptor.getName() },195 .{ lhs, data.td.getName() },
200 );196 );
201 } else logMessage("division by zero", .{});197 } else logMessage("division by zero", .{});
202}198}
...@@ -204,29 +200,30 @@ fn divRemHandler(...@@ -204,29 +200,30 @@ fn divRemHandler(
204const AlignmentAssumptionData = extern struct {200const AlignmentAssumptionData = extern struct {
205 loc: SourceLocation,201 loc: SourceLocation,
206 assumption_loc: SourceLocation,202 assumption_loc: SourceLocation,
207 type_descriptor: *const TypeDescriptor,203 td: *const TypeDescriptor,
208};204};
209205
210fn alignmentAssumptionHandler(206fn alignmentAssumptionHandler(
211 data: *const AlignmentAssumptionData,207 data: *const AlignmentAssumptionData,
212 pointer: ValueHandle,208 pointer: ValueHandle,
213 alignment: ValueHandle,209 alignment_handle: ValueHandle,
214 maybe_offset: ?ValueHandle,210 maybe_offset: ?ValueHandle,
215) callconv(.c) noreturn {211) callconv(.c) noreturn {
216 const real_pointer = @intFromPtr(pointer) - @intFromPtr(maybe_offset);212 const real_pointer = @intFromPtr(pointer) - @intFromPtr(maybe_offset);
217 const lsb = @ctz(real_pointer);213 const lsb = @ctz(real_pointer);
218 const actual_alignment = @as(u64, 1) << @intCast(lsb);214 const actual_alignment = @as(u64, 1) << @intCast(lsb);
219 const mask = @intFromPtr(alignment) - 1;215 const mask = @intFromPtr(alignment_handle) - 1;
220 const misalignment_offset = real_pointer & mask;216 const misalignment_offset = real_pointer & mask;
217 const alignment: Value = .{ .handle = alignment_handle, .td = data.td };
221218
222 if (maybe_offset) |offset| {219 if (maybe_offset) |offset| {
223 logMessage(220 logMessage(
224 "assumption of {} byte alignment (with offset of {} byte) for pointer of type {s} failed\n" ++221 "assumption of {} byte alignment (with offset of {} byte) for pointer of type {s} failed\n" ++
225 "offset address is {} aligned, misalignment offset is {} bytes",222 "offset address is {} aligned, misalignment offset is {} bytes",
226 .{223 .{
227 alignment.getValue(data),224 alignment,
228 @intFromPtr(offset),225 @intFromPtr(offset),
229 data.type_descriptor.getName(),226 data.td.getName(),
230 actual_alignment,227 actual_alignment,
231 misalignment_offset,228 misalignment_offset,
232 },229 },
...@@ -236,8 +233,8 @@ fn alignmentAssumptionHandler(...@@ -236,8 +233,8 @@ fn alignmentAssumptionHandler(
236 "assumption of {} byte alignment for pointer of type {s} failed\n" ++233 "assumption of {} byte alignment for pointer of type {s} failed\n" ++
237 "address is {} aligned, misalignment offset is {} bytes",234 "address is {} aligned, misalignment offset is {} bytes",
238 .{235 .{
239 alignment.getValue(data),236 alignment,
240 data.type_descriptor.getName(),237 data.td.getName(),
241 actual_alignment,238 actual_alignment,
242 misalignment_offset,239 misalignment_offset,
243 },240 },
...@@ -256,8 +253,8 @@ fn shiftOob(...@@ -256,8 +253,8 @@ fn shiftOob(
256 lhs_handle: ValueHandle,253 lhs_handle: ValueHandle,
257 rhs_handle: ValueHandle,254 rhs_handle: ValueHandle,
258) callconv(.c) noreturn {255) callconv(.c) noreturn {
259 const lhs: Value = .{ .handle = lhs_handle, .type_descriptor = data.lhs_type };256 const lhs: Value = .{ .handle = lhs_handle, .td = data.lhs_type };
260 const rhs: Value = .{ .handle = rhs_handle, .type_descriptor = data.rhs_type };257 const rhs: Value = .{ .handle = rhs_handle, .td = data.rhs_type };
261258
262 if (rhs.isNegative() or259 if (rhs.isNegative() or
263 rhs.getPositiveInteger() >= data.lhs_type.getIntegerSize())260 rhs.getPositiveInteger() >= data.lhs_type.getIntegerSize())
...@@ -289,7 +286,7 @@ const OutOfBoundsData = extern struct {...@@ -289,7 +286,7 @@ const OutOfBoundsData = extern struct {
289};286};
290287
291fn outOfBounds(data: *const OutOfBoundsData, index_handle: ValueHandle) callconv(.c) noreturn {288fn outOfBounds(data: *const OutOfBoundsData, index_handle: ValueHandle) callconv(.c) noreturn {
292 const index: Value = .{ .handle = index_handle, .type_descriptor = data.index_type };289 const index: Value = .{ .handle = index_handle, .td = data.index_type };
293 logMessage(290 logMessage(
294 "index {} out of bounds for type {s}",291 "index {} out of bounds for type {s}",
295 .{ index, data.array_type.getName() },292 .{ index, data.array_type.getName() },
...@@ -344,7 +341,7 @@ fn pointerOverflow(...@@ -344,7 +341,7 @@ fn pointerOverflow(
344341
345const TypeMismatchData = extern struct {342const TypeMismatchData = extern struct {
346 loc: SourceLocation,343 loc: SourceLocation,
347 type_descriptor: *const TypeDescriptor,344 td: *const TypeDescriptor,
348 log_alignment: u8,345 log_alignment: u8,
349 kind: enum(u8) {346 kind: enum(u8) {
350 load,347 load,
...@@ -388,17 +385,17 @@ fn typeMismatch(...@@ -388,17 +385,17 @@ fn typeMismatch(
388 if (pointer == null) {385 if (pointer == null) {
389 logMessage(386 logMessage(
390 "{s} null pointer of type {s}",387 "{s} null pointer of type {s}",
391 .{ data.kind.getName(), data.type_descriptor.getName() },388 .{ data.kind.getName(), data.td.getName() },
392 );389 );
393 } else if (!std.mem.isAligned(handle, alignment)) {390 } else if (!std.mem.isAligned(handle, alignment)) {
394 logMessage(391 logMessage(
395 "{s} misaligned address 0x{x} for type {s}, which requires {} byte alignment",392 "{s} misaligned address 0x{x} for type {s}, which requires {} byte alignment",
396 .{ data.kind.getName(), handle, data.type_descriptor.getName(), alignment },393 .{ data.kind.getName(), handle, data.td.getName(), alignment },
397 );394 );
398 } else {395 } else {
399 logMessage(396 logMessage(
400 "{s} address 0x{x} with insufficient space for an object of type {s}",397 "{s} address 0x{x} with insufficient space for an object of type {s}",
401 .{ data.kind.getName(), handle, data.type_descriptor.getName() },398 .{ data.kind.getName(), handle, data.td.getName() },
402 );399 );
403 }400 }
404}401}
...@@ -438,16 +435,18 @@ fn nonNullArg(data: *const NonNullArgData) callconv(.c) noreturn {...@@ -438,16 +435,18 @@ fn nonNullArg(data: *const NonNullArgData) callconv(.c) noreturn {
438435
439const InvalidValueData = extern struct {436const InvalidValueData = extern struct {
440 loc: SourceLocation,437 loc: SourceLocation,
441 type_descriptor: *const TypeDescriptor,438 td: *const TypeDescriptor,
442};439};
443440
444fn loadInvalidValue(441fn loadInvalidValue(
445 data: *const InvalidValueData,442 data: *const InvalidValueData,
446 value_handle: ValueHandle,443 value_handle: ValueHandle,
447) callconv(.c) noreturn {444) callconv(.c) noreturn {
448 logMessage("load of value {}, which is not valid for type {s}", .{445 const value: Value = .{ .handle = value_handle, .td = data.td };
449 value_handle.getValue(data), data.type_descriptor.getName(),446 logMessage(
450 });447 "load of value {}, which is not valid for type {s}",
448 .{ value, data.td.getName() },
449 );
451}450}
452451
453const InvalidBuiltinData = extern struct {452const InvalidBuiltinData = extern struct {
...@@ -467,16 +466,18 @@ fn invalidBuiltin(data: *const InvalidBuiltinData) callconv(.c) noreturn {...@@ -467,16 +466,18 @@ fn invalidBuiltin(data: *const InvalidBuiltinData) callconv(.c) noreturn {
467466
468const VlaBoundNotPositive = extern struct {467const VlaBoundNotPositive = extern struct {
469 loc: SourceLocation,468 loc: SourceLocation,
470 type_descriptor: *const TypeDescriptor,469 td: *const TypeDescriptor,
471};470};
472471
473fn vlaBoundNotPositive(472fn vlaBoundNotPositive(
474 data: *const VlaBoundNotPositive,473 data: *const VlaBoundNotPositive,
475 bound_handle: ValueHandle,474 bound_handle: ValueHandle,
476) callconv(.c) noreturn {475) callconv(.c) noreturn {
477 logMessage("variable length array bound evaluates to non-positive value {}", .{476 const bound: Value = .{ .handle = bound_handle, .td = data.td };
478 bound_handle.getValue(data),477 logMessage(
479 });478 "variable length array bound evaluates to non-positive value {}",
479 .{bound},
480 );
480}481}
481482
482const FloatCastOverflowData = extern struct {483const FloatCastOverflowData = extern struct {
...@@ -499,13 +500,13 @@ fn floatCastOverflow(...@@ -499,13 +500,13 @@ fn floatCastOverflow(
499 const ptr: [*]const u8 = @ptrCast(data_handle);500 const ptr: [*]const u8 = @ptrCast(data_handle);
500 if (@as(u16, ptr[0]) + @as(u16, ptr[1]) < 2 or ptr[0] == 0xFF or ptr[1] == 0xFF) {501 if (@as(u16, ptr[0]) + @as(u16, ptr[1]) < 2 or ptr[0] == 0xFF or ptr[1] == 0xFF) {
501 const data: *const FloatCastOverflowData = @ptrCast(data_handle);502 const data: *const FloatCastOverflowData = @ptrCast(data_handle);
502 const from_value: Value = .{ .handle = from_handle, .type_descriptor = data.from };503 const from_value: Value = .{ .handle = from_handle, .td = data.from };
503 logMessage("{} is outside the range of representable values of type {s}", .{504 logMessage("{} is outside the range of representable values of type {s}", .{
504 from_value, data.to.getName(),505 from_value, data.to.getName(),
505 });506 });
506 } else {507 } else {
507 const data: *const FloatCastOverflowDataV2 = @ptrCast(data_handle);508 const data: *const FloatCastOverflowDataV2 = @ptrCast(data_handle);
508 const from_value: Value = .{ .handle = from_handle, .type_descriptor = data.from };509 const from_value: Value = .{ .handle = from_handle, .td = data.from };
509 logMessage("{} is outside the range of representable values of type {s}", .{510 logMessage("{} is outside the range of representable values of type {s}", .{
510 from_value, data.to.getName(),511 from_value, data.to.getName(),
511 });512 });