Skip to content

Commit a170fc5

Browse files
alexmarkovcommit-bot@chromium.org
authored andcommitted
[vm] Fix DirectChainedHashMap iterator
BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Iterator::Next() was first checking if array_index_ is larger than the size of map's array, and only then it was looking at remaining entries in the collision list. So, when there is a collision in the last bucket, array_index_ was bumped and the first entry in the list was returned. After that, Next() returned NULL, skipping remaining entries in the collision list. This caused incorrect stack state management in BytecodeFlowGraphBuilder and BytecodeFlowGraphBuilder::DropUnusedValuesFromStack() was removing too many entries from the stack, which caused crash in BytecodeFlowGraphBuilder::BuildStoreIndexedTOS(). Issue: #38979 Change-Id: Ie073ca7014da5b04999b7984d508984b4c9743b8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/122176 Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
1 parent 5d4cd6d commit a170fc5

File tree

3 files changed

+108
-21
lines changed

3 files changed

+108
-21
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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+
// Verifies that compiler doesn't crash on a particular piece of code.
6+
7+
import "package:expect/expect.dart";
8+
import 'dart:typed_data';
9+
10+
Int8List var3 = Int8List(1);
11+
bool var14 = true;
12+
Duration var15 = Duration();
13+
int var16 = 22;
14+
String var18 = '';
15+
Map<bool, bool> var25 = {};
16+
Map<bool, int> var26 = {};
17+
Map<int, String> var30 = {};
18+
Map<String, bool> var31 = {};
19+
20+
int foo1(Int8List par1, Map<bool, int> par2) {
21+
throw 'err';
22+
}
23+
24+
class X0 {
25+
Int32x4 foo0_0(Duration par1, Set<bool> par2) {
26+
if (var14) {
27+
{
28+
int loc0 = 0;
29+
do {
30+
var31 = {
31+
(String.fromCharCode(((true ? true : true)
32+
? (var14 ? 33 : var16)
33+
: (-(foo1(var3,
34+
{(false ? false : var14): (true ? 20 : var3[27])})))))):
35+
((((var16 > (-((-(loc0))))) ? Duration() : Duration()) +
36+
(var14 ? (true ? var15 : par1) : Duration())) <
37+
Duration()),
38+
(((var30[(Int32x4.yzxw as int)]).toUpperCase()) +
39+
(Uri.encodeComponent(('2' ??
40+
(var25[true]
41+
? (String.fromEnvironment(''))
42+
: var18))))): (!(var14)),
43+
(var31['MgOdzM']
44+
? var30[15]
45+
: (('D9q6Ma').substring(
46+
(~((--var16))), foo1(var3, (false ? {} : var26))))):
47+
(!(false)),
48+
};
49+
} while (++loc0 < 39);
50+
}
51+
}
52+
}
53+
}
54+
55+
main() {
56+
Expect.throws(() => X0().foo0_0(Duration(), {true, false}),
57+
(e) => e is NoSuchMethodError);
58+
}

runtime/vm/hash_map.h

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -188,32 +188,27 @@ BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Iterator::Next() {
188188
const typename KeyValueTrait::Value kNoValue =
189189
KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
190190

191-
if (array_index_ < map_.array_size_) {
192-
// If we're not in the middle of a list, find the next array slot.
193-
if (list_index_ == kNil) {
194-
while ((array_index_ < map_.array_size_) &&
195-
KeyValueTrait::ValueOf(map_.array_[array_index_].kv) == kNoValue) {
196-
array_index_++;
197-
}
198-
if (array_index_ < map_.array_size_) {
199-
// When we're done with the list, we'll continue with the next array
200-
// slot.
201-
const intptr_t old_array_index = array_index_;
202-
array_index_++;
203-
list_index_ = map_.array_[old_array_index].next;
204-
return &map_.array_[old_array_index].kv;
205-
} else {
206-
return NULL;
207-
}
208-
}
209-
210-
// Otherwise, return the current lists_ entry, advancing list_index_.
191+
// Return the current lists_ entry (if any), advancing list_index_.
192+
if (list_index_ != kNil) {
211193
intptr_t current = list_index_;
212194
list_index_ = map_.lists_[current].next;
213195
return &map_.lists_[current].kv;
214196
}
215197

216-
return NULL;
198+
// When we're done with the list, we'll continue with the next array
199+
// slot.
200+
while ((array_index_ < map_.array_size_) &&
201+
KeyValueTrait::ValueOf(map_.array_[array_index_].kv) == kNoValue) {
202+
++array_index_;
203+
}
204+
if (array_index_ < map_.array_size_) {
205+
const intptr_t old_array_index = array_index_;
206+
++array_index_;
207+
list_index_ = map_.array_[old_array_index].next;
208+
return &map_.array_[old_array_index].kv;
209+
}
210+
211+
return nullptr;
217212
}
218213

219214
template <typename KeyValueTrait, typename B, typename Allocator>

runtime/vm/hash_map_test.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,40 @@ TEST_CASE(DirectChainedHashMapIterator) {
172172
EXPECT(sum == 15);
173173
}
174174

175+
TEST_CASE(DirectChainedHashMapIteratorWithCollisionInLastBucket) {
176+
intptr_t values[] = {65, 325, 329, 73, 396, 207, 215, 93, 227, 39,
177+
431, 112, 176, 313, 188, 317, 61, 127, 447};
178+
IntMap<intptr_t> map;
179+
180+
for (intptr_t value : values) {
181+
map.Insert(value, value);
182+
}
183+
184+
bool visited[ARRAY_SIZE(values)] = {};
185+
intptr_t count = 0;
186+
auto it = map.GetIterator();
187+
for (auto* p = it.Next(); p != nullptr; p = it.Next()) {
188+
++count;
189+
bool found = false;
190+
intptr_t i = 0;
191+
for (intptr_t v : values) {
192+
if (v == p->key) {
193+
EXPECT(v == p->value);
194+
EXPECT(!visited[i]);
195+
visited[i] = true;
196+
found = true;
197+
break;
198+
}
199+
++i;
200+
}
201+
EXPECT(found);
202+
}
203+
EXPECT(count == ARRAY_SIZE(values));
204+
for (bool is_visited : visited) {
205+
EXPECT(is_visited);
206+
}
207+
}
208+
175209
TEST_CASE(CStringMap) {
176210
const char* const kConst1 = "test";
177211
const char* const kConst2 = "test 2";

0 commit comments

Comments
 (0)