Skip to content

Commit 17f4510

Browse files
authored
Merge pull request scala/scala#10924 from lrytz/t13048
Fix reentrancy issue in LongMap/AnyRefMap.getOrElseUpdate
2 parents e54d7e4 + 6e52acb commit 17f4510

File tree

2 files changed

+18
-10
lines changed

2 files changed

+18
-10
lines changed

library/src/scala/collection/mutable/AnyRefMap.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,17 @@ class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initi
161161
val h = hashOf(key)
162162
var i = seekEntryOrOpen(h, key)
163163
if (i < 0) {
164-
// It is possible that the default value computation was side-effecting
165-
// Our hash table may have resized or even contain what we want now
166-
// (but if it does, we'll replace it)
167164
val value = {
168-
val oh = _hashes
165+
val ohs = _hashes
166+
val j = i & IndexMask
167+
val oh = ohs(j)
169168
val ans = defaultValue
170-
if (oh ne _hashes) {
169+
// Evaluating `defaultValue` may change the map
170+
// - repack: the array is different
171+
// - element added at `j`: since `i < 0`, the key was missing and `oh` is either 0 or MinValue.
172+
// If `defaultValue` added an element at `j` then `_hashes(j)` must be different now.
173+
// (`hashOf` never returns 0 or MinValue.)
174+
if (ohs.ne(_hashes) || oh != _hashes(j)) {
171175
i = seekEntryOrOpen(h, key)
172176
if (i >= 0) _size -= 1
173177
}

library/src/scala/collection/mutable/LongMap.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,17 @@ final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBuff
185185
else {
186186
var i = seekEntryOrOpen(key)
187187
if (i < 0) {
188-
// It is possible that the default value computation was side-effecting
189-
// Our hash table may have resized or even contain what we want now
190-
// (but if it does, we'll replace it)
191188
val value = {
192-
val ok = _keys
189+
val oks = _keys
190+
val j = i & IndexMask
191+
val ok = oks(j)
193192
val ans = defaultValue
194-
if (ok ne _keys) {
193+
// Evaluating `defaultValue` may change the map
194+
// - repack: the array is different
195+
// - element added at `j`: since `i < 0`, the key was missing and `ok` is either 0 or MinValue.
196+
// If `defaultValue` added an element at `j` then `_keys(j)` must be different now.
197+
// (`_keys` never contains 0 or MinValue.)
198+
if (oks.ne(_keys) || ok != _keys(j)) {
195199
i = seekEntryOrOpen(key)
196200
if (i >= 0) _size -= 1
197201
}

0 commit comments

Comments
 (0)