From da8e24b07ea839de3733b0c89ded5797a774d4bb Mon Sep 17 00:00:00 2001 From: oscarddssmith Date: Wed, 28 Feb 2024 10:15:43 -0500 Subject: [PATCH 1/5] add check for invalid state in _growend! slow-path --- base/array.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/base/array.jl b/base/array.jl index 4fcf29af69b4b..5c725d47a2d79 100644 --- a/base/array.jl +++ b/base/array.jl @@ -1103,6 +1103,10 @@ function _growend!(a::Vector, delta::Integer) newmemlen = offset + newlen - 1 if memlen < newmemlen @noinline (function() + if offset + len <= memlen || offset < 1 + throw(ConcurrencyViolationError("Vector has invalid state. Don't modify internal fields incorrectly, or resize without correct locks")) + end + if offset - 1 > div(5 * newlen, 4) # If the offset is far enough that we can copy without resizing # while maintaining proportional spacing on both ends of the array From c8332d5b9be0ed61fafe0542990c893ad39079fb Mon Sep 17 00:00:00 2001 From: oscarddssmith Date: Wed, 28 Feb 2024 10:32:01 -0500 Subject: [PATCH 2/5] also check that ref didn't change --- base/array.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/base/array.jl b/base/array.jl index 5c725d47a2d79..af0e13a015a1b 100644 --- a/base/array.jl +++ b/base/array.jl @@ -1124,6 +1124,9 @@ function _growend!(a::Vector, delta::Integer) end newref = @inbounds GenericMemoryRef(newmem, newoffset) unsafe_copyto!(newref, ref, len) + if ref !== a.ref + throw(ConcurrencyViolationError("Vector can not be resized concurrently")) + end setfield!(a, :ref, newref) end)() end From 5b812b89da89a2bf08b50fd2a5e2dd62ad40ce70 Mon Sep 17 00:00:00 2001 From: oscarddssmith Date: Mon, 4 Mar 2024 10:52:52 -0500 Subject: [PATCH 3/5] fix condition --- base/array.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/array.jl b/base/array.jl index af0e13a015a1b..cec313f70d2ad 100644 --- a/base/array.jl +++ b/base/array.jl @@ -1103,7 +1103,7 @@ function _growend!(a::Vector, delta::Integer) newmemlen = offset + newlen - 1 if memlen < newmemlen @noinline (function() - if offset + len <= memlen || offset < 1 + if offset + len - 1 > memlen || offset < 1 throw(ConcurrencyViolationError("Vector has invalid state. Don't modify internal fields incorrectly, or resize without correct locks")) end From 6b4f76d5eb4d5d83a15b84588461451201ed825c Mon Sep 17 00:00:00 2001 From: oscarddssmith Date: Mon, 4 Mar 2024 16:47:12 -0500 Subject: [PATCH 4/5] add tests to growbeg also --- base/array.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/base/array.jl b/base/array.jl index cec313f70d2ad..3dc3ec8d6f1cb 100644 --- a/base/array.jl +++ b/base/array.jl @@ -1068,6 +1068,9 @@ function _growbeg!(a::Vector, delta::Integer) else @noinline (function() memlen = length(mem) + if offset + len - 1 > memlen || offset < 1 + throw(ConcurrencyViolationError("Vector has invalid state. Don't modify internal fields incorrectly, or resize without correct locks")) + end # since we will allocate the array in the middle of the memory we need at least 2*delta extra space # the +1 is because I didn't want to have an off by 1 error. newmemlen = max(overallocation(memlen), len + 2 * delta + 1) @@ -1083,6 +1086,9 @@ function _growbeg!(a::Vector, delta::Integer) newmem = array_new_memory(mem, newmemlen) end unsafe_copyto!(newmem, newoffset + delta, mem, offset, len) + if ref !== a.ref + throw(ConcurrencyViolationError("Vector can not be resized concurrently")) + end setfield!(a, :ref, @inbounds GenericMemoryRef(newmem, newoffset)) end)() end From 2841030ed8fa5cb1710d698c5719e8036a048ba4 Mon Sep 17 00:00:00 2001 From: oscarddssmith Date: Wed, 6 Mar 2024 14:56:26 -0500 Subject: [PATCH 5/5] fix inference --- base/array.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/array.jl b/base/array.jl index 3dc3ec8d6f1cb..76d5981ba8861 100644 --- a/base/array.jl +++ b/base/array.jl @@ -1087,7 +1087,7 @@ function _growbeg!(a::Vector, delta::Integer) end unsafe_copyto!(newmem, newoffset + delta, mem, offset, len) if ref !== a.ref - throw(ConcurrencyViolationError("Vector can not be resized concurrently")) + @noinline throw(ConcurrencyViolationError("Vector can not be resized concurrently")) end setfield!(a, :ref, @inbounds GenericMemoryRef(newmem, newoffset)) end)() @@ -1131,7 +1131,7 @@ function _growend!(a::Vector, delta::Integer) newref = @inbounds GenericMemoryRef(newmem, newoffset) unsafe_copyto!(newref, ref, len) if ref !== a.ref - throw(ConcurrencyViolationError("Vector can not be resized concurrently")) + @noinline throw(ConcurrencyViolationError("Vector can not be resized concurrently")) end setfield!(a, :ref, newref) end)()