InternPool: prevent anon struct UAF bugs with type safety
Instead of using actual slices for InternPool.Key.AnonStructType, this
commit changes to use Slice types instead, which store a
long-lived index rather than a pointer.
This is a follow-up to 7ef1eb1c27.
This commit is contained in:
@@ -1275,7 +1275,11 @@ pub const DeclGen = struct {
|
||||
|
||||
try writer.writeByte('{');
|
||||
var empty = true;
|
||||
for (tuple.types, tuple.values, 0..) |field_ty, comptime_ty, field_i| {
|
||||
for (
|
||||
tuple.types.get(ip),
|
||||
tuple.values.get(ip),
|
||||
0..,
|
||||
) |field_ty, comptime_ty, field_i| {
|
||||
if (comptime_ty != .none) continue;
|
||||
if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
|
||||
|
||||
@@ -7745,16 +7749,18 @@ fn lowerFnRetTy(ret_ty: Type, mod: *Module) !Type {
|
||||
if (ret_ty.ip_index == .noreturn_type) return Type.noreturn;
|
||||
|
||||
if (lowersToArray(ret_ty, mod)) {
|
||||
const gpa = mod.gpa;
|
||||
const ip = &mod.intern_pool;
|
||||
const names = [1]InternPool.NullTerminatedString{
|
||||
try mod.intern_pool.getOrPutString(mod.gpa, "array"),
|
||||
try ip.getOrPutString(gpa, "array"),
|
||||
};
|
||||
const types = [1]InternPool.Index{ret_ty.ip_index};
|
||||
const values = [1]InternPool.Index{.none};
|
||||
const interned = try mod.intern(.{ .anon_struct_type = .{
|
||||
const interned = try ip.getAnonStructType(gpa, .{
|
||||
.names = &names,
|
||||
.types = &types,
|
||||
.values = &values,
|
||||
} });
|
||||
});
|
||||
return interned.toType();
|
||||
}
|
||||
|
||||
|
||||
@@ -2392,7 +2392,7 @@ pub const Object = struct {
|
||||
comptime assert(struct_layout_version == 2);
|
||||
var offset: u64 = 0;
|
||||
|
||||
for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| {
|
||||
for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
|
||||
if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
|
||||
|
||||
const field_size = field_ty.toType().abiSize(mod);
|
||||
@@ -2401,7 +2401,7 @@ pub const Object = struct {
|
||||
offset = field_offset + field_size;
|
||||
|
||||
const field_name = if (tuple.names.len != 0)
|
||||
ip.stringToSlice(tuple.names[i])
|
||||
ip.stringToSlice(tuple.names.get(ip)[i])
|
||||
else
|
||||
try std.fmt.allocPrintZ(gpa, "{d}", .{i});
|
||||
defer if (tuple.names.len == 0) gpa.free(field_name);
|
||||
@@ -3325,7 +3325,10 @@ pub const Object = struct {
|
||||
var offset: u64 = 0;
|
||||
var big_align: u32 = 0;
|
||||
|
||||
for (anon_struct_type.types, anon_struct_type.values) |field_ty, field_val| {
|
||||
for (
|
||||
anon_struct_type.types.get(ip),
|
||||
anon_struct_type.values.get(ip),
|
||||
) |field_ty, field_val| {
|
||||
if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
|
||||
|
||||
const field_align = field_ty.toType().abiAlignment(mod);
|
||||
@@ -3874,7 +3877,11 @@ pub const Object = struct {
|
||||
var offset: u64 = 0;
|
||||
var big_align: u32 = 0;
|
||||
var need_unnamed = false;
|
||||
for (tuple.types, tuple.values, 0..) |field_ty, field_val, field_index| {
|
||||
for (
|
||||
tuple.types.get(ip),
|
||||
tuple.values.get(ip),
|
||||
0..,
|
||||
) |field_ty, field_val, field_index| {
|
||||
if (field_val != .none) continue;
|
||||
if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
|
||||
|
||||
@@ -10537,10 +10544,11 @@ fn llvmField(ty: Type, field_index: usize, mod: *Module) ?LlvmField {
|
||||
var offset: u64 = 0;
|
||||
var big_align: u32 = 0;
|
||||
|
||||
const struct_type = switch (mod.intern_pool.indexToKey(ty.toIntern())) {
|
||||
const ip = &mod.intern_pool;
|
||||
const struct_type = switch (ip.indexToKey(ty.toIntern())) {
|
||||
.anon_struct_type => |tuple| {
|
||||
var llvm_field_index: c_uint = 0;
|
||||
for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| {
|
||||
for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
|
||||
if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
|
||||
|
||||
const field_align = field_ty.toType().abiAlignment(mod);
|
||||
@@ -11118,6 +11126,7 @@ fn isByRef(ty: Type, mod: *Module) bool {
|
||||
// For tuples and structs, if there are more than this many non-void
|
||||
// fields, then we make it byref, otherwise byval.
|
||||
const max_fields_byval = 0;
|
||||
const ip = &mod.intern_pool;
|
||||
|
||||
switch (ty.zigTypeTag(mod)) {
|
||||
.Type,
|
||||
@@ -11146,10 +11155,10 @@ fn isByRef(ty: Type, mod: *Module) bool {
|
||||
.Struct => {
|
||||
// Packed structs are represented to LLVM as integers.
|
||||
if (ty.containerLayout(mod) == .Packed) return false;
|
||||
const struct_type = switch (mod.intern_pool.indexToKey(ty.toIntern())) {
|
||||
const struct_type = switch (ip.indexToKey(ty.toIntern())) {
|
||||
.anon_struct_type => |tuple| {
|
||||
var count: usize = 0;
|
||||
for (tuple.types, tuple.values) |field_ty, field_val| {
|
||||
for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, field_val| {
|
||||
if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
|
||||
|
||||
count += 1;
|
||||
|
||||
@@ -1227,6 +1227,7 @@ pub const DeclGen = struct {
|
||||
/// Turn a Zig type into a SPIR-V Type, and return a reference to it.
|
||||
fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!CacheRef {
|
||||
const mod = self.module;
|
||||
const ip = &mod.intern_pool;
|
||||
log.debug("resolveType: ty = {}", .{ty.fmt(self.module)});
|
||||
const target = self.getTarget();
|
||||
switch (ty.zigTypeTag(mod)) {
|
||||
@@ -1271,7 +1272,6 @@ pub const DeclGen = struct {
|
||||
},
|
||||
.Fn => switch (repr) {
|
||||
.direct => {
|
||||
const ip = &mod.intern_pool;
|
||||
const fn_info = mod.typeToFunc(ty).?;
|
||||
// TODO: Put this somewhere in Sema.zig
|
||||
if (fn_info.is_var_args)
|
||||
@@ -1333,13 +1333,13 @@ pub const DeclGen = struct {
|
||||
} });
|
||||
},
|
||||
.Struct => {
|
||||
const struct_ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) {
|
||||
const struct_ty = switch (ip.indexToKey(ty.toIntern())) {
|
||||
.anon_struct_type => |tuple| {
|
||||
const member_types = try self.gpa.alloc(CacheRef, tuple.values.len);
|
||||
defer self.gpa.free(member_types);
|
||||
|
||||
var member_index: usize = 0;
|
||||
for (tuple.types, tuple.values) |field_ty, field_val| {
|
||||
for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, field_val| {
|
||||
if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
|
||||
|
||||
member_types[member_index] = try self.resolveType(field_ty.toType(), .indirect);
|
||||
@@ -1369,12 +1369,12 @@ pub const DeclGen = struct {
|
||||
while (it.next()) |field_and_index| {
|
||||
const field = field_and_index.field;
|
||||
const index = field_and_index.index;
|
||||
const field_name = mod.intern_pool.stringToSlice(struct_obj.fields.keys()[index]);
|
||||
const field_name = ip.stringToSlice(struct_obj.fields.keys()[index]);
|
||||
try member_types.append(try self.resolveType(field.ty, .indirect));
|
||||
try member_names.append(try self.spv.resolveString(field_name));
|
||||
}
|
||||
|
||||
const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(self.module));
|
||||
const name = ip.stringToSlice(try struct_obj.getFullyQualifiedName(self.module));
|
||||
|
||||
return try self.spv.resolve(.{ .struct_type = .{
|
||||
.name = try self.spv.resolveString(name),
|
||||
|
||||
Reference in New Issue
Block a user