Skip to content

Commit 15ca594

Browse files
committed
Fix a small number of invalid unsafe code
Fix #23520
1 parent 4d2e1d7 commit 15ca594

File tree

21 files changed

+93
-56
lines changed

21 files changed

+93
-56
lines changed

base/array.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ that N is inbounds on either array. Incorrect usage may corrupt or segfault your
171171
the same manner as C.
172172
"""
173173
function unsafe_copy!(dest::Array{T}, doffs, src::Array{T}, soffs, n) where T
174+
t1 = @_gc_preserve_begin dest
175+
t2 = @_gc_preserve_begin src
174176
if isbits(T)
175177
unsafe_copy!(pointer(dest, doffs), pointer(src, soffs), n)
176178
elseif isbitsunion(T)
@@ -185,6 +187,8 @@ function unsafe_copy!(dest::Array{T}, doffs, src::Array{T}, soffs, n) where T
185187
ccall(:jl_array_ptr_copy, Void, (Any, Ptr{Void}, Any, Ptr{Void}, Int),
186188
dest, pointer(dest, doffs), src, pointer(src, soffs), n)
187189
end
190+
@_gc_preserve_end t2
191+
@_gc_preserve_end t1
188192
return dest
189193
end
190194

@@ -1570,6 +1574,7 @@ function vcat(arrays::Vector{T}...) where T
15701574
else
15711575
elsz = Core.sizeof(Ptr{Void})
15721576
end
1577+
t = @_gc_preserve_begin arr
15731578
for a in arrays
15741579
na = length(a)
15751580
nba = na * elsz
@@ -1589,6 +1594,7 @@ function vcat(arrays::Vector{T}...) where T
15891594
end
15901595
ptr += nba
15911596
end
1597+
@_gc_preserve_end t
15921598
return arr
15931599
end
15941600

base/datafmt.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ function readdlm_auto(input::AbstractString, dlm::Char, T::Type, eol::Char, auto
130130
# TODO: It would be nicer to use String(a) without making a copy,
131131
# but because the mmap'ed array is not NUL-terminated this causes
132132
# jl_try_substrtod to segfault below.
133-
return readdlm_string(unsafe_string(pointer(a),length(a)), dlm, T, eol, auto, optsd)
133+
return readdlm_string(Base.@gc_preserve(a, unsafe_string(pointer(a),length(a))), dlm, T, eol, auto, optsd)
134134
else
135135
return readdlm_string(read(input, String), dlm, T, eol, auto, optsd)
136136
end
@@ -220,7 +220,7 @@ function DLMStore(::Type{T}, dims::NTuple{2,Integer},
220220
end
221221

222222
_chrinstr(sbuff::String, chr::UInt8, startpos::Int, endpos::Int) =
223-
(endpos >= startpos) && (C_NULL != ccall(:memchr, Ptr{UInt8},
223+
Base.@gc_preserve sbuff (endpos >= startpos) && (C_NULL != ccall(:memchr, Ptr{UInt8},
224224
(Ptr{UInt8}, Int32, Csize_t), pointer(sbuff)+startpos-1, chr, endpos-startpos+1))
225225

226226
function store_cell(dlmstore::DLMStore{T}, row::Int, col::Int,

base/deepcopy.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ function deepcopy_internal(x::String, stackdict::ObjectIdDict)
4646
if haskey(stackdict, x)
4747
return stackdict[x]
4848
end
49-
y = unsafe_string(pointer(x), sizeof(x))
49+
y = @gc_preserve x unsafe_string(pointer(x), sizeof(x))
5050
stackdict[x] = y
5151
return y
5252
end

base/env.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ if Sys.iswindows()
9999
blk = block[2]
100100
len = ccall(:wcslen, UInt, (Ptr{UInt16},), pos)
101101
buf = Vector{UInt16}(len)
102-
unsafe_copy!(pointer(buf), pos, len)
102+
@gc_preserve buf unsafe_copy!(pointer(buf), pos, len)
103103
env = transcode(String, buf)
104104
m = match(r"^(=?[^=]+)=(.*)$"s, env)
105105
if m === nothing

base/essentials.jl

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ macro _noinline_meta()
1818
Expr(:meta, :noinline)
1919
end
2020

21+
macro _gc_preserve_begin(arg1)
22+
Expr(:gc_preserve_begin, esc(arg1))
23+
end
24+
25+
macro _gc_preserve_end(token)
26+
Expr(:gc_preserve_end, esc(token))
27+
end
28+
2129
"""
2230
@nospecialize
2331
@@ -513,16 +521,23 @@ end
513521
# SimpleVector
514522

515523
function getindex(v::SimpleVector, i::Int)
516-
if !(1 <= i <= length(v))
524+
@boundscheck if !(1 <= i <= length(v))
517525
throw(BoundsError(v,i))
518526
end
527+
t = @_gc_preserve_begin v
519528
x = unsafe_load(convert(Ptr{Ptr{Void}},data_pointer_from_objref(v)) + i*sizeof(Ptr))
520529
x == C_NULL && throw(UndefRefError())
521-
return unsafe_pointer_to_objref(x)
530+
o = unsafe_pointer_to_objref(x)
531+
@_gc_preserve_end t
532+
return o
522533
end
523534

524-
# TODO: add gc use intrinsic call instead of noinline
525-
length(v::SimpleVector) = (@_noinline_meta; unsafe_load(convert(Ptr{Int},data_pointer_from_objref(v))))
535+
function length(v::SimpleVector)
536+
t = @_gc_preserve_begin v
537+
l = unsafe_load(convert(Ptr{Int},data_pointer_from_objref(v)))
538+
@_gc_preserve_end t
539+
return l
540+
end
526541
endof(v::SimpleVector) = length(v)
527542
start(v::SimpleVector) = 1
528543
next(v::SimpleVector,i) = (v[i],i+1)
@@ -573,7 +588,9 @@ function isassigned end
573588

574589
function isassigned(v::SimpleVector, i::Int)
575590
@boundscheck 1 <= i <= length(v) || return false
591+
t = @_gc_preserve_begin v
576592
x = unsafe_load(convert(Ptr{Ptr{Void}},data_pointer_from_objref(v)) + i*sizeof(Ptr))
593+
@_gc_preserve_end t
577594
return x != C_NULL
578595
end
579596

base/gmp.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ function tryparse_internal(::Type{BigInt}, s::AbstractString, startpos::Int, end
252252
if Base.containsnul(bstr)
253253
err = -1 # embedded NUL char (not handled correctly by GMP)
254254
else
255-
err = MPZ.set_str!(z, pointer(bstr)+(i-start(bstr)), base)
255+
err = Base.@gc_preserve bstr MPZ.set_str!(z, pointer(bstr)+(i-start(bstr)), base)
256256
end
257257
if err != 0
258258
raise && throw(ArgumentError("invalid BigInt: $(repr(bstr))"))
@@ -612,7 +612,7 @@ function base(b::Integer, n::BigInt, pad::Integer=1)
612612
nd1 = ndigits(n, b)
613613
nd = max(nd1, pad)
614614
sv = Base.StringVector(nd + isneg(n))
615-
MPZ.get_str!(pointer(sv) + nd - nd1, b, n)
615+
Base.@gc_preserve sv MPZ.get_str!(pointer(sv) + nd - nd1, b, n)
616616
@inbounds for i = (1:nd-nd1) .+ isneg(n)
617617
sv[i] = '0' % UInt8
618618
end

base/io.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,9 @@ function write(s::IO, A::AbstractArray)
365365
return nb
366366
end
367367

368-
@noinline function write(s::IO, a::Array) # mark noinline to ensure the array is gc-rooted somewhere (by the caller)
368+
function write(s::IO, a::Array)
369369
if isbits(eltype(a))
370-
return unsafe_write(s, pointer(a), sizeof(a))
370+
return @gc_preserve a unsafe_write(s, pointer(a), sizeof(a))
371371
else
372372
depwarn("Calling `write` on non-isbits arrays is deprecated. Use a loop or `serialize` instead.", :write)
373373
nb = 0
@@ -384,7 +384,7 @@ function write(s::IO, a::SubArray{T,N,<:Array}) where {T,N}
384384
end
385385
elsz = sizeof(T)
386386
colsz = size(a,1) * elsz
387-
if stride(a,1) != 1
387+
@gc_preserve a if stride(a,1) != 1
388388
for idxs in CartesianRange(size(a))
389389
unsafe_write(s, pointer(a, idxs.I), elsz)
390390
end
@@ -444,14 +444,14 @@ end
444444
read(s::IO, ::Type{Bool}) = (read(s, UInt8) != 0)
445445
read(s::IO, ::Type{Ptr{T}}) where {T} = convert(Ptr{T}, read(s, UInt))
446446

447-
@noinline function read!(s::IO, a::Array{UInt8}) # mark noinline to ensure the array is gc-rooted somewhere (by the caller)
448-
unsafe_read(s, pointer(a), sizeof(a))
447+
function read!(s::IO, a::Array{UInt8})
448+
@gc_preserve a unsafe_read(s, pointer(a), sizeof(a))
449449
return a
450450
end
451451

452-
@noinline function read!(s::IO, a::Array{T}) where T # mark noinline to ensure the array is gc-rooted somewhere (by the caller)
452+
function read!(s::IO, a::Array{T}) where T
453453
if isbits(T)
454-
unsafe_read(s, pointer(a), sizeof(a))
454+
@gc_preserve a unsafe_read(s, pointer(a), sizeof(a))
455455
else
456456
for i in eachindex(a)
457457
a[i] = read(s, T)

base/iobuffer.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ function unsafe_read(from::GenericIOBuffer, p::Ptr{UInt8}, nb::UInt)
9999
from.readable || throw(ArgumentError("read failed, IOBuffer is not readable"))
100100
avail = nb_available(from)
101101
adv = min(avail, nb)
102-
unsafe_copy!(p, pointer(from.data, from.ptr), adv)
102+
@gc_preserve from unsafe_copy!(p, pointer(from.data, from.ptr), adv)
103103
from.ptr += adv
104104
if nb > avail
105105
throw(EOFError())
@@ -114,7 +114,7 @@ function read_sub(from::GenericIOBuffer, a::AbstractArray{T}, offs, nel) where T
114114
end
115115
if isbits(T) && isa(a,Array)
116116
nb = UInt(nel * sizeof(T))
117-
unsafe_read(from, pointer(a, offs), nb)
117+
@gc_preserve a unsafe_read(from, pointer(a, offs), nb)
118118
else
119119
for i = offs:offs+nel-1
120120
a[i] = read(to, T)
@@ -334,7 +334,7 @@ function write_sub(to::GenericIOBuffer, a::AbstractArray{UInt8}, offs, nel)
334334
if offs+nel-1 > length(a) || offs < 1 || nel < 0
335335
throw(BoundsError())
336336
end
337-
unsafe_write(to, pointer(a, offs), UInt(nel))
337+
@gc_preserve a unsafe_write(to, pointer(a, offs), UInt(nel))
338338
end
339339

340340
@inline function write(to::GenericIOBuffer, a::UInt8)
@@ -367,7 +367,7 @@ read(io::GenericIOBuffer, nb::Integer) = read!(io,StringVector(min(nb, nb_availa
367367

368368
function search(buf::IOBuffer, delim::UInt8)
369369
p = pointer(buf.data, buf.ptr)
370-
q = ccall(:memchr,Ptr{UInt8},(Ptr{UInt8},Int32,Csize_t),p,delim,nb_available(buf))
370+
q = @gc_preserve buf ccall(:memchr,Ptr{UInt8},(Ptr{UInt8},Int32,Csize_t),p,delim,nb_available(buf))
371371
nb::Int = (q == C_NULL ? 0 : q-p+1)
372372
return nb
373373
end
@@ -413,7 +413,7 @@ function crc32c(io::IOBuffer, nb::Integer, crc::UInt32=0x00000000)
413413
io.readable || throw(ArgumentError("read failed, IOBuffer is not readable"))
414414
n = min(nb, nb_available(io))
415415
n == 0 && return crc
416-
crc = unsafe_crc32c(pointer(io.data, io.ptr), n, crc)
416+
crc = @gc_preserve io unsafe_crc32c(pointer(io.data, io.ptr), n, crc)
417417
io.ptr += n
418418
return crc
419419
end

base/iostream.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ end
264264
function readbytes_all!(s::IOStream, b::Array{UInt8}, nb)
265265
olb = lb = length(b)
266266
nr = 0
267-
while nr < nb
267+
@gc_preserve b while nr < nb
268268
if lb < nr+1
269269
lb = max(65536, (nr+1) * 2)
270270
resize!(b, lb)
@@ -284,8 +284,8 @@ function readbytes_some!(s::IOStream, b::Array{UInt8}, nb)
284284
if nb > lb
285285
resize!(b, nb)
286286
end
287-
nr = Int(ccall(:ios_read, Csize_t, (Ptr{Void}, Ptr{Void}, Csize_t),
288-
s.ios, pointer(b), nb))
287+
nr = @gc_preserve b Int(ccall(:ios_read, Csize_t, (Ptr{Void}, Ptr{Void}, Csize_t),
288+
s.ios, pointer(b), nb))
289289
if lb > olb && lb > nr
290290
resize!(b, nr)
291291
end

base/libc.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ function gethostname()
249249
ccall(:gethostname, Int32, (Ptr{UInt8}, UInt), hn, length(hn))
250250
end
251251
systemerror("gethostname", err != 0)
252-
return unsafe_string(pointer(hn))
252+
return Base.@gc_preserve hn unsafe_string(pointer(hn))
253253
end
254254

255255
## system error handling ##
@@ -305,7 +305,7 @@ if Sys.iswindows()
305305
p = lpMsgBuf[]
306306
len == 0 && return ""
307307
buf = Vector{UInt16}(len)
308-
unsafe_copy!(pointer(buf), p, len)
308+
Base.@gc_preserve buf unsafe_copy!(pointer(buf), p, len)
309309
ccall(:LocalFree, stdcall, Ptr{Void}, (Ptr{Void},), p)
310310
return transcode(String, buf)
311311
end

0 commit comments

Comments
 (0)