diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-05-07 15:06:58 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-06-10 20:42:29 -0700 |
| commit | 8699cdc3dfcf3a3a6f09a64ea9c67be2459e1240 (patch) | |
| tree | 78d4142325d385513a4691e27813fba6d1f3d5dc /src/InternPool.zig | |
| parent | 2ffef605c75b62ba49e21bfb3256537a4a2c0a5e (diff) | |
| download | zig-8699cdc3dfcf3a3a6f09a64ea9c67be2459e1240.tar.gz zig-8699cdc3dfcf3a3a6f09a64ea9c67be2459e1240.zip | |
InternPool: fix UAF in getCoercedInt and add u16 int value encoding
Diffstat (limited to 'src/InternPool.zig')
| -rw-r--r-- | src/InternPool.zig | 83 |
1 files changed, 77 insertions, 6 deletions
diff --git a/src/InternPool.zig b/src/InternPool.zig index f6d594cbbb..c60f58e207 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -721,6 +721,9 @@ pub const Tag = enum(u8) { /// only an enum tag, but will be presented via the API with a different Key. /// data is SimpleInternal enum value. simple_internal, + /// Type: u16 + /// data is integer value + int_u16, /// Type: u32 /// data is integer value int_u32, @@ -1053,6 +1056,10 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { .type_error_union => @panic("TODO"), .type_enum_simple => @panic("TODO"), .simple_internal => @panic("TODO"), + .int_u16 => .{ .int = .{ + .ty = .u16_type, + .storage = .{ .u64 = data }, + } }, .int_u32 => .{ .int = .{ .ty = .u32_type, .storage = .{ .u64 = data }, @@ -1219,6 +1226,26 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { .int => |int| b: { switch (int.ty) { .none => unreachable, + .u16_type => switch (int.storage) { + .big_int => |big_int| { + if (big_int.to(u32)) |casted| { + ip.items.appendAssumeCapacity(.{ + .tag = .int_u16, + .data = casted, + }); + break :b; + } else |_| {} + }, + inline .u64, .i64 => |x| { + if (std.math.cast(u32, x)) |casted| { + ip.items.appendAssumeCapacity(.{ + .tag = .int_u16, + .data = casted, + }); + break :b; + } + }, + }, .u32_type => switch (int.storage) { .big_int => |big_int| { if (big_int.to(u32)) |casted| { @@ -1252,7 +1279,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { inline .u64, .i64 => |x| { if (std.math.cast(i32, x)) |casted| { ip.items.appendAssumeCapacity(.{ - .tag = .int_u32, + .tag = .int_i32, .data = @bitCast(u32, casted), }); break :b; @@ -1466,6 +1493,7 @@ fn limbData(ip: InternPool, comptime T: type, index: usize) T { return result; } +/// This function returns the Limb slice that is trailing data after a payload. fn limbSlice(ip: InternPool, comptime S: type, limb_index: u32, len: u32) []const Limb { const field_count = @typeInfo(S).Struct.fields.len; switch (@sizeOf(Limb)) { @@ -1481,6 +1509,33 @@ fn limbSlice(ip: InternPool, comptime S: type, limb_index: u32, len: u32) []cons } } +const LimbsAsIndexes = struct { + start: u32, + len: u32, +}; + +fn limbsSliceToIndex(ip: InternPool, limbs: []const Limb) LimbsAsIndexes { + const host_slice = switch (@sizeOf(Limb)) { + @sizeOf(u32) => ip.extra.items, + @sizeOf(u64) => ip.limbs.items, + else => @compileError("unsupported host"), + }; + // TODO: https://github.com/ziglang/zig/issues/1738 + return .{ + .start = @intCast(u32, @divExact(@ptrToInt(limbs.ptr) - @ptrToInt(host_slice.ptr), @sizeOf(Limb))), + .len = @intCast(u32, limbs.len), + }; +} + +/// This function converts Limb array indexes to a primitive slice type. +fn limbsIndexToSlice(ip: InternPool, limbs: LimbsAsIndexes) []const Limb { + return switch (@sizeOf(Limb)) { + @sizeOf(u32) => ip.extra.items[limbs.start..][0..limbs.len], + @sizeOf(u64) => ip.limbs.items[limbs.start..][0..limbs.len], + else => @compileError("unsupported host"), + }; +} + test "basic usage" { const gpa = std.testing.allocator; @@ -1544,15 +1599,30 @@ pub fn getCoercedInt(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) // Here we pre-reserve the limbs to ensure that the logic in `addInt` will // not use an invalidated limbs pointer. switch (key.int.storage) { - .u64, .i64 => {}, + .u64 => |x| return ip.get(gpa, .{ .int = .{ + .ty = new_ty, + .storage = .{ .u64 = x }, + } }), + .i64 => |x| return ip.get(gpa, .{ .int = .{ + .ty = new_ty, + .storage = .{ .i64 = x }, + } }), + .big_int => |big_int| { + const positive = big_int.positive; + const limbs = ip.limbsSliceToIndex(big_int.limbs); + // This line invalidates the limbs slice, but the indexes computed in the + // previous line are still correct. try reserveLimbs(ip, gpa, @typeInfo(Int).Struct.fields.len + big_int.limbs.len); + return ip.get(gpa, .{ .int = .{ + .ty = new_ty, + .storage = .{ .big_int = .{ + .limbs = ip.limbsIndexToSlice(limbs), + .positive = positive, + } }, + } }); }, } - return ip.get(gpa, .{ .int = .{ - .ty = new_ty, - .storage = key.int.storage, - } }); } pub fn dump(ip: InternPool) void { @@ -1608,6 +1678,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { .simple_type => 0, .simple_value => 0, .simple_internal => 0, + .int_u16 => 0, .int_u32 => 0, .int_i32 => 0, .int_usize => 0, |
