Skip to content

Commit da6c937

Browse files
authored
Fix UB in OptimizeInstructions (#7676)
When optimizing `add` operations, OptimizeInstructions calculates the max bits of the operands and shifts that value to produce a bit mask. When an operand is unreachable, it is arbitrarily considered to have a max bits value of 64, even for 32-bit operations. This leads to UB in the shift. Fix the problem by returning before the shift in this case.
1 parent c1a484e commit da6c937

File tree

2 files changed

+41
-12
lines changed

2 files changed

+41
-12
lines changed

src/passes/OptimizeInstructions.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3604,11 +3604,14 @@ struct OptimizeInstructions
36043604
// Check left's max bits and right is constant.
36053605
auto leftMaxBits = Bits::getMaxBits(left, this);
36063606
uint64_t maskLeft;
3607-
if (!left->type.isNumber() || leftMaxBits == left->type.getByteSize() * 8) {
3607+
// leftMaxBits may be greater than size if the lhs is unreachable but has
3608+
// not been refinalized yet.
3609+
if (!left->type.isNumber() || leftMaxBits >= left->type.getByteSize() * 8) {
36083610
// If we know nothing useful about the bits on the left,
36093611
// we cannot optimize.
36103612
return nullptr;
36113613
} else {
3614+
assert(leftMaxBits < 64);
36123615
maskLeft = (1ULL << leftMaxBits) - 1;
36133616
}
36143617
if (auto* c = right->dynCast<Const>()) {

test/lit/passes/optimize-instructions-gc.wast

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
;; CHECK: (type $struct_i64 (func (param structref) (result i64)))
5252
(type $struct_i64 (func (param (ref null struct)) (result i64)))
5353

54-
;; CHECK: (import "env" "get-i32" (func $get-i32 (type $9) (result i32)))
54+
;; CHECK: (import "env" "get-i32" (func $get-i32 (type $8) (result i32)))
5555
(import "env" "get-i32" (func $get-i32 (result i32)))
5656

5757
;; These functions test if an `if` with subtyped arms is correctly folded
@@ -1418,7 +1418,7 @@
14181418
)
14191419
)
14201420

1421-
;; CHECK: (func $incompatible-test-heap-types-nonnullable (type $8) (param $anyref anyref) (result anyref)
1421+
;; CHECK: (func $incompatible-test-heap-types-nonnullable (type $9) (param $anyref anyref) (result anyref)
14221422
;; CHECK-NEXT: (block $outer (result anyref)
14231423
;; CHECK-NEXT: (drop
14241424
;; CHECK-NEXT: (block (result i32)
@@ -1460,7 +1460,7 @@
14601460
)
14611461
)
14621462

1463-
;; CHECK: (func $incompatible-test-heap-types-nullable (type $8) (param $anyref anyref) (result anyref)
1463+
;; CHECK: (func $incompatible-test-heap-types-nullable (type $9) (param $anyref anyref) (result anyref)
14641464
;; CHECK-NEXT: (block $outer (result anyref)
14651465
;; CHECK-NEXT: (drop
14661466
;; CHECK-NEXT: (block (result i32)
@@ -1501,7 +1501,7 @@
15011501
)
15021502
)
15031503

1504-
;; CHECK: (func $incompatible-test-heap-types-unreachable (type $8) (param $anyref anyref) (result anyref)
1504+
;; CHECK: (func $incompatible-test-heap-types-unreachable (type $9) (param $anyref anyref) (result anyref)
15051505
;; CHECK-NEXT: (block $outer (result anyref)
15061506
;; CHECK-NEXT: (drop
15071507
;; CHECK-NEXT: (block (result i32)
@@ -2641,7 +2641,7 @@
26412641
)
26422642
)
26432643

2644-
;; CHECK: (func $incompatible-cast-heap-types-nonnullable (type $8) (param $anyref anyref) (result anyref)
2644+
;; CHECK: (func $incompatible-cast-heap-types-nonnullable (type $9) (param $anyref anyref) (result anyref)
26452645
;; CHECK-NEXT: (block $outer (result (ref any))
26462646
;; CHECK-NEXT: (block
26472647
;; CHECK-NEXT: (drop
@@ -2677,7 +2677,7 @@
26772677
)
26782678
)
26792679

2680-
;; CHECK: (func $incompatible-cast-heap-types-nullable (type $8) (param $anyref anyref) (result anyref)
2680+
;; CHECK: (func $incompatible-cast-heap-types-nullable (type $9) (param $anyref anyref) (result anyref)
26812681
;; CHECK-NEXT: (block $outer (result anyref)
26822682
;; CHECK-NEXT: (ref.cast nullref
26832683
;; CHECK-NEXT: (block (result nullref)
@@ -2709,7 +2709,7 @@
27092709
)
27102710
)
27112711

2712-
;; CHECK: (func $incompatible-cast-heap-types-unreachable (type $8) (param $anyref anyref) (result anyref)
2712+
;; CHECK: (func $incompatible-cast-heap-types-unreachable (type $9) (param $anyref anyref) (result anyref)
27132713
;; CHECK-NEXT: (block $outer (result anyref)
27142714
;; CHECK-NEXT: (block
27152715
;; CHECK-NEXT: (drop
@@ -2966,7 +2966,7 @@
29662966
)
29672967
)
29682968

2969-
;; CHECK: (func $non-null-bottom-ref-test (type $9) (result i32)
2969+
;; CHECK: (func $non-null-bottom-ref-test (type $8) (result i32)
29702970
;; CHECK-NEXT: (local $0 funcref)
29712971
;; CHECK-NEXT: (drop
29722972
;; CHECK-NEXT: (local.tee $0
@@ -2989,7 +2989,7 @@
29892989
)
29902990
)
29912991

2992-
;; CHECK: (func $non-null-bottom-ref-test-notee (type $9) (result i32)
2992+
;; CHECK: (func $non-null-bottom-ref-test-notee (type $8) (result i32)
29932993
;; CHECK-NEXT: (local $0 funcref)
29942994
;; CHECK-NEXT: (drop
29952995
;; CHECK-NEXT: (loop (result (ref nofunc))
@@ -3009,7 +3009,7 @@
30093009
)
30103010
)
30113011

3012-
;; CHECK: (func $non-null-bottom-test (type $9) (result i32)
3012+
;; CHECK: (func $non-null-bottom-test (type $8) (result i32)
30133013
;; CHECK-NEXT: (drop
30143014
;; CHECK-NEXT: (ref.func $non-null-bottom-cast)
30153015
;; CHECK-NEXT: )
@@ -3079,7 +3079,7 @@
30793079
)
30803080
)
30813081

3082-
;; CHECK: (func $ref.test-then-optimizeAddedConstants (type $9) (result i32)
3082+
;; CHECK: (func $ref.test-then-optimizeAddedConstants (type $8) (result i32)
30833083
;; CHECK-NEXT: (i32.add
30843084
;; CHECK-NEXT: (block
30853085
;; CHECK-NEXT: (drop
@@ -3691,4 +3691,30 @@
36913691
)
36923692
)
36933693
)
3694+
3695+
;; Regression test for UB when analyzing bits.
3696+
;; CHECK: (func $unreachable-bits (type $8) (result i32)
3697+
;; CHECK-NEXT: (drop
3698+
;; CHECK-NEXT: (block
3699+
;; CHECK-NEXT: (drop
3700+
;; CHECK-NEXT: (unreachable)
3701+
;; CHECK-NEXT: )
3702+
;; CHECK-NEXT: (unreachable)
3703+
;; CHECK-NEXT: )
3704+
;; CHECK-NEXT: )
3705+
;; CHECK-NEXT: (i32.const 0)
3706+
;; CHECK-NEXT: )
3707+
(func $unreachable-bits (result i32)
3708+
;; When this is optimized, the unreachable left hand side is arbitrarily
3709+
;; considered to have 64 bits. This should not lead to UB.
3710+
(i32.and
3711+
;; This will be optimized to an unreachable block.
3712+
(ref.test (ref none)
3713+
(ref.as_non_null
3714+
(ref.null none)
3715+
)
3716+
)
3717+
(i32.const 0)
3718+
)
3719+
)
36943720
)

0 commit comments

Comments
 (0)