Skip to content

Commit 1ac0a36

Browse files
aartbikcommit-bot@chromium.org
authored andcommitted
[dart/vm] Fix division-by-zero bug in range analysis
Rationale: The attached test, a simplified version from a case found by fuzzing, yielded the range [4,4] for the left hand side of the division but [25,0] (sic!) for the right hand side. This reverse range caused the logic in the TRUNC evaluation to pass the >= 1 test but introduce the division by zero in the compiler code. The true culprit, however, was the reason for [25,0] which was due to a difference in C++ and Dart shift right semantics. This CL fixes the bug and adds some sanity assert to find more of such cases. #37622 Change-Id: I60e07428435d99589e1177c113ef5e24e1611d0e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/110420 Reviewed-by: Alexander Markov <[email protected]> Reviewed-by: Ryan Macnak <[email protected]> Commit-Queue: Aart Bik <[email protected]>
1 parent 939cce7 commit 1ac0a36

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

runtime/vm/compiler/backend/range_analysis.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2442,6 +2442,10 @@ void Range::BinaryOp(const Token::Kind op,
24422442

24432443
ASSERT(!min.IsUnknown() && !max.IsUnknown());
24442444

2445+
// Sanity: avoid [l, u] with constants l > u.
2446+
ASSERT(!min.IsConstant() || !max.IsConstant() ||
2447+
min.ConstantValue() <= max.ConstantValue());
2448+
24452449
*result = Range(min, max);
24462450
}
24472451

runtime/vm/compiler/backend/range_analysis.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,10 @@ class RangeBoundary : public ValueObject {
250250
int64_t shift_count) {
251251
ASSERT(value_boundary.IsConstant());
252252
ASSERT(shift_count >= 0);
253-
int64_t value = static_cast<int64_t>(value_boundary.ConstantValue());
254-
int64_t result = value >> shift_count;
253+
const int64_t value = static_cast<int64_t>(value_boundary.ConstantValue());
254+
const int64_t result = (shift_count <= 63)
255+
? (value >> shift_count)
256+
: (value >= 0 ? 0 : -1); // Dart semantics
255257
return RangeBoundary(result);
256258
}
257259

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// VMOptions=--deterministic --enable-inlining-annotations
6+
7+
// Issue #37622 found with fuzzing: internal compiler crash (division-by-zero).
8+
9+
import 'dart:typed_data';
10+
11+
import "package:expect/expect.dart";
12+
13+
const String NeverInline = 'NeverInline';
14+
15+
@NeverInline
16+
int foo() {
17+
int x = 0;
18+
{
19+
int loc0 = 67;
20+
while (--loc0 > 0) {
21+
--loc0;
22+
x += (4 ~/ (Int32x4.wxwx >> loc0));
23+
--loc0;
24+
--loc0;
25+
}
26+
}
27+
}
28+
29+
main() {
30+
int x = 0;
31+
bool d = false;
32+
try {
33+
x = foo();
34+
} on IntegerDivisionByZeroException catch (e) {
35+
d = true;
36+
}
37+
Expect.equals(x, 0);
38+
Expect.isTrue(d);
39+
}

0 commit comments

Comments
 (0)