InternPool: make more use of NullTerminatedString.Slice

This should avoid the random pointer invalidation crashes.

Closes #18954
This commit is contained in:
Jacob Young 2024-02-16 03:13:25 +01:00 committed by Andrew Kelley
parent 0183b44bb1
commit 6f08e17229
9 changed files with 70 additions and 61 deletions

View File

@ -12619,8 +12619,9 @@ fn analyzeSwitchRuntimeBlock(
operand_ty.fmt(mod),
});
}
for (0..operand_ty.errorSetNames(mod).len) |i| {
const error_name = operand_ty.errorSetNames(mod)[i];
const error_names = operand_ty.errorSetNames(mod);
for (0..error_names.len) |name_index| {
const error_name = error_names.get(ip)[name_index];
if (seen_errors.contains(error_name)) continue;
cases_len += 1;
@ -22362,8 +22363,9 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
if (!operand_ty.isAnyError(mod) and operand_ty.errorSetIsEmpty(mod)) break :disjoint true;
if (dest_ty.isAnyError(mod)) break :disjoint false;
if (operand_ty.isAnyError(mod)) break :disjoint false;
for (dest_ty.errorSetNames(mod)) |dest_err_name| {
if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name))
const dest_err_names = dest_ty.errorSetNames(mod);
for (0..dest_err_names.len) |dest_err_index| {
if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_names.get(ip)[dest_err_index]))
break :disjoint false;
}
@ -22375,8 +22377,8 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
_ = try sema.resolveInferredErrorSetTy(block, src, dest_ty.toIntern());
_ = try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty.toIntern());
for (dest_ty.errorSetNames(mod)) |dest_err_name| {
if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name))
for (0..dest_err_names.len) |dest_err_index| {
if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_names.get(ip)[dest_err_index]))
break :disjoint false;
}
@ -38780,17 +38782,18 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
/// Asserts that lhs and rhs are both error sets and are resolved.
fn errorSetMerge(sema: *Sema, lhs: Type, rhs: Type) !Type {
const mod = sema.mod;
const ip = &mod.intern_pool;
const arena = sema.arena;
const lhs_names = lhs.errorSetNames(mod);
const rhs_names = rhs.errorSetNames(mod);
var names: InferredErrorSet.NameMap = .{};
try names.ensureUnusedCapacity(arena, lhs_names.len);
for (lhs_names) |name| {
names.putAssumeCapacityNoClobber(name, {});
for (0..lhs_names.len) |lhs_index| {
names.putAssumeCapacityNoClobber(lhs_names.get(ip)[lhs_index], {});
}
for (rhs_names) |name| {
try names.put(arena, name, {});
for (0..rhs_names.len) |rhs_index| {
try names.put(arena, rhs_names.get(ip)[rhs_index], {});
}
return mod.errorSetFromUnsortedNames(names.keys());

View File

@ -7216,13 +7216,14 @@ fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
const mod = func.bin_file.base.comp.module.?;
const ip = &mod.intern_pool;
const enum_decl_index = enum_ty.getOwnerDecl(mod);
var arena_allocator = std.heap.ArenaAllocator.init(func.gpa);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
const fqn = mod.intern_pool.stringToSlice(try mod.declPtr(enum_decl_index).getFullyQualifiedName(mod));
const fqn = ip.stringToSlice(try mod.declPtr(enum_decl_index).getFullyQualifiedName(mod));
const func_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn});
// check if we already generated code for this.
@ -7252,9 +7253,9 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
// TODO: Make switch implementation generic so we can use a jump table for this when the tags are not sparse.
// generate an if-else chain for each tag value as well as constant.
for (enum_ty.enumFields(mod), 0..) |tag_name_ip, field_index_usize| {
const field_index = @as(u32, @intCast(field_index_usize));
const tag_name = mod.intern_pool.stringToSlice(tag_name_ip);
const tag_names = enum_ty.enumFields(mod);
for (0..tag_names.len) |tag_index| {
const tag_name = ip.stringToSlice(tag_names.get(ip)[tag_index]);
// for each tag name, create an unnamed const,
// and then get a pointer to its value.
const name_ty = try mod.arrayType(.{
@ -7279,7 +7280,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
try writer.writeByte(std.wasm.opcode(.local_get));
try leb.writeULEB128(writer, @as(u32, 1));
const tag_val = try mod.enumValueFieldIndex(enum_ty, field_index);
const tag_val = try mod.enumValueFieldIndex(enum_ty, @intCast(tag_index));
const tag_value = try func.lowerConstant(tag_val, enum_ty);
switch (tag_value) {
@ -7372,6 +7373,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const mod = func.bin_file.base.comp.module.?;
const ip = &mod.intern_pool;
const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const operand = try func.resolveInst(ty_op.operand);
@ -7384,8 +7386,8 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
var lowest: ?u32 = null;
var highest: ?u32 = null;
for (names) |name| {
const err_int = @as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(name).?));
for (0..names.len) |name_index| {
const err_int: Module.ErrorInt = @intCast(mod.global_error_set.getIndex(names.get(ip)[name_index]).?);
if (lowest) |*l| {
if (err_int < l.*) {
l.* = err_int;

View File

@ -2187,6 +2187,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
const mod = self.bin_file.comp.module.?;
const ip = &mod.intern_pool;
switch (lazy_sym.ty.zigTypeTag(mod)) {
.Enum => {
const enum_ty = lazy_sym.ty;
@ -2209,10 +2210,10 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty });
var data_off: i32 = 0;
for (exitlude_jump_relocs, 0..) |*exitlude_jump_reloc, index_usize| {
const index: u32 = @intCast(index_usize);
const tag_name = mod.intern_pool.stringToSlice(enum_ty.enumFields(mod)[index_usize]);
const tag_val = try mod.enumValueFieldIndex(enum_ty, index);
const tag_names = enum_ty.enumFields(mod);
for (exitlude_jump_relocs, 0..) |*exitlude_jump_reloc, tag_index| {
const tag_name_len = ip.stringToSlice(tag_names.get(ip)[tag_index]).len;
const tag_val = try mod.enumValueFieldIndex(enum_ty, @intCast(tag_index));
const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val });
try self.genBinOpMir(.{ ._, .cmp }, enum_ty, enum_mcv, tag_mcv);
const skip_reloc = try self.asmJccReloc(.ne, undefined);
@ -2228,14 +2229,14 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
.{ .reg = ret_reg },
8,
Type.usize,
.{ .immediate = tag_name.len },
.{ .immediate = tag_name_len },
.{},
);
exitlude_jump_reloc.* = try self.asmJmpReloc(undefined);
self.performReloc(skip_reloc);
data_off += @intCast(tag_name.len + 1);
data_off += @intCast(tag_name_len + 1);
}
try self.airTrap();

View File

@ -119,6 +119,7 @@ pub fn generateLazySymbol(
const comp = bin_file.comp;
const zcu = comp.module.?;
const ip = &zcu.intern_pool;
const target = comp.root_mod.resolved_target.result;
const endian = target.cpu.arch.endian();
const gpa = comp.gpa;
@ -151,8 +152,9 @@ pub fn generateLazySymbol(
return Result.ok;
} else if (lazy_sym.ty.zigTypeTag(zcu) == .Enum) {
alignment.* = .@"1";
for (lazy_sym.ty.enumFields(zcu)) |tag_name_ip| {
const tag_name = zcu.intern_pool.stringToSlice(tag_name_ip);
const tag_names = lazy_sym.ty.enumFields(zcu);
for (0..tag_names.len) |tag_index| {
const tag_name = zcu.intern_pool.stringToSlice(tag_names.get(ip)[tag_index]);
try code.ensureUnusedCapacity(tag_name.len + 1);
code.appendSliceAssumeCapacity(tag_name);
code.appendAssumeCapacity(0);

View File

@ -2595,6 +2595,7 @@ pub fn genGlobalAsm(mod: *Module, writer: anytype) !void {
pub fn genErrDecls(o: *Object) !void {
const mod = o.dg.module;
const ip = &mod.intern_pool;
const writer = o.writer();
var max_name_len: usize = 0;
@ -2603,7 +2604,7 @@ pub fn genErrDecls(o: *Object) !void {
try writer.writeAll("enum {\n");
o.indent_writer.pushIndent();
for (mod.global_error_set.keys()[1..], 1..) |name_nts, value| {
const name = mod.intern_pool.stringToSlice(name_nts);
const name = ip.stringToSlice(name_nts);
max_name_len = @max(name.len, max_name_len);
const err_val = try mod.intern(.{ .err = .{
.ty = .anyerror_type,
@ -2621,8 +2622,8 @@ pub fn genErrDecls(o: *Object) !void {
defer o.dg.gpa.free(name_buf);
@memcpy(name_buf[0..name_prefix.len], name_prefix);
for (mod.global_error_set.keys()) |name_nts| {
const name = mod.intern_pool.stringToSlice(name_nts);
for (mod.global_error_set.keys()) |name_ip| {
const name = ip.stringToSlice(name_ip);
@memcpy(name_buf[name_prefix.len..][0..name.len], name);
const identifier = name_buf[0 .. name_prefix.len + name.len];
@ -2652,7 +2653,7 @@ pub fn genErrDecls(o: *Object) !void {
try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, .none, .complete);
try writer.writeAll(" = {");
for (mod.global_error_set.keys(), 0..) |name_nts, value| {
const name = mod.intern_pool.stringToSlice(name_nts);
const name = ip.stringToSlice(name_nts);
if (value != 0) try writer.writeByte(',');
const len_val = try mod.intValue(Type.usize, name.len);
@ -2730,6 +2731,7 @@ fn genExports(o: *Object) !void {
pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
const mod = o.dg.module;
const ip = &mod.intern_pool;
const w = o.writer();
const key = lazy_fn.key_ptr.*;
const val = lazy_fn.value_ptr;
@ -2747,23 +2749,23 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
try w.writeByte('(');
try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete);
try w.writeAll(") {\n switch (tag) {\n");
for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| {
const index = @as(u32, @intCast(index_usize));
const name = mod.intern_pool.stringToSlice(name_ip);
const tag_val = try mod.enumValueFieldIndex(enum_ty, index);
const tag_names = enum_ty.enumFields(mod);
for (0..tag_names.len) |tag_index| {
const tag_name = ip.stringToSlice(tag_names.get(ip)[tag_index]);
const tag_val = try mod.enumValueFieldIndex(enum_ty, @intCast(tag_index));
const int_val = try tag_val.intFromEnum(enum_ty, mod);
const name_ty = try mod.arrayType(.{
.len = name.len,
.len = tag_name.len,
.child = .u8_type,
.sentinel = .zero_u8,
});
const name_val = try mod.intern(.{ .aggregate = .{
.ty = name_ty.toIntern(),
.storage = .{ .bytes = name },
.storage = .{ .bytes = tag_name },
} });
const len_val = try mod.intValue(Type.usize, name.len);
const len_val = try mod.intValue(Type.usize, tag_name.len);
try w.print(" case {}: {{\n static ", .{
try o.dg.fmtIntLiteral(enum_ty, int_val, .Other),

View File

@ -9574,6 +9574,7 @@ pub const FuncGen = struct {
fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.dg.object;
const mod = o.module;
const ip = &mod.intern_pool;
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const operand = try self.resolveInst(ty_op.operand);
const error_set_ty = ty_op.ty.toType();
@ -9585,8 +9586,8 @@ pub const FuncGen = struct {
var wip_switch = try self.wip.@"switch"(operand, invalid_block, @intCast(names.len));
defer wip_switch.finish(&self.wip);
for (names) |name| {
const err_int = mod.global_error_set.getIndex(name).?;
for (0..names.len) |name_index| {
const err_int = mod.global_error_set.getIndex(names.get(ip)[name_index]).?;
const this_tag_int_value = try o.builder.intConst(try o.errorIntType(), err_int);
try wip_switch.addCase(this_tag_int_value, valid_block, &self.wip);
}

View File

@ -2828,7 +2828,7 @@ fn addDbgInfoErrorSet(
target: std.Target,
dbg_info_buffer: *std.ArrayList(u8),
) !void {
return addDbgInfoErrorSetNames(mod, ty, ty.errorSetNames(mod), target, dbg_info_buffer);
return addDbgInfoErrorSetNames(mod, ty, ty.errorSetNames(mod).get(&mod.intern_pool), target, dbg_info_buffer);
}
fn addDbgInfoErrorSetNames(

View File

@ -2908,22 +2908,21 @@ pub const Type = struct {
// Asserts that `ty` is an error set and not `anyerror`.
// Asserts that `ty` is resolved if it is an inferred error set.
pub fn errorSetNames(ty: Type, mod: *Module) []const InternPool.NullTerminatedString {
pub fn errorSetNames(ty: Type, mod: *Module) InternPool.NullTerminatedString.Slice {
const ip = &mod.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) {
.error_set_type => |x| x.names.get(ip),
.error_set_type => |x| x.names,
.inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
.none => unreachable, // unresolved inferred error set
.anyerror_type => unreachable,
else => |t| ip.indexToKey(t).error_set_type.names.get(ip),
else => |t| ip.indexToKey(t).error_set_type.names,
},
else => unreachable,
};
}
pub fn enumFields(ty: Type, mod: *Module) []const InternPool.NullTerminatedString {
const ip = &mod.intern_pool;
return ip.indexToKey(ty.toIntern()).enum_type.names.get(ip);
pub fn enumFields(ty: Type, mod: *Module) InternPool.NullTerminatedString.Slice {
return mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names;
}
pub fn enumFieldCount(ty: Type, mod: *Module) usize {

View File

@ -219,23 +219,22 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void {
, "");
}
// https://github.com/ziglang/zig/issues/18954
//{
// var case = ctx.exeFromCompiledC("inferred local const and var", .{}, b);
{
var case = ctx.exeFromCompiledC("inferred local const and var", .{}, b);
// case.addCompareOutput(
// \\fn add(a: i32, b: i32) i32 {
// \\ return a + b;
// \\}
// \\
// \\pub export fn main() c_int {
// \\ const x = add(1, 2);
// \\ var y = add(3, 0);
// \\ y -= x;
// \\ return y;
// \\}
// , "");
//}
case.addCompareOutput(
\\fn add(a: i32, b: i32) i32 {
\\ return a + b;
\\}
\\
\\pub export fn main() c_int {
\\ const x = add(1, 2);
\\ var y = add(3, 0);
\\ y -= x;
\\ return y;
\\}
, "");
}
{
var case = ctx.exeFromCompiledC("control flow", .{}, b);