Skip to content

Commit

Permalink
Do not reinterpret to wrong alignment
Browse files Browse the repository at this point in the history
This is undefined behavior in LLVM and can actually segfault on real hardware
including x86 in certain cases.

Also add missing endianess test since it is changed in this commit.
  • Loading branch information
yuyichao committed May 17, 2017
1 parent cff2d75 commit 99286f9
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 28 deletions.
5 changes: 3 additions & 2 deletions base/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -283,11 +283,12 @@ function copy_to_bitarray_chunks!(Bc::Vector{UInt64}, pos_d::Int, C::Array{Bool}
nc8 = (nc >>> 3) << 3
if nc8 > 0
ind8 = 1
C8 = reinterpret(UInt64, unsafe_wrap(Array, pointer(C, ind), nc8 << 6))
P8 = Ptr{UInt64}(pointer(C, ind)) # unaligned i64 pointer
@inbounds for i = 1:nc8
c = UInt64(0)
for j = 0:7
c |= (pack8bools(C8[ind8]) << (j<<3))
# unaligned load
c |= (pack8bools(unsafe_load(P8, ind8)) << (j<<3))
ind8 += 1
end
Bc[bind] = c
Expand Down
10 changes: 7 additions & 3 deletions base/dSFMT.jl
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,13 @@ end

# dSFMT jump
function dsfmt_jump(s::DSFMT_state, jp::AbstractString)
index = s.val[end-1]
work = zeros(UInt64, JN32>>1)
dsfmt = reinterpret(UInt64, copy(s.val))
val = s.val
nval = length(val)
index = val[nval - 1]
work = zeros(UInt64, JN32 >> 1)
dsfmt = Vector{UInt64}(nval >> 1)
ccall(:memcpy, Ptr{Void}, (Ptr{UInt64}, Ptr{Int32}, Csize_t),
dsfmt, val, (nval - 1) * sizeof(Int32))
dsfmt[end] = UInt64(N*2)

for c in jp
Expand Down
36 changes: 20 additions & 16 deletions base/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -215,29 +215,33 @@ readlines(s=STDIN; chomp::Bool=true) = collect(eachline(s, chomp=chomp))

## byte-order mark, ntoh & hton ##

let endian_boms = reinterpret(UInt8, UInt32[0x01020304])
global ntoh, hton, ltoh, htol
if endian_boms == UInt8[1:4;]
ntoh(x) = x
hton(x) = x
ltoh(x) = bswap(x)
htol(x) = bswap(x)
const global ENDIAN_BOM = 0x01020304
elseif endian_boms == UInt8[4:-1:1;]
ntoh(x) = bswap(x)
hton(x) = bswap(x)
ltoh(x) = x
htol(x) = x
const global ENDIAN_BOM = 0x04030201
else
error("seriously? what is this machine?")
end
end

"""
ENDIAN_BOM
The 32-bit byte-order-mark indicates the native byte order of the host machine.
Little-endian machines will contain the value `0x04030201`. Big-endian machines will contain
the value `0x01020304`.
"""
const ENDIAN_BOM = reinterpret(UInt32,UInt8[1:4;])[1]

if ENDIAN_BOM == 0x01020304
ntoh(x) = x
hton(x) = x
ltoh(x) = bswap(x)
htol(x) = bswap(x)
elseif ENDIAN_BOM == 0x04030201
ntoh(x) = bswap(x)
hton(x) = bswap(x)
ltoh(x) = x
htol(x) = x
else
error("seriously? what is this machine?")
end

ENDIAN_BOM

"""
ntoh(x)
Expand Down
8 changes: 4 additions & 4 deletions base/pcre.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,18 @@ const OPTIONS_MASK = COMPILE_MASK | EXECUTE_MASK

const UNSET = ~Csize_t(0) # Indicates that an output vector element is unset

function info(regex::Ptr{Void}, what::Integer, T)
buf = zeros(UInt8,sizeof(T))
function info(regex::Ptr{Void}, what::Integer, ::Type{T}) where T
buf = Ref{T}()
ret = ccall((:pcre2_pattern_info_8, PCRE_LIB), Int32,
(Ptr{Void}, Int32, Ptr{UInt8}),
(Ptr{Void}, Int32, Ptr{Void}),
regex, what, buf)
if ret != 0
error(ret == ERROR_NULL ? "NULL regex object" :
ret == ERROR_BADMAGIC ? "invalid regex object" :
ret == ERROR_BADOPTION ? "invalid option flags" :
"unknown error $ret")
end
reinterpret(T,buf)[1]
buf[]
end

function get_ovec(match_data)
Expand Down
9 changes: 6 additions & 3 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4848,12 +4848,15 @@ end
let ni128 = sizeof(FP128test) ÷ sizeof(Int),
ns128 = sizeof(FP128align) ÷ sizeof(Int),
nbit = sizeof(Int) * 8,
arr = reinterpret(FP128align, collect(Int, 1:(2 * ns128))),
arr = Vector{FP128align}(2),
offset = Base.datatype_alignment(FP128test) ÷ sizeof(Int),
little,
expected
expected,
arrint = reinterpret(Int, arr)

@test length(arrint) == 2 * ns128
arrint .= 1:(2 * ns128)
@test sizeof(FP128test) == 16
@test length(arr) == 2
@test arr[1].i == 1
@test arr[2].i == 1 + ns128
expected = UInt128(0)
Expand Down
23 changes: 23 additions & 0 deletions test/misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -678,3 +678,26 @@ let foo() = begin
end
@test foo() == 2
end

# Endian tests
# For now, we only support little endian.
# Add an `Sys.ARCH` test for big endian when/if we add support for that.
# Do **NOT** use `ENDIAN_BOM` to figure out the endianess
# since that's exactly what we want to test.
@test ENDIAN_BOM == 0x04030201
@test ntoh(0x1) == 0x1
@test hton(0x1) == 0x1
@test ltoh(0x1) == 0x1
@test htol(0x1) == 0x1
@test ntoh(0x102) == 0x201
@test hton(0x102) == 0x201
@test ltoh(0x102) == 0x102
@test htol(0x102) == 0x102
@test ntoh(0x1020304) == 0x4030201
@test hton(0x1020304) == 0x4030201
@test ltoh(0x1020304) == 0x1020304
@test htol(0x1020304) == 0x1020304
@test ntoh(0x102030405060708) == 0x807060504030201
@test hton(0x102030405060708) == 0x807060504030201
@test ltoh(0x102030405060708) == 0x102030405060708
@test htol(0x102030405060708) == 0x102030405060708

0 comments on commit 99286f9

Please sign in to comment.