Skip to content

Commit be8564c

Browse files
committed
Array resizing fixes and clean up
* Move `memcpy` and `memmove` from julia to C (this is dangerous especially for `ptrarray`) * Make sure resizing a ptrarray always have the new memory cleared * Make sure resizing a byte array always have the implicit NUL byte * Use array flag to conditionally copy the array when there's no implicit NUL byte in the array. * Add more test for shared array resizing and implicit NUL byte check
1 parent 59d1539 commit be8564c

File tree

6 files changed

+478
-247
lines changed

6 files changed

+478
-247
lines changed

base/array.jl

Lines changed: 18 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ end
3838
## copy ##
3939

4040
function unsafe_copy!{T}(dest::Ptr{T}, src::Ptr{T}, n)
41+
# Do not use this to copy data between arrays.
42+
# It can't be made safe no matter how carefully you checked.
4143
ccall(:memmove, Ptr{Void}, (Ptr{Void}, Ptr{Void}, UInt),
4244
dest, src, n*sizeof(T))
4345
return dest
@@ -64,11 +66,7 @@ end
6466

6567
copy!{T}(dest::Array{T}, src::Array{T}) = copy!(dest, 1, src, 1, length(src))
6668

67-
function copy(a::Array)
68-
b = similar(a)
69-
ccall(:memcpy, Ptr{Void}, (Ptr{Void}, Ptr{Void}, UInt), b, a, sizeof(a))
70-
return b
71-
end
69+
copy{T<:Array}(a::T) = ccall(:jl_array_copy, Ref{T}, (Any,), a)
7270

7371
function reinterpret{T,S}(::Type{T}, a::Array{S,1})
7472
nel = Int(div(length(a)*sizeof(S),sizeof(T)))
@@ -386,66 +384,13 @@ setindex!{T, N}(A::Array{T, N}, x::Number, ::Vararg{Colon, N}) = fill!(A, x)
386384

387385
# efficiently grow an array
388386

389-
function _growat!(a::Vector, i::Integer, delta::Integer)
390-
n = length(a)
391-
if i < div(n,2)
392-
_growat_beg!(a, i, delta)
393-
else
394-
_growat_end!(a, i, delta)
395-
end
396-
return a
397-
end
398-
399-
function _growat_beg!(a::Vector, i::Integer, delta::Integer)
400-
ccall(:jl_array_grow_beg, Void, (Any, UInt), a, delta)
401-
if i > 1
402-
ccall(:memmove, Ptr{Void}, (Ptr{Void}, Ptr{Void}, Csize_t),
403-
pointer(a, 1), pointer(a, 1+delta), (i-1)*elsize(a))
404-
end
405-
return a
406-
end
407-
408-
function _growat_end!(a::Vector, i::Integer, delta::Integer)
409-
ccall(:jl_array_grow_end, Void, (Any, UInt), a, delta)
410-
n = length(a)
411-
if n >= i+delta
412-
ccall(:memmove, Ptr{Void}, (Ptr{Void}, Ptr{Void}, Csize_t),
413-
pointer(a, i+delta), pointer(a, i), (n-i-delta+1)*elsize(a))
414-
end
415-
return a
416-
end
387+
_growat!(a::Vector, i::Integer, delta::Integer) =
388+
ccall(:jl_array_grow_at, Void, (Any, Int, UInt), a, i - 1, delta)
417389

418390
# efficiently delete part of an array
419391

420-
function _deleteat!(a::Vector, i::Integer, delta::Integer)
421-
n = length(a)
422-
last = i+delta-1
423-
if i-1 < n-last
424-
_deleteat_beg!(a, i, delta)
425-
else
426-
_deleteat_end!(a, i, delta)
427-
end
428-
return a
429-
end
430-
431-
function _deleteat_beg!(a::Vector, i::Integer, delta::Integer)
432-
if i > 1
433-
ccall(:memmove, Ptr{Void}, (Ptr{Void}, Ptr{Void}, Csize_t),
434-
pointer(a, 1+delta), pointer(a, 1), (i-1)*elsize(a))
435-
end
436-
ccall(:jl_array_del_beg, Void, (Any, UInt), a, delta)
437-
return a
438-
end
439-
440-
function _deleteat_end!(a::Vector, i::Integer, delta::Integer)
441-
n = length(a)
442-
if n >= i+delta
443-
ccall(:memmove, Ptr{Void}, (Ptr{Void}, Ptr{Void}, Csize_t),
444-
pointer(a, i), pointer(a, i+delta), (n-i-delta+1)*elsize(a))
445-
end
446-
ccall(:jl_array_del_end, Void, (Any, UInt), a, delta)
447-
return a
448-
end
392+
_deleteat!(a::Vector, i::Integer, delta::Integer) =
393+
ccall(:jl_array_del_at, Void, (Any, Int, UInt), a, i - 1, delta)
449394

450395
## Dequeue functionality ##
451396

@@ -525,34 +470,20 @@ function shift!(a::Vector)
525470
end
526471

527472
function insert!{T}(a::Array{T,1}, i::Integer, item)
528-
if !(1 <= i <= length(a)+1)
529-
throw(BoundsError())
530-
end
531-
if i == length(a)+1
532-
return push!(a, item)
533-
end
534-
item = convert(T, item)
473+
# Throw convert error before changing the shape of the array
474+
_item = convert(T, item)
535475
_growat!(a, i, 1)
536-
a[i] = item
476+
# _growat! already did bound check
477+
@inbounds a[i] = _item
537478
return a
538479
end
539480

540-
function deleteat!(a::Vector, i::Integer)
541-
if !(1 <= i <= length(a))
542-
throw(BoundsError())
543-
end
544-
return _deleteat!(a, i, 1)
545-
end
481+
deleteat!(a::Vector, i::Integer) = (_deleteat!(a, i, 1); a)
546482

547483
function deleteat!{T<:Integer}(a::Vector, r::UnitRange{T})
548484
n = length(a)
549-
isempty(r) && return a
550-
f = first(r)
551-
l = last(r)
552-
if !(1 <= f && l <= n)
553-
throw(BoundsError())
554-
end
555-
return _deleteat!(a, f, length(r))
485+
isempty(r) || _deleteat!(a, first(r), length(r))
486+
return a
556487
end
557488

558489
function deleteat!(a::Vector, inds)
@@ -619,18 +550,9 @@ function splice!{T<:Integer}(a::Vector, r::UnitRange{T}, ins=_default_splice)
619550

620551
if m < d
621552
delta = d - m
622-
if f-1 < n-l
623-
_deleteat_beg!(a, f, delta)
624-
else
625-
_deleteat_end!(a, l-delta+1, delta)
626-
end
553+
_deleteat!(a, (f - 1 < n - l) ? f : (l - delta + 1), delta)
627554
elseif m > d
628-
delta = m - d
629-
if f-1 < n-l
630-
_growat_beg!(a, f, delta)
631-
else
632-
_growat_end!(a, l+1, delta)
633-
end
555+
_growat!(a, (f - 1 < n - l) ? f : (l + 1), m - d)
634556
end
635557

636558
k = 1
@@ -683,27 +605,8 @@ function reverse!(v::AbstractVector, s=1, n=length(v))
683605
return v
684606
end
685607

686-
function vcat{T}(arrays::Vector{T}...)
687-
n = 0
688-
for a in arrays
689-
n += length(a)
690-
end
691-
arr = Array{T}(n)
692-
ptr = pointer(arr)
693-
offset = 0
694-
if isbits(T)
695-
elsz = sizeof(T)
696-
else
697-
elsz = Core.sizeof(Ptr{Void})
698-
end
699-
for a in arrays
700-
nba = length(a)*elsz
701-
ccall(:memcpy, Ptr{Void}, (Ptr{Void}, Ptr{Void}, UInt),
702-
ptr+offset, a, nba)
703-
offset += nba
704-
end
705-
return arr
706-
end
608+
vcat{T}(arrays::Vector{T}...) =
609+
ccall(:jl_array_vcat_vectors, Ref{Vector{T}}, (Any,), arrays)
707610

708611
function hcat{T}(V::Vector{T}...)
709612
height = length(V[1])

base/c.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,18 @@ unsafe_wrap(::Type{String}, p::Cstring, len::Integer, own::Bool=false) =
8080
unsafe_string(s::Cstring) = unsafe_string(convert(Ptr{UInt8}, s))
8181

8282
# convert strings to String etc. to pass as pointers
83-
cconvert(::Type{Cstring}, s::AbstractString) = String(s)
83+
cconvert(::Type{Cstring}, s::String) =
84+
ccall(:jl_array_cconvert_cstring, Ref{Vector{UInt8}},
85+
(Vector{UInt8},), s.data)
86+
cconvert(::Type{Cstring}, s::AbstractString) = String(s)::String
8487
cconvert(::Type{Cwstring}, s::AbstractString) = wstring(s)
8588

8689
containsnul(p::Ptr, len) =
8790
C_NULL != ccall(:memchr, Ptr{Cchar}, (Ptr{Cchar}, Cint, Csize_t), p, 0, len)
8891
containsnul(s::String) = containsnul(unsafe_convert(Ptr{Cchar}, s), sizeof(s))
8992
containsnul(s::AbstractString) = '\0' in s
9093

91-
function unsafe_convert(::Type{Cstring}, s::String)
94+
function unsafe_convert(::Type{Cstring}, s::Union{String,Vector{UInt8}})
9295
p = unsafe_convert(Ptr{Cchar}, s)
9396
if containsnul(p, sizeof(s))
9497
throw(ArgumentError("embedded NULs are not allowed in C strings: $(repr(s))"))

base/precompile.jl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,7 @@ precompile(Libc.TmStruct, (Float64,))
154154
precompile(Base.VersionNumber, (Int, Int, Int, Tuple{}, Tuple{String}))
155155
precompile(Base._atexit, ())
156156
precompile(Base._deleteat!, (Array{UInt8, 1}, Int, Int))
157-
precompile(Base._deleteat_beg!, (Array{UInt8, 1}, Int, Int))
158-
precompile(Base._deleteat_end!, (Array{UInt8, 1}, Int, Int))
159-
precompile(Base._growat_beg!, (Array{UInt8, 1}, Int, Int))
160-
precompile(Base._growat_end!, (Array{UInt8, 1}, Int, Int))
157+
precompile(Base._growat!, (Array{UInt8, 1}, Int, Int))
161158
precompile(Base._setindex!, (Base.Dict{Symbol, Any}, Base.LineEdit.Prompt, Symbol, Int))
162159
precompile(Base._setindex!, (Dict{Any, Any}, Base.LineEdit.PromptState, Base.LineEdit.Prompt, Int))
163160
precompile(Base._setindex!, (Dict{Any, Any}, Bool, WeakRef, Int))

0 commit comments

Comments
 (0)