IntSet crashes Julia 0.6.1

Dearests,

The following

julia> N=2^10; a= rand(UInt64,N);  sa=IntSet(a); #gives an error ... which is fine
ERROR: InexactError()
....
julia> a= rand(UInt32,N);  sa=IntSet(a); #now the system crashes
signal (11): Segmentation fault: 11
...

Note that the segfault occurs (systematically) only after the the first error is produced. Indeed, the help on IntSet constructor says

  [...] Only Ints greater than 0 can be stored. If the set
  will be sparse (for example holding a few very large integers), use Set
  instead.

and perhaps it is not a bug. However, let me know it you think it’s worth reporting upstream

I’m on

Version 0.6.1 (2017-10-24 22:15 UTC)
x86_64-apple-darwin15.6.0

Cheers

Andrea

I get various errors, but never manage to crash Julia (v0.6.1, on Linux). These are typical:

julia> N=2^10; a= rand(UInt64,N);  sa=IntSet(a);
ERROR: OutOfMemoryError()
Stacktrace:
 [1] resize!(::BitArray{1}, ::UInt64) at ./bitarray.jl:836
 [2] _resize0!(::BitArray{1}, ::UInt64) at ./intset.jl:35
 [3] _setint! at ./intset.jl:25 [inlined]
 [4] push! at ./intset.jl:69 [inlined]
 [5] union!(::IntSet, ::Array{UInt64,1}) at ./intset.jl:95
 [6] IntSet(::Array{UInt64,1}) at ./intset.jl:7

julia> N=2^10; a= rand(UInt64,N);  sa=IntSet(a);
ERROR: InexactError()
Stacktrace:
 [1] resize!(::BitArray{1}, ::UInt64) at ./bitarray.jl:834
 [2] _resize0!(::BitArray{1}, ::UInt64) at ./intset.jl:35
 [3] _setint! at ./intset.jl:25 [inlined]
 [4] push! at ./intset.jl:69 [inlined]
 [5] union!(::IntSet, ::Array{UInt64,1}) at ./intset.jl:95
 [6] IntSet(::Array{UInt64,1}) at ./intset.jl:7

julia> N=2^10; a= rand(UInt64,N);  sa=IntSet(a);
ERROR: ArgumentError: elements of IntSet must be between 1 and typemax(Int)
Stacktrace:
 [1] _throw_intset_bounds_err() at ./intset.jl:64
 [2] push! at ./intset.jl:68 [inlined]
 [3] union!(::IntSet, ::Array{UInt64,1}) at ./intset.jl:95
 [4] IntSet(::Array{UInt64,1}) at ./intset.jl:7

Perhaps to make the error reproducible you could include a random seed.

Same as @Tamas_Papp, I get the correct errors (oxy moron?), but Julia doesn’t crash. This on x86_64 Linux.

In the past I’ve noticed that segfaults can pop up at very unexpected times in Julia; is it possible you ran some other code prior to this that was the real cause?

The second time shoul be run with UInt32 as in my example … an yes it is in a fresh session.

Yes, there’s likely something fishy going on here with UInt32 arithmetic in the internals of the IntSet.

julia> IntSet(UInt32(2^32-1))
IntSet([])

julia> IntSet((2^32-1))
IntSet([4294967295])

Edit: caught it:

julia> Base._setint!(IntSet(), UInt32(2^32-10), true)

signal (11): Segmentation fault: 11
while loading no file, in expression starting on line 0
unsafe_bitsetindex! at ./bitarray.jl:675 [inlined]
setindex! at ./bitarray.jl:682 [inlined]
_setindex! at ./abstractarray.jl:979 [inlined]
setindex! at ./abstractarray.jl:967 [inlined]
_setint! at ./intset.jl:27

Note that those stack traces are actually very helpful!

And with --check-bounds=yes:

julia> Base.push!(IntSet(), UInt32(2^32-10), true)
ERROR: BoundsError: attempt to access 2147483633-element BitArray{1} at index [4294967286]
Stacktrace:
 [1] throw_boundserror(::BitArray{1}, ::Tuple{Int64}) at ./abstractarray.jl:433
 [2] checkbounds at ./abstractarray.jl:362 [inlined]
 [3] setindex! at ./bitarray.jl:681 [inlined]
 [4] _setindex! at ./abstractarray.jl:979 [inlined]
 [5] setindex! at ./abstractarray.jl:967 [inlined]
 [6] _setint! at ./intset.jl:27 [inlined]
 [7] push!(::IntSet, ::UInt32) at ./intset.jl:69
 [8] push!(::IntSet, ::UInt32, ::Bool) at ./intset.jl:71

I’m confused

julia> IntSet(UInt32(2^32-1))
ERROR: ReadOnlyMemoryError()
Stacktrace:
 [1] unsafe_bitsetindex! at ./bitarray.jl:675 [inlined]
 [2] setindex! at ./bitarray.jl:682 [inlined]
 [3] _setindex! at ./abstractarray.jl:980 [inlined]
 [4] setindex! at ./abstractarray.jl:968 [inlined]
 [5] _setint! at ./intset.jl:27 [inlined]
 [6] push! at ./intset.jl:69 [inlined]
 [7] union!(::IntSet, ::UInt32) at ./intset.jl:95
 [8] IntSet(::UInt32) at ./intset.jl:7

julia> IntSet((2^32-1))
IntSet([4294967295])

julia> Base._setint!(IntSet(), UInt32(2^32-10), true)
IntSet([])

IntSet isn’t allocating enough space for the large UInt32 because it’s overflowing when it tries to compute how much space is required. So then it ends up writing out of bounds inside an @inbounds block. The behavior you see will vary depending upon where that out-of-bounds write lands: It could be in a read-only memory area, or it could silently corrupt something else, or it could crash.

https://github.com/JuliaLang/julia/pull/24365

4 Likes

Wow … quite a lot of activity on this! @mbauman, thanks a lot for detecting and solving the problem

A