Skip to content

Commit

Permalink
fix #9037: segfault caused by incorrect alignment assumptions
Browse files Browse the repository at this point in the history
The rand!(::MersenneTwister, A::Array{Float64}) assumed that the
array A was 16-byte aligned, which can be false (e.g. after a call
to resize!) and lead to a segfault in libdSFMT.
  • Loading branch information
rfourquet committed Nov 17, 2014
1 parent aa1f53b commit 4e0ae82
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 12 deletions.
13 changes: 6 additions & 7 deletions base/dSFMT.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,18 @@ function dsfmt_init_by_array(s::DSFMT_state, seed::Vector{UInt32})
s.val, seed, length(seed))
end


# precondition for dsfmt_fill_array_*:
# the underlying C array must be 16-byte aligned, which is the case for "Array"
function dsfmt_fill_array_close1_open2!(s::DSFMT_state, A::Array{Float64}, n::Int)
@assert dsfmt_min_array_size <= n <= length(A) && iseven(n)
function dsfmt_fill_array_close1_open2!(s::DSFMT_state, A::Ptr{Float64}, n::Int)
@assert Int(A) % 16 == 0 # the underlying C array must be 16-byte aligned
@assert dsfmt_min_array_size <= n && iseven(n)
ccall((:dsfmt_fill_array_close1_open2,:libdSFMT),
Void,
(Ptr{Void}, Ptr{Float64}, Int),
s.val, A, n)
end

function dsfmt_fill_array_close_open!(s::DSFMT_state, A::Array{Float64}, n::Int)
@assert dsfmt_min_array_size <= n <= length(A) && iseven(n)
function dsfmt_fill_array_close_open!(s::DSFMT_state, A::Ptr{Float64}, n::Int)
@assert Int(A) % 16 == 0 # the underlying C array must be 16-byte aligned
@assert dsfmt_min_array_size <= n && iseven(n)
ccall((:dsfmt_fill_array_close_open,:libdSFMT),
Void,
(Ptr{Void}, Ptr{Float64}, Int),
Expand Down
23 changes: 18 additions & 5 deletions base/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ end
@inline mt_pop!(r::MersenneTwister) = @inbounds return r.vals[r.idx+=1]

function gen_rand(r::MersenneTwister)
dsfmt_fill_array_close1_open2!(r.state, r.vals, length(r.vals))
dsfmt_fill_array_close1_open2!(r.state, pointer(r.vals), length(r.vals))
mt_setfull!(r)
end

Expand Down Expand Up @@ -218,15 +218,28 @@ end

rand!(r::MersenneTwister, A::AbstractArray{Float64}) = rand_AbstractArray_Float64!(r, A)

fill_array!(s::DSFMT_state, A::Array{Float64}, n::Int, ::Type{CloseOpen}) = dsfmt_fill_array_close_open!(s, A, n)
fill_array!(s::DSFMT_state, A::Array{Float64}, n::Int, ::Type{Close1Open2}) = dsfmt_fill_array_close1_open2!(s, A, n)
fill_array!(s::DSFMT_state, A::Ptr{Float64}, n::Int, ::Type{CloseOpen}) = dsfmt_fill_array_close_open!(s, A, n)
fill_array!(s::DSFMT_state, A::Ptr{Float64}, n::Int, ::Type{Close1Open2}) = dsfmt_fill_array_close1_open2!(s, A, n)

function rand!{I<:FloatInterval}(r::MersenneTwister, A::Array{Float64}, n=length(A), ::Type{I}=CloseOpen)
if n < dsfmt_get_min_array_size()
rand_AbstractArray_Float64!(r, A, n, I)
else
fill_array!(r.state, A, 2*(n ÷ 2), I)
isodd(n) && (A[n] = rand(r, I))
pA = pointer(A)
rem = Int(pA) % 16
if rem > 0
pA2 = pA + 16 - rem
n2 = rem < 8 ? n-2 : n-1
rand!(r, pointer_to_array(pA2, n2), n2, I)
unsafe_copy!(pA, pA2, n2)
for i=n2+1:n
A[i] = rand(r, I)
end
else
# pA is 16-byte aligned, so it's safe to use fill_array!
fill_array!(r.state, pA, 2*(n ÷ 2), I)
isodd(n) && (A[n] = rand(r, I))
end
end
A
end
Expand Down

0 comments on commit 4e0ae82

Please sign in to comment.