From 851a892d29732cc651c3e7fbd07bd9937c87b3e5 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Fri, 16 Feb 2018 23:36:39 +0100 Subject: [PATCH] Make resize! a no-op when size does not change Else we set the last element to zero for one-byte element types like UInt8, which means that resizing a vector allocated with StringVector corrupts it. Also add redundant checks in Julia code to avoid a function call. --- base/array.jl | 2 +- src/array.c | 4 ++++ test/arrayops.jl | 15 +++++++++++++++ test/strings/basic.jl | 10 ++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/base/array.jl b/base/array.jl index 458dab4ef1356..353c4029dd778 100644 --- a/base/array.jl +++ b/base/array.jl @@ -936,7 +936,7 @@ function resize!(a::Vector, nl::Integer) l = length(a) if nl > l ccall(:jl_array_grow_end, Cvoid, (Any, UInt), a, nl-l) - else + elseif nl != l if nl < 0 throw(ArgumentError("new length must be ≥ 0")) end diff --git a/src/array.c b/src/array.c index 5c36497ad7b29..4b91b6314413d 100644 --- a/src/array.c +++ b/src/array.c @@ -999,6 +999,8 @@ JL_DLLEXPORT void jl_array_del_beg(jl_array_t *a, size_t dec) jl_bounds_error_int((jl_value_t*)a, dec); if (__unlikely(a->flags.isshared)) array_try_unshare(a); + if (dec == 0) + return; jl_array_del_at_beg(a, 0, dec, n); } @@ -1009,6 +1011,8 @@ JL_DLLEXPORT void jl_array_del_end(jl_array_t *a, size_t dec) jl_bounds_error_int((jl_value_t*)a, 0); if (__unlikely(a->flags.isshared)) array_try_unshare(a); + if (dec == 0) + return; jl_array_del_at_end(a, n - dec, dec, n); } diff --git a/test/arrayops.jl b/test/arrayops.jl index 3f25e6000fb8c..2bf39e8d5f33b 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -2342,4 +2342,19 @@ Base.view(::T25958, args...) = args @test t[end,1,end] == @view(t[end,1,end]) == @views t[end,1,end] @test t[end,end,1] == @view(t[end,end,1]) == @views t[end,end,1] @test t[end,end,end] == @view(t[end,end,end]) == @views t[end,end,end] +end + +# resize! sets the last element to zero when element size is one byte +@testset "check that resize! is a no-op when size does not change" for T in (Int, UInt8, Int8) + x = Vector{T}(uninitialized, 1) + resize!(x, 0) + unsafe_store!(pointer(x), 1, 1) + resize!(x, 0) + @test unsafe_load(pointer(x), 1) == 1 + + x = Vector{T}(uninitialized, 2) + resize!(x, 1) + unsafe_store!(pointer(x), 1, 2) + resize!(x, 1) + @test unsafe_load(pointer(x), 2) == 1 end \ No newline at end of file diff --git a/test/strings/basic.jl b/test/strings/basic.jl index 5b7e2b8b24c05..e86a4925ec0f8 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -8,6 +8,16 @@ using Random @test String("abc!") == "abc!" @test String(0x61:0x63) == "abc" + # Check that resizing empty source vector does not corrupt string + b = IOBuffer() + write(b, "ab") + x = take!(b) + s = String(x) + resize!(x, 0) + @test s == "ab" + resize!(x, 1) + @test s == "ab" + @test isempty(string()) @test eltype(GenericString) == Char @test firstindex("abc") == 1