Skip to content

Commit

Permalink
Disables finalize after segfaulting error (#15)
Browse files Browse the repository at this point in the history
* Adds specialized error type and disables finalize after segfaulting error

* Simplifies disabling finalize

* Removes `mutable` from `LZ4Decompressor`
  • Loading branch information
Sam Morrison authored and omus committed Apr 2, 2018
1 parent 69c6353 commit a882f50
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 37 deletions.
9 changes: 9 additions & 0 deletions src/CodecLz4.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ else
error("CodecLz4 not properly installed. Please run Pkg.build(\"CodecLz4\") and restart julia")
end

struct LZ4Exception <: Exception
src::AbstractString
msg::AbstractString
end

function Base.showerror(io::IO, ex::LZ4Exception, bt; backtrace=false)
printstyled(io, "$(ex.src): $(ex.msg)", color=Base.error_color())
end

include("lz4frame.jl")
include("stream_compression.jl")

Expand Down
20 changes: 10 additions & 10 deletions src/lz4frame.jl
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,13 @@ end

function check_context_initialized(ctx::Ptr{LZ4F_cctx})
if ctx == Ptr{LZ4F_cctx}(C_NULL)
error("Uninitialized compression context")
throw(LZ4Exception("LZ4F_cctx", "Uninitialized compression context"))
end
end

function check_context_initialized(ctx::Ptr{LZ4F_dctx})
if ctx == Ptr{LZ4F_dctx}(C_NULL)
error("Uninitialized decompression context")
throw(LZ4Exception("LZ4F_dctx", "Uninitialized decompression context"))
end
end

Expand Down Expand Up @@ -205,7 +205,7 @@ Will throw an error if there was an error during context creation.
function LZ4F_createCompressionContext(cctxPtr::Ref{Ptr{LZ4F_cctx}}, version::UInt32)
ret = ccall((:LZ4F_createCompressionContext, liblz4), Csize_t, (Ref{Ptr{LZ4F_cctx}}, UInt32), cctxPtr, version)
if LZ4F_isError(ret)
error("LZ4F_createCompressionContext: " * LZ4F_getErrorName(ret))
throw(LZ4Exception("LZ4F_createCompressionContext", LZ4F_getErrorName(ret)))
end
ret
end
Expand All @@ -228,7 +228,7 @@ function LZ4F_compressBegin(cctx::Ptr{LZ4F_cctx}, dstBuffer, dstCapacity::Csize_
check_context_initialized(cctx)
ret = ccall((:LZ4F_compressBegin, liblz4), Csize_t, (Ptr{LZ4F_cctx}, Ptr{Cvoid}, Csize_t, Ref{LZ4F_preferences_t}), cctx, dstBuffer, dstCapacity, prefsPtr)
if LZ4F_isError(ret)
error("LZ4F_compressBegin: " * LZ4F_getErrorName(ret))
throw(LZ4Exception("LZ4F_compressBegin" ,LZ4F_getErrorName(ret)))
end
ret
end
Expand Down Expand Up @@ -259,7 +259,7 @@ function LZ4F_compressUpdate(cctx::Ptr{LZ4F_cctx}, dstBuffer, dstCapacity::Csize
check_context_initialized(cctx)
ret = ccall((:LZ4F_compressUpdate, liblz4), Csize_t, (Ptr{LZ4F_cctx}, Ptr{Cvoid}, Csize_t, Ptr{Cvoid}, Csize_t, Ptr{LZ4F_compressOptions_t}), cctx, dstBuffer, dstCapacity, srcBuffer, srcSize, cOptPtr)
if LZ4F_isError(ret)
error("LZ4F_compressUpdate: " * LZ4F_getErrorName(ret))
throw(LZ4Exception("LZ4F_compressUpdate", LZ4F_getErrorName(ret)))
end
ret
end
Expand All @@ -276,7 +276,7 @@ function LZ4F_flush(cctx::Ptr{LZ4F_cctx}, dstBuffer, dstCapacity::Csize_t, cOptP
check_context_initialized(cctx)
ret = ccall((:LZ4F_flush, liblz4), Csize_t, (Ptr{LZ4F_cctx}, Ptr{Cvoid}, Csize_t, Ptr{LZ4F_compressOptions_t}), cctx, dstBuffer, dstCapacity, cOptPtr)
if LZ4F_isError(ret)
error("LZ4F_flush: " * LZ4F_getErrorName(ret))
throw(LZ4Exception("LZ4F_flush", LZ4F_getErrorName(ret)))
end
ret
end
Expand All @@ -295,7 +295,7 @@ function LZ4F_compressEnd(cctx::Ptr{LZ4F_cctx}, dstBuffer, dstCapacity::Csize_t,
check_context_initialized(cctx)
ret = ccall((:LZ4F_compressEnd, liblz4), Csize_t, (Ptr{LZ4F_cctx}, Ptr{Cvoid}, Csize_t, Ptr{LZ4F_compressOptions_t}), cctx, dstBuffer, dstCapacity, cOptPtr)
if LZ4F_isError(ret)
error("LZ4F_compressEnd: " * LZ4F_getErrorName(ret))
throw(LZ4Exception("LZ4F_compressEnd", LZ4F_getErrorName(ret)))
end
ret
end
Expand All @@ -311,7 +311,7 @@ The `dctx` memory can be released using `LZ4F_freeDecompressionContext()`.
function LZ4F_createDecompressionContext(dctxPtr::Ref{Ptr{LZ4F_dctx}}, version::UInt32)
ret = ccall((:LZ4F_createDecompressionContext, liblz4), Csize_t, (Ref{Ptr{LZ4F_dctx}}, UInt32), dctxPtr, version)
if LZ4F_isError(ret)
error("LZ4F_createDecompressionContext: " * LZ4F_getErrorName(ret))
throw(LZ4Exception("LZ4F_createDecompressionContext", LZ4F_getErrorName(ret)))
end
ret
end
Expand Down Expand Up @@ -352,7 +352,7 @@ function LZ4F_getFrameInfo(dctx::Ptr{LZ4F_dctx}, frameInfoPtr::Ref{LZ4F_frameInf
check_context_initialized(dctx)
ret = ccall((:LZ4F_getFrameInfo, liblz4), Csize_t, (Ptr{LZ4F_dctx}, Ref{LZ4F_frameInfo_t}, Ptr{Cvoid}, Ref{Csize_t}), dctx, frameInfoPtr, srcBuffer, srcSizePtr)
if LZ4F_isError(ret)
error("LZ4F_getFrameInfo: " * LZ4F_getErrorName(ret))
throw(LZ4Exception("LZ4F_getFrameInfo", LZ4F_getErrorName(ret)))
end
ret
end
Expand Down Expand Up @@ -388,7 +388,7 @@ function LZ4F_decompress(dctx::Ptr{LZ4F_dctx}, dstBuffer, dstSizePtr::Ref{Csize_
check_context_initialized(dctx)
ret = ccall((:LZ4F_decompress, liblz4), Csize_t, (Ptr{LZ4F_dctx}, Ptr{Cvoid}, Ref{Csize_t}, Ptr{Cvoid}, Ref{Csize_t}, Ptr{LZ4F_decompressOptions_t}), dctx, dstBuffer, dstSizePtr, srcBuffer, srcSizePtr, dOptPtr)
if LZ4F_isError(ret)
error("LZ4F_decompress: " * LZ4F_getErrorName(ret))
throw(LZ4Exception("LZ4F_decompress", LZ4F_getErrorName(ret)))
end
ret
end
Expand Down
15 changes: 4 additions & 11 deletions src/stream_compression.jl
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
using TranscodingStreams
using TranscodingStreams: splitkwargs

const BUF_SIZE = 16*1024
const LZ4_FOOTER_SIZE = 4

# borrowed from CodecZlib.jl
function splitkwargs(kwargs, keys)
hits = []
others = []
for kwarg in kwargs
push!(kwarg[1] keys ? hits : others, kwarg)
end
return hits, others
end

mutable struct LZ4Compressor <: TranscodingStreams.Codec
ctx::Ref{Ptr{LZ4F_cctx}}
prefs::Ref{LZ4F_preferences_t}
Expand Down Expand Up @@ -198,6 +188,9 @@ function TranscodingStreams.process(codec::LZ4Decompressor, input::Memory, outpu
end

catch err
if isa(err, LZ4Exception) && err.msg == "ERROR_frameType_unknown"
codec.dctx[] = C_NULL
end
error[] = err
(data_read, data_written, :error)
end
Expand Down
30 changes: 15 additions & 15 deletions test/lz4frame.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ using Compat
@test !CodecLz4.LZ4F_isError(err)

ctx = Ptr{CodecLz4.LZ4F_cctx}(C_NULL)
@test_throws ErrorException CodecLz4.check_context_initialized(ctx)
@test_throws CodecLz4.LZ4Exception CodecLz4.check_context_initialized(ctx)
end


Expand All @@ -89,8 +89,8 @@ using Compat
@test err == 0

dctx = Ptr{CodecLz4.LZ4F_dctx}(C_NULL)
@test_throws ErrorException CodecLz4.check_context_initialized(dctx)
@test_throws ErrorException CodecLz4.LZ4F_resetDecompressionContext(dctx)
@test_throws CodecLz4.LZ4Exception CodecLz4.check_context_initialized(dctx)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_resetDecompressionContext(dctx)

end

Expand Down Expand Up @@ -135,12 +135,12 @@ using Compat
CodecLz4.LZ4F_createDecompressionContext(dctx, version)

buffer[1:CodecLz4.LZ4F_HEADER_SIZE_MAX] = 0x10
@test_throws ErrorException CodecLz4.LZ4F_getFrameInfo(dctx[], frameinfo, buffer, srcsize)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_getFrameInfo(dctx[], frameinfo, buffer, srcsize)

offset = srcsize[]
srcsize[] = origsize - offset

@test_throws ErrorException CodecLz4.LZ4F_decompress(dctx[], decbuffer, dstsize, pointer(buffer) + offset, srcsize, C_NULL)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_decompress(dctx[], decbuffer, dstsize, pointer(buffer) + offset, srcsize, C_NULL)

result = CodecLz4.LZ4F_freeDecompressionContext(dctx[])
@test !CodecLz4.LZ4F_isError(result)
Expand Down Expand Up @@ -189,10 +189,10 @@ using Compat
bufsize = test_size
buffer = Vector{UInt8}(uninitialized, test_size)

@test_throws ErrorException CodecLz4.LZ4F_compressBegin(ctx[], buffer, bufsize, prefs)
@test_throws ErrorException CodecLz4.LZ4F_compressUpdate(ctx[], pointer(buffer), bufsize, pointer(testIn), test_size, C_NULL)
@test_throws ErrorException CodecLz4.LZ4F_flush(ctx[], pointer(buffer), bufsize, C_NULL)
@test_throws ErrorException CodecLz4.LZ4F_compressEnd(ctx[], pointer(buffer), bufsize, C_NULL)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_compressBegin(ctx[], buffer, bufsize, prefs)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_compressUpdate(ctx[], pointer(buffer), bufsize, pointer(testIn), test_size, C_NULL)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_flush(ctx[], pointer(buffer), bufsize, C_NULL)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_compressEnd(ctx[], pointer(buffer), bufsize, C_NULL)
end

@testset "CompressInvalid" begin
Expand All @@ -207,8 +207,8 @@ using Compat
bufsize = bound + CodecLz4.LZ4F_HEADER_SIZE_MAX
buffer = Vector{UInt8}(uninitialized, ceil(Int, bound / 8))

@test_throws ErrorException CodecLz4.LZ4F_compressBegin(ctx[], buffer, UInt(2), prefs)
@test_throws ErrorException CodecLz4.LZ4F_compressUpdate(ctx[], pointer(buffer), bufsize, pointer(testIn), test_size, C_NULL)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_compressBegin(ctx[], buffer, UInt(2), prefs)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_compressUpdate(ctx[], pointer(buffer), bufsize, pointer(testIn), test_size, C_NULL)

result = CodecLz4.LZ4F_freeCompressionContext(ctx[])
@test !CodecLz4.LZ4F_isError(result)
Expand All @@ -222,8 +222,8 @@ using Compat
offset = result
@test_nowarn result = CodecLz4.LZ4F_compressUpdate(ctx[], pointer(buffer) + offset, bufsize - offset, pointer(testIn), test_size, C_NULL)

@test_throws ErrorException CodecLz4.LZ4F_flush(ctx[], pointer(buffer), UInt(2), C_NULL)
@test_throws ErrorException CodecLz4.LZ4F_compressEnd(ctx[], pointer(buffer), UInt(2), C_NULL)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_flush(ctx[], pointer(buffer), UInt(2), C_NULL)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_compressEnd(ctx[], pointer(buffer), UInt(2), C_NULL)

result = CodecLz4.LZ4F_freeCompressionContext(ctx[])
@test !CodecLz4.LZ4F_isError(result)
Expand All @@ -236,8 +236,8 @@ using Compat
decbuffer = Vector{UInt8}(uninitialized, 1280)

frameinfo = Ref(CodecLz4.LZ4F_frameInfo_t())
@test_throws ErrorException CodecLz4.LZ4F_getFrameInfo(dctx[], frameinfo, pointer(testIn), srcsize)
@test_throws ErrorException CodecLz4.LZ4F_decompress(dctx[], decbuffer, dstsize, pointer(testIn), srcsize, C_NULL)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_getFrameInfo(dctx[], frameinfo, pointer(testIn), srcsize)
@test_throws CodecLz4.LZ4Exception CodecLz4.LZ4F_decompress(dctx[], decbuffer, dstsize, pointer(testIn), srcsize, C_NULL)
end

@testset "Preferences" begin
Expand Down
8 changes: 7 additions & 1 deletion test/stream_compression.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ end
corrupted[1] = 0x00
file = IOBuffer(corrupted)
stream = LZ4DecompressorStream(file)
@test_throws ErrorException read(stream)
@test_throws CodecLz4.LZ4Exception read(stream)
@test_throws ArgumentError read(stream)

output = Memory(Vector{UInt8}(uninitialized, 1))
Expand All @@ -75,6 +75,12 @@ end
err = Error()
@test TranscodingStreams.process(compressor, input, output, err) == (0, 0, :error)
@test err[].msg == "Output buffer too small for header."
@test_nowarn TranscodingStreams.finalize(compressor)

codec = LZ4Decompressor()
@test_throws CodecLz4.LZ4Exception transcode(codec, "not properly formatted")
@test_nowarn TranscodingStreams.finalize(codec)

end

@testset "keywords" begin
Expand Down

0 comments on commit a882f50

Please sign in to comment.