diff --git a/Cargo.toml b/Cargo.toml index 6ab163f1..51310817 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ lto=true [dependencies] "alloc-no-stdlib" = {version="2.0"} -"brotli-decompressor" = {version="> 2.0.1, < 2.1.0"} +"brotli-decompressor" = {version="> 2.0.2, < 2.1.0"} "alloc-stdlib" = {version="~0.2", optional=true} "packed_simd" = {version="0.3", optional=true} "sha2" = {version="~0.8", optional=true} diff --git a/c/Cargo.toml b/c/Cargo.toml index 761e4c0b..16d00def 100644 --- a/c/Cargo.toml +++ b/c/Cargo.toml @@ -20,7 +20,7 @@ lto=true [dependencies] "alloc-no-stdlib" = {version="2.0"} -"brotli-decompressor" = {version="~2.0"} +"brotli-decompressor" = {version="> 2.0.2, < 2.1.0"} "alloc-stdlib" = {version="~0.2", optional=true} "packed_simd" = {version="0.3", optional=true} "sha2" = {version="~0.8", optional=true} diff --git a/c/Makefile b/c/Makefile index af0f322b..1bf316a6 100644 --- a/c/Makefile +++ b/c/Makefile @@ -1,4 +1,4 @@ -multiexample: multiexample_d decompressor multiexample.c vec_u8.h arg.h custom_alloc.h +multiexample: multiexample_d decompressor multiexample.c vec_u8.h arg.h custom_alloc.h fuzz fuzz_d gcc -O3 -o multiexample -g multiexample.c -I. target/release/libbrotli.[ds][lyo]* multiexample_d: decompressor multiexample.c vec_u8.h arg.h custom_alloc.h gcc -o multiexample_d -g multiexample.c -I. target/debug/libbrotli.[ds][lyo]* @@ -6,6 +6,10 @@ decompressor: decompressor_d decompressor.c target/release/libbrotli.so catbrotl gcc -O3 -o decompressor -g decompressor.c -I. target/release/libbrotli.[ds][lyo]* decompressor_d: decompressor.c target/debug/libbrotli.so brotli_tool catbrotli_d cargo build && gcc -o decompressor_d -g decompressor.c -I. target/debug/libbrotli.[ds][lyo]* +fuzz: fuzz_d fuzz.c target/release/libbrotli.so catbrotli + gcc -O3 -o fuzz -g fuzz.c -I. target/release/libbrotli.[ds][lyo]* +fuzz_d: fuzz.c target/debug/libbrotli.so brotli_tool catbrotli_d + cargo build && gcc -o fuzz_d -g fuzz.c -I. target/debug/libbrotli.[ds][lyo]* brotli_tool: brotli_tool_d decompressor.c target/release/libbrotli.so gcc -O3 -o brotli_tool -g brotli.c -I. target/release/libbrotli.[ds][lyo]* diff --git a/c/brotli/decode.h b/c/brotli/decode.h index 0f5c8f9d..9305276c 100644 --- a/c/brotli/decode.h +++ b/c/brotli/decode.h @@ -325,6 +325,20 @@ BROTLI_DEC_API BROTLI_BOOL BrotliDecoderIsFinished( BROTLI_DEC_API BrotliDecoderErrorCode BrotliDecoderGetErrorCode( const BrotliDecoderState* state); +/** + * Acquires a detailed error code. + * + * Should be used only after ::BrotliDecoderDecompressStream returns + * ::BROTLI_DECODER_RESULT_ERROR. + * + * See also ::BrotliDecoderGetErrorString + * + * @param state decoder instance + * @returns last saved error code as a string, or panic information + */ +BROTLI_DEC_API const char* BrotliDecoderGetErrorString( + const BrotliDecoderState* state); + /** * Converts error code to a c-string. */ diff --git a/c/fuzz.c b/c/fuzz.c new file mode 100644 index 00000000..1fa07c78 --- /dev/null +++ b/c/fuzz.c @@ -0,0 +1,60 @@ +#include "brotli/decode.h" +#include +#include +#include +#include +int custom_alloc_data = 0; +void * custom_alloc(void*opaque, size_t size) { + assert(opaque == &custom_alloc_data); + return malloc(size); +} +void custom_free(void*opaque, void* addr) { + assert(opaque == &custom_alloc_data); + free(addr); +} + +int main(int argc, char **argv) { + FILE * fp = argc > 1 ? fopen(argv[1], "rb") : stdin; + BrotliDecoderState * state = BrotliDecoderCreateInstance(custom_alloc, custom_free, &custom_alloc_data); + unsigned char ibuffer[4096]; + unsigned char obuffer[4096]; + size_t total_out = 0; + BrotliDecoderResult rest; + while(1) { + size_t avail_in = fread(ibuffer, 1, sizeof(ibuffer), fp); + int is_eof = (avail_in == 0); + const unsigned char *i_ptr = &ibuffer[0]; + while (1) { + unsigned char *o_ptr = &obuffer[0]; + size_t avail_out = sizeof(obuffer); + rest = BrotliDecoderDecompressStream(state, &avail_in, &i_ptr, &avail_out, &o_ptr, &total_out); + if (o_ptr != &obuffer[0]) { + // don't actually write + } + if (rest == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) { + break; + } + if (rest == BROTLI_DECODER_RESULT_SUCCESS || rest == BROTLI_DECODER_RESULT_ERROR) { + break; + } + } + if (rest == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT && is_eof) { + fprintf(stderr, "Unexpected EOF\n"); + break; + } + if (rest == BROTLI_DECODER_RESULT_SUCCESS) { + break; + } + if (rest == BROTLI_DECODER_RESULT_ERROR) { + fprintf(stderr, "Error: %s\n", BrotliDecoderGetErrorString(state)); + if (BrotliDecoderGetErrorCode(state) == BROTLI_DECODER_ERROR_UNREACHABLE) { + abort(); // possibly a stack trace + } + break; + } + } + BrotliDecoderDestroyInstance(state); + if (rest == BROTLI_DECODER_RESULT_ERROR) { + fprintf(stderr, "Not a valid brotli file\n"); + } +} diff --git a/research/concatenate_some.py b/research/concatenate_some.py index cfc8638d..1c3838ca 100644 --- a/research/concatenate_some.py +++ b/research/concatenate_some.py @@ -42,7 +42,7 @@ def process(work, brotli, cat, prefix): quality = "-q" + str(insecure_random.randrange(2,12 if len(work) < 8 else 10)) if insecure_random.randrange(0,16) == 0: quality = '-q9.5' - append = insecure_random.randrange(0,8) == 0 + append = insecure_random.randrange(0,2) == 0 frivolous_procs = [] procs = [] print 'processing',work,'at',quality,append diff --git a/src/ffi/decompressor.rs b/src/ffi/decompressor.rs index 37768bc3..dad0b9e1 100644 --- a/src/ffi/decompressor.rs +++ b/src/ffi/decompressor.rs @@ -98,3 +98,7 @@ pub unsafe extern fn CBrotliDecoderIsFinished(state_ptr: *const ffi::BrotliDecod pub unsafe extern fn CBrotliDecoderGetErrorCode(state_ptr: *const ffi::BrotliDecoderState) -> ffi::BrotliDecoderErrorCode { ffi::BrotliDecoderGetErrorCode(state_ptr) } +#[no_mangle] +pub unsafe extern fn CBrotliDecoderGetErrorString(state_ptr: *const ffi::BrotliDecoderState) -> *const u8 { + ffi::BrotliDecoderGetErrorString(state_ptr) +}