Skip to content

Commit

Permalink
Guard against StackoverflowErrors: prevent packages from extending Fi…
Browse files Browse the repository at this point in the history
…leIO.load or FileIO.save
  • Loading branch information
timholy committed Sep 21, 2017
1 parent 5a68c11 commit ab8c940
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/loadsave.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ function load{F}(q::Formatted{F}, args...; options...)
if !has_method_from(methods(Library.load), Library)
throw(LoaderError(string(library), "load not defined"))
end
if Library.load == FileIO.load
throw(LoaderError(string(library), "module should not extend FileIO.load"))
end
return eval(Main, :($(Library.load)($q, $args...; $options...)))
catch e
push!(failures, (e, q))
Expand All @@ -112,6 +115,9 @@ function save{F}(q::Formatted{F}, data...; options...)
if !has_method_from(methods(Library.save), Library)
throw(WriterError(string(library), "save not defined"))
end
if Library.save == FileIO.save
throw(WriterError(string(library), "module should not extend FileIO.save"))
end
return eval(Main, :($(Library.save)($q, $data...; $options...)))
catch e
push!(failures, (e, q))
Expand Down
43 changes: 43 additions & 0 deletions test/loadsave.jl
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,46 @@ end
@testset "Absent file" begin
@test_throws SystemError load("nonexistent.oops")
end

# Stack overflows (issue #141)
module IOrecursion1
using FileIO
# One shouldn't extend FileIO.load, but what happens if someone does anyway?
FileIO.load(file::File{format"IOrecursion1"}) = 1
end

module IOrecursion2
using FileIO
# One shouldn't extend FileIO.load, but what happens if someone does anyway?
FileIO.load(file::Stream{format"IOrecursion2"}) = 2
end

module IOrecursion3
using FileIO
# One shouldn't extend FileIO.load, but what happens if someone does anyway?
FileIO.load(file::File{format"IOrecursion3"}) = 3
FileIO.load(file::Stream{format"IOrecursion3"}) = 3
end

sym2loader = copy(FileIO.sym2loader)
sym2saver = copy(FileIO.sym2saver)
try
empty!(FileIO.sym2loader)
empty!(FileIO.sym2saver)
add_loader(format"IOrecursion1", :IOrecursion1)
add_loader(format"IOrecursion2", :IOrecursion2)
add_loader(format"IOrecursion3", :IOrecursion3)

@testset "Stackoverflow" begin
io = IOBuffer()
@test load(File(format"IOrecursion1", @__FILE__)) == 1
@test_throws FileIO.LoaderError load(Stream(format"IOrecursion1", io))
@test_throws FileIO.LoaderError load(File(format"IOrecursion2", @__FILE__))
@test load(Stream(format"IOrecursion2", io)) == 2
@test load(File(format"IOrecursion3", @__FILE__)) == 3
@test load(Stream(format"IOrecursion3", io)) == 3
end
finally
merge!(FileIO.sym2loader, sym2loader)
merge!(FileIO.sym2saver, sym2saver)
end

0 comments on commit ab8c940

Please sign in to comment.