Skip to content

Commit a0cee55

Browse files
authored
add check for invalid state in _growend! slow-path (JuliaLang#53513)
This only triggers in cases where the user has done something pretty bad (e.g. modified the size incorrectly, or calling `push!` from multiple threads on the same vector without a lock). I'm very unsure if `ConcurrencyViolationError` is the right error to throw here, but I think most of the time, that is going to be the cause. This check is in the slow path because adding extra checks here is basically free (since it will run rarely, and will be batched with O(n) work to copy everything over).
1 parent 5fc1662 commit a0cee55

File tree

1 file changed

+13
-0
lines changed

1 file changed

+13
-0
lines changed

base/array.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,9 @@ function _growbeg!(a::Vector, delta::Integer)
10681068
else
10691069
@noinline (function()
10701070
memlen = length(mem)
1071+
if offset + len - 1 > memlen || offset < 1
1072+
throw(ConcurrencyViolationError("Vector has invalid state. Don't modify internal fields incorrectly, or resize without correct locks"))
1073+
end
10711074
# since we will allocate the array in the middle of the memory we need at least 2*delta extra space
10721075
# the +1 is because I didn't want to have an off by 1 error.
10731076
newmemlen = max(overallocation(memlen), len + 2 * delta + 1)
@@ -1083,6 +1086,9 @@ function _growbeg!(a::Vector, delta::Integer)
10831086
newmem = array_new_memory(mem, newmemlen)
10841087
end
10851088
unsafe_copyto!(newmem, newoffset + delta, mem, offset, len)
1089+
if ref !== a.ref
1090+
@noinline throw(ConcurrencyViolationError("Vector can not be resized concurrently"))
1091+
end
10861092
setfield!(a, :ref, @inbounds GenericMemoryRef(newmem, newoffset))
10871093
end)()
10881094
end
@@ -1103,6 +1109,10 @@ function _growend!(a::Vector, delta::Integer)
11031109
newmemlen = offset + newlen - 1
11041110
if memlen < newmemlen
11051111
@noinline (function()
1112+
if offset + len - 1 > memlen || offset < 1
1113+
throw(ConcurrencyViolationError("Vector has invalid state. Don't modify internal fields incorrectly, or resize without correct locks"))
1114+
end
1115+
11061116
if offset - 1 > div(5 * newlen, 4)
11071117
# If the offset is far enough that we can copy without resizing
11081118
# while maintaining proportional spacing on both ends of the array
@@ -1120,6 +1130,9 @@ function _growend!(a::Vector, delta::Integer)
11201130
end
11211131
newref = @inbounds GenericMemoryRef(newmem, newoffset)
11221132
unsafe_copyto!(newref, ref, len)
1133+
if ref !== a.ref
1134+
@noinline throw(ConcurrencyViolationError("Vector can not be resized concurrently"))
1135+
end
11231136
setfield!(a, :ref, newref)
11241137
end)()
11251138
end

0 commit comments

Comments
 (0)