Skip to content

Commit 16fb745

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 b848fd8 commit 16fb745

File tree

9 files changed

+543
-267
lines changed

9 files changed

+543
-267
lines changed

base/array.jl

Lines changed: 24 additions & 121 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
@@ -65,11 +67,7 @@ end
6567

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

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

7472
function reinterpret{T,S}(::Type{T}, a::Array{S,1})
7573
nel = Int(div(length(a)*sizeof(S),sizeof(T)))
@@ -120,14 +118,14 @@ end
120118
## Constructors ##
121119

122120
similar(a::Array, T::Type, dims::Dims) = Array{T}(dims)
123-
similar{T}(a::Array{T,1}) = Array{T}(size(a,1))
124-
similar{T}(a::Array{T,2}) = Array{T}(size(a,1), size(a,2))
121+
similar{T<:Array}(a::T) =
122+
ccall(:jl_array_similar, Ref{T}, (Any,), a)
123+
similar{T}(a::Array{T}, m::Int) =
124+
ccall(:jl_array_similar_1d, Ref{Vector{T}}, (Any, Any, Int), Vector{T}, a, m)
125+
similar{T}(a::Array{T,1}, S::Type) = Vector{S}(size(a,1))
126+
similar{T}(a::Array{T,2}, S::Type) = Matrix{S}(size(a,1), size(a,2))
125127
similar{T}(a::Array{T,1}, dims::Dims) = Array{T}(dims)
126-
similar{T}(a::Array{T,1}, m::Int) = Array{T}(m)
127-
similar{T}(a::Array{T,1}, S::Type) = Array{S}(size(a,1))
128128
similar{T}(a::Array{T,2}, dims::Dims) = Array{T}(dims)
129-
similar{T}(a::Array{T,2}, m::Int) = Array{T}(m)
130-
similar{T}(a::Array{T,2}, S::Type) = Array{S}(size(a,1), size(a,2))
131129

132130
# T[x...] constructs Array{T,1}
133131
function getindex(T::Type, vals...)
@@ -387,66 +385,13 @@ setindex!{T, N}(A::Array{T, N}, x::Number, ::Vararg{Colon, N}) = fill!(A, x)
387385

388386
# efficiently grow an array
389387

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

419391
# efficiently delete part of an array
420392

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

451396
## Dequeue functionality ##
452397

@@ -526,34 +471,20 @@ function shift!(a::Vector)
526471
end
527472

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

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

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

559490
function deleteat!(a::Vector, inds)
@@ -620,18 +551,9 @@ function splice!{T<:Integer}(a::Vector, r::UnitRange{T}, ins=_default_splice)
620551

621552
if m < d
622553
delta = d - m
623-
if f-1 < n-l
624-
_deleteat_beg!(a, f, delta)
625-
else
626-
_deleteat_end!(a, l-delta+1, delta)
627-
end
554+
_deleteat!(a, (f - 1 < n - l) ? f : (l - delta + 1), delta)
628555
elseif m > d
629-
delta = m - d
630-
if f-1 < n-l
631-
_growat_beg!(a, f, delta)
632-
else
633-
_growat_end!(a, l+1, delta)
634-
end
556+
_growat!(a, (f - 1 < n - l) ? f : (l + 1), m - d)
635557
end
636558

637559
k = 1
@@ -684,27 +606,8 @@ function reverse!(v::AbstractVector, s=1, n=length(v))
684606
return v
685607
end
686608

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

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

base/c.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,19 @@ 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) =
87+
cconvert(Cstring, String(s)::String)
8488
cconvert(::Type{Cwstring}, s::AbstractString) = wstring(s)
8589

8690
containsnul(p::Ptr, len) =
8791
C_NULL != ccall(:memchr, Ptr{Cchar}, (Ptr{Cchar}, Cint, Csize_t), p, 0, len)
8892
containsnul(s::String) = containsnul(unsafe_convert(Ptr{Cchar}, s), sizeof(s))
8993
containsnul(s::AbstractString) = '\0' in s
9094

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

base/libgit2.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ function clone{P<:AbstractPayload}(repo_url::AbstractString, repo_path::Abstract
297297
remote_cb::Ptr{Void} = C_NULL,
298298
payload::Nullable{P}=Nullable{AbstractPayload}())
299299
# setup clone options
300-
lbranch = Base.cconvert(Cstring, String(branch))
300+
lbranch = Base.cconvert(Cstring, branch)
301301
fetch_opts=FetchOptions(callbacks = RemoteCallbacks(credentials_cb(), payload))
302302
clone_opts = CloneOptions(
303303
bare = Cint(isbare),

base/libgit2/strarray.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
function StrArrayStruct{T<:AbstractString}(strs::T...)
44
strcount = length(strs)
5-
map(s->Base.unsafe_convert(Cstring, String(s)), strs) # check for null-strings
5+
for s in strs
6+
if Base.containsnul(s)
7+
throw("embedded NULs are not allowed in C strings: $(repr(s))")
8+
end
9+
end
610
sa_strings = convert(Ptr{Cstring}, Libc.malloc(sizeof(Cstring) * strcount))
711
for i=1:strcount
812
len = length(strs[i])

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)