mirror of
https://github.com/ziglang/zig.git
synced 2026-01-06 13:33:21 +00:00
TypedValue: do not crash when failing to dereference pointer
All of the logic in `Value.elemValue` is quite questionable, but printing an error is definitely better than crashing. Notably, this should stop us from hitting crashes when dumping AIR.
This commit is contained in:
parent
2da62a7106
commit
0182b7242e
@ -135,9 +135,10 @@ pub fn print(
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) {
|
||||
const maybe_elem_val = payload.ptr.maybeElemValue(mod, i) catch |err| switch (err) {
|
||||
error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic
|
||||
};
|
||||
const elem_val = maybe_elem_val orelse return writer.writeAll(".{ (reinterpreted data) }");
|
||||
if (elem_val.isUndef(mod)) break :str;
|
||||
buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str;
|
||||
}
|
||||
@ -153,9 +154,10 @@ pub fn print(
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) {
|
||||
const maybe_elem_val = payload.ptr.maybeElemValue(mod, i) catch |err| switch (err) {
|
||||
error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic
|
||||
};
|
||||
const elem_val = maybe_elem_val orelse return writer.writeAll("(reinterpreted data) }");
|
||||
try print(.{
|
||||
.ty = elem_ty,
|
||||
.val = elem_val,
|
||||
@ -272,7 +274,8 @@ pub fn print(
|
||||
const max_len = @min(len, max_string_len);
|
||||
var buf: [max_string_len]u8 = undefined;
|
||||
for (buf[0..max_len], 0..) |*c, i| {
|
||||
const elem = try val.elemValue(mod, i);
|
||||
const maybe_elem = try val.maybeElemValue(mod, i);
|
||||
const elem = maybe_elem orelse return writer.writeAll(".{ (reinterpreted data) }");
|
||||
if (elem.isUndef(mod)) break :str;
|
||||
c.* = @as(u8, @intCast(elem.toUnsignedInt(mod)));
|
||||
}
|
||||
@ -283,9 +286,11 @@ pub fn print(
|
||||
const max_len = @min(len, max_aggregate_items);
|
||||
for (0..max_len) |i| {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
const maybe_elem = try val.maybeElemValue(mod, i);
|
||||
const elem = maybe_elem orelse return writer.writeAll("(reinterpreted data) }");
|
||||
try print(.{
|
||||
.ty = elem_ty,
|
||||
.val = try val.elemValue(mod, i),
|
||||
.val = elem,
|
||||
}, writer, level - 1, mod);
|
||||
}
|
||||
if (len > max_aggregate_items) {
|
||||
|
||||
@ -1520,33 +1520,38 @@ pub const Value = struct {
|
||||
/// Asserts the value is a single-item pointer to an array, or an array,
|
||||
/// or an unknown-length pointer, and returns the element value at the index.
|
||||
pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {
|
||||
return (try val.maybeElemValue(mod, index)).?;
|
||||
}
|
||||
|
||||
/// Like `elemValue`, but returns `null` instead of asserting on failure.
|
||||
pub fn maybeElemValue(val: Value, mod: *Module, index: usize) Allocator.Error!?Value {
|
||||
return switch (val.ip_index) {
|
||||
.none => switch (val.tag()) {
|
||||
.bytes => try mod.intValue(Type.u8, val.castTag(.bytes).?.data[index]),
|
||||
.repeated => val.castTag(.repeated).?.data,
|
||||
.aggregate => val.castTag(.aggregate).?.data[index],
|
||||
.slice => val.castTag(.slice).?.data.ptr.elemValue(mod, index),
|
||||
else => unreachable,
|
||||
.slice => val.castTag(.slice).?.data.ptr.maybeElemValue(mod, index),
|
||||
else => null,
|
||||
},
|
||||
else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.undef => |ty| (try mod.intern(.{
|
||||
.undef = ty.toType().elemType2(mod).toIntern(),
|
||||
})).toValue(),
|
||||
.ptr => |ptr| switch (ptr.addr) {
|
||||
.decl => |decl| mod.declPtr(decl).val.elemValue(mod, index),
|
||||
.decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index),
|
||||
.mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod))
|
||||
.toValue().elemValue(mod, index),
|
||||
.int, .eu_payload => unreachable,
|
||||
.opt_payload => |base| base.toValue().elemValue(mod, index),
|
||||
.comptime_field => |field_val| field_val.toValue().elemValue(mod, index),
|
||||
.elem => |elem| elem.base.toValue().elemValue(mod, index + @as(usize, @intCast(elem.index))),
|
||||
.toValue().maybeElemValue(mod, index),
|
||||
.int, .eu_payload => null,
|
||||
.opt_payload => |base| base.toValue().maybeElemValue(mod, index),
|
||||
.comptime_field => |field_val| field_val.toValue().maybeElemValue(mod, index),
|
||||
.elem => |elem| elem.base.toValue().maybeElemValue(mod, index + @as(usize, @intCast(elem.index))),
|
||||
.field => |field| if (field.base.toValue().pointerDecl(mod)) |decl_index| {
|
||||
const base_decl = mod.declPtr(decl_index);
|
||||
const field_val = try base_decl.val.fieldValue(mod, @as(usize, @intCast(field.index)));
|
||||
return field_val.elemValue(mod, index);
|
||||
} else unreachable,
|
||||
return field_val.maybeElemValue(mod, index);
|
||||
} else null,
|
||||
},
|
||||
.opt => |opt| opt.val.toValue().elemValue(mod, index),
|
||||
.opt => |opt| opt.val.toValue().maybeElemValue(mod, index),
|
||||
.aggregate => |aggregate| {
|
||||
const len = mod.intern_pool.aggregateTypeLen(aggregate.ty);
|
||||
if (index < len) return switch (aggregate.storage) {
|
||||
@ -1560,7 +1565,7 @@ pub const Value = struct {
|
||||
assert(index == len);
|
||||
return mod.intern_pool.indexToKey(aggregate.ty).array_type.sentinel.toValue();
|
||||
},
|
||||
else => unreachable,
|
||||
else => null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user