authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-30 03:54:34-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:47:57-07:00
logf673c98a7cd18b552cb4959bc22d1794df34c7ab
tree97ab5454dc30fdcf53b1338dc8386afb0a9cabef
parentd0cd1c89da5d688634cdcd3fd645799b14553660

Sema: fix sus overflow behavior in RangeSetUnhandledIterator

The old code assumed that `intAddScalar` could return a value outside of the range of `ty`, which is problematic for many reasons. The new code (ab)uses the InternPool for speed.

1 files changed, 55 insertions(+), 32 deletions(-)

src/Sema.zig+55-32
...@@ -11509,7 +11509,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11509,7 +11509,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11509 while (try it.next()) |cur| {11509 while (try it.next()) |cur| {
11510 cases_len += 1;11510 cases_len += 1;
1151111511
11512 const item_ref = try sema.addConstant(operand_ty, cur);11512 const item_ref = try sema.addConstant(operand_ty, cur.toValue());
11513 case_block.inline_case_capture = item_ref;11513 case_block.inline_case_capture = item_ref;
1151411514
11515 case_block.instructions.shrinkRetainingCapacity(0);11515 case_block.instructions.shrinkRetainingCapacity(0);
...@@ -11647,47 +11647,70 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -11647,47 +11647,70 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
11647}11647}
1164811648
11649const RangeSetUnhandledIterator = struct {11649const RangeSetUnhandledIterator = struct {
11650 sema: *Sema,11650 mod: *Module,
11651 ty: Type,11651 cur: ?InternPool.Index,
11652 cur: Value,11652 max: InternPool.Index,
11653 max: Value,11653 range_i: usize,
11654 ranges: []const RangeSet.Range,11654 ranges: []const RangeSet.Range,
11655 range_i: usize = 0,11655 limbs: []math.big.Limb,
11656 first: bool = true,11656
11657 const preallocated_limbs = math.big.int.calcTwosCompLimbCount(128);
1165711658
11658 fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator {11659 fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator {
11659 const mod = sema.mod;11660 const mod = sema.mod;
11660 const min = try ty.minInt(mod, ty);11661 const int_type = mod.intern_pool.indexToKey(ty.toIntern()).int_type;
11661 const max = try ty.maxInt(mod, ty);11662 const needed_limbs = math.big.int.calcTwosCompLimbCount(int_type.bits);
1166211663 return .{
11663 return RangeSetUnhandledIterator{11664 .mod = mod,
11664 .sema = sema,11665 .cur = (try ty.minInt(mod, ty)).toIntern(),
11665 .ty = ty,11666 .max = (try ty.maxInt(mod, ty)).toIntern(),
11666 .cur = min,11667 .range_i = 0,
11667 .max = max,
11668 .ranges = range_set.ranges.items,11668 .ranges = range_set.ranges.items,
11669 .limbs = if (needed_limbs > preallocated_limbs)
11670 try sema.arena.alloc(math.big.Limb, needed_limbs)
11671 else
11672 &.{},
11669 };11673 };
11670 }11674 }
1167111675
11672 fn next(it: *RangeSetUnhandledIterator) !?Value {11676 fn addOne(it: *const RangeSetUnhandledIterator, val: InternPool.Index) !?InternPool.Index {
11673 while (it.range_i < it.ranges.len) : (it.range_i += 1) {11677 if (val == it.max) return null;
11674 if (!it.first) {11678 const int = it.mod.intern_pool.indexToKey(val).int;
11675 it.cur = try it.sema.intAddScalar(it.cur, try it.sema.mod.intValue(it.ty, 1), it.ty);11679
11676 }11680 switch (int.storage) {
11677 it.first = false;11681 inline .u64, .i64 => |val_int| {
11678 if (it.cur.compareScalar(.lt, it.ranges[it.range_i].first.toValue(), it.ty, it.sema.mod)) {11682 const next_int = @addWithOverflow(val_int, 1);
11679 return it.cur;11683 if (next_int[1] == 0)
11680 }11684 return (try it.mod.intValue(int.ty.toType(), next_int[0])).toIntern();
11681 it.cur = it.ranges[it.range_i].last.toValue();11685 },
11682 }11686 .big_int => {},
11683 if (!it.first) {11687 .lazy_align, .lazy_size => unreachable,
11684 it.cur = try it.sema.intAddScalar(it.cur, try it.sema.mod.intValue(it.ty, 1), it.ty);
11685 }11688 }
11686 it.first = false;11689
11687 if (it.cur.compareScalar(.lte, it.max, it.ty, it.sema.mod)) {11690 var val_space: InternPool.Key.Int.Storage.BigIntSpace = undefined;
11688 return it.cur;11691 const val_bigint = int.storage.toBigInt(&val_space);
11692
11693 var result_limbs: [preallocated_limbs]math.big.Limb = undefined;
11694 var result_bigint = math.big.int.Mutable.init(
11695 if (it.limbs.len > 0) it.limbs else &result_limbs,
11696 0,
11697 );
11698
11699 result_bigint.addScalar(val_bigint, 1);
11700 return (try it.mod.intValue_big(int.ty.toType(), result_bigint.toConst())).toIntern();
11701 }
11702
11703 fn next(it: *RangeSetUnhandledIterator) !?InternPool.Index {
11704 var cur = it.cur orelse return null;
11705 while (it.range_i < it.ranges.len and cur == it.ranges[it.range_i].first) {
11706 defer it.range_i += 1;
11707 cur = (try it.addOne(it.ranges[it.range_i].last)) orelse {
11708 it.cur = null;
11709 return null;
11710 };
11689 }11711 }
11690 return null;11712 it.cur = try it.addOne(cur);
11713 return cur;
11691 }11714 }
11692};11715};
1169311716