From 579d38bfd0a3c9fd3a62a9d18560685110161cf8 Mon Sep 17 00:00:00 2001 From: Lode Date: Sun, 17 Sep 2017 12:22:58 +0200 Subject: fix encoder memory leak for some input error cases --- lodepng.cpp | 66 ++++++++++++++++++++++++++------------------------- lodepng.h | 7 +++--- lodepng_benchmark.cpp | 8 +++---- lodepng_unittest.cpp | 63 +++++++++++++++++++++++++++++++++++++----------- 4 files changed, 91 insertions(+), 53 deletions(-) diff --git a/lodepng.cpp b/lodepng.cpp index bf237df..ad6ed24 100644 --- a/lodepng.cpp +++ b/lodepng.cpp @@ -1,7 +1,7 @@ /* -LodePNG version 20161127 +LodePNG version 20170917 -Copyright (c) 2005-2016 Lode Vandevenne +Copyright (c) 2005-2017 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -39,7 +39,7 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for #pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ #endif /*_MSC_VER */ -const char* LODEPNG_VERSION_STRING = "20161127"; +const char* LODEPNG_VERSION_STRING = "20170917"; /* This source file is built up in the following large parts. The code sections @@ -3463,6 +3463,7 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, size_t i; ColorTree tree; size_t numpixels = w * h; + unsigned error = 0; if(lodepng_color_mode_equal(mode_out, mode_in)) { @@ -3516,7 +3517,8 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, for(i = 0; i != numpixels; ++i) { getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); - CERROR_TRY_RETURN(rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a)); + error = rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a); + if (error) break; } } @@ -3525,7 +3527,7 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, color_tree_cleanup(&tree); } - return 0; /*no error*/ + return error; } #ifdef LODEPNG_COMPILE_ENCODER @@ -5651,22 +5653,12 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, *outsize = 0; state->error = 0; - lodepng_info_init(&info); - lodepng_info_copy(&info, &state->info_png); - - if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette) - && (info.color.palettesize == 0 || info.color.palettesize > 256)) + /*check input values validity*/ + if((state->info_png.color.colortype == LCT_PALETTE || state->encoder.force_palette) + && (state->info_png.color.palettesize == 0 || state->info_png.color.palettesize > 256)) { - state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ - return state->error; + CERROR_RETURN_ERROR(state->error, 68); /*invalid palette size, it is only allowed to be 1-256*/ } - - if(state->encoder.auto_convert) - { - state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw); - } - if(state->error) return state->error; - if(state->encoder.zlibsettings.btype > 2) { CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/ @@ -5675,28 +5667,38 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, { CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/ } - - state->error = checkColorValidity(info.color.colortype, info.color.bitdepth); + state->error = checkColorValidity(state->info_png.color.colortype, state->info_png.color.bitdepth); if(state->error) return state->error; /*error: unexisting color type given*/ state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); if(state->error) return state->error; /*error: unexisting color type given*/ - if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) + /* color convert and compute scanline filter types */ + lodepng_info_init(&info); + lodepng_info_copy(&info, &state->info_png); + if(state->encoder.auto_convert) { - unsigned char* converted; - size_t size = (w * h * (size_t)lodepng_get_bpp(&info.color) + 7) / 8; - - converted = (unsigned char*)lodepng_malloc(size); - if(!converted && size) state->error = 83; /*alloc fail*/ - if(!state->error) + state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw); + } + if (!state->error) + { + if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) { - state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); + unsigned char* converted; + size_t size = (w * h * (size_t)lodepng_get_bpp(&info.color) + 7) / 8; + + converted = (unsigned char*)lodepng_malloc(size); + if(!converted && size) state->error = 83; /*alloc fail*/ + if(!state->error) + { + state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); + } + if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); + lodepng_free(converted); } - if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); - lodepng_free(converted); + else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); } - else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); + /* output all PNG chunks */ ucvector_init(&outv); while(!state->error) /*while only executed once, to break on error*/ { diff --git a/lodepng.h b/lodepng.h index 8c634d2..d633bfa 100644 --- a/lodepng.h +++ b/lodepng.h @@ -1,7 +1,7 @@ /* -LodePNG version 20161127 +LodePNG version 20170917 -Copyright (c) 2005-2016 Lode Vandevenne +Copyright (c) 2005-2017 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -1608,6 +1608,7 @@ yyyymmdd. Some changes aren't backwards compatible. Those are indicated with a (!) symbol. +*) 17 sep 2017: fix memory leak for some encoder input error cases *) 27 nov 2016: grey+alpha auto color model detection bugfix *) 18 apr 2016: Changed qsort to custom stable sort (for platforms w/o qsort). *) 09 apr 2016: Fixed colorkey usage detection, and better file loading (within @@ -1757,5 +1758,5 @@ Domain: gmail dot com. Account: lode dot vandevenne. -Copyright (c) 2005-2016 Lode Vandevenne +Copyright (c) 2005-2017 Lode Vandevenne */ diff --git a/lodepng_benchmark.cpp b/lodepng_benchmark.cpp index 791ced0..66de123 100644 --- a/lodepng_benchmark.cpp +++ b/lodepng_benchmark.cpp @@ -499,10 +499,10 @@ int main(int argc, char *argv[]) } } - std::cout << "Total decoding time: " << total_dec_time/NUM_DECODE << "s" << std::endl; - std::cout << "Total encoding time: " << total_enc_time << "s" << std::endl; - std::cout << "Total input size : " << total_in_size << std::endl; - std::cout << "Total encoded size: " << total_enc_size << std::endl; + std::cout << "Total decoding time: " << total_dec_time/NUM_DECODE << "s (" << ((total_in_size/1024.0/1024.0)/(total_dec_time/NUM_DECODE)) << " MB/s)" << std::endl; + std::cout << "Total encoding time: " << total_enc_time << "s (" << ((total_in_size/1024.0/1024.0)/(total_enc_time)) << " MB/s)" << std::endl; + std::cout << "Total uncompressed size : " << total_in_size << std::endl; + std::cout << "Total encoded size: " << total_enc_size << " (" << (100.0 * total_enc_size / total_in_size) << "%)" << std::endl; if(verbose) std::cout << "benchmark done" << std::endl; } diff --git a/lodepng_unittest.cpp b/lodepng_unittest.cpp index 5297a35..5fb9c60 100644 --- a/lodepng_unittest.cpp +++ b/lodepng_unittest.cpp @@ -28,6 +28,8 @@ freely, subject to the following restrictions: /* Testing instructions: +*) Ensure no tests commented out below + *) Compile with g++ with all warnings and run the unit test g++ lodepng.cpp lodepng_util.cpp lodepng_unittest.cpp -Wall -Wextra -Wshadow -pedantic -ansi -O3 && ./a.out @@ -1712,26 +1714,59 @@ void testPredefinedFilters() { for(size_t i = 0; i < h; i++) ASSERT_EQUALS(3, outfilters[i]); } -void testWrongWindowSizeGivesError() { +void testEncoderErrors() { + std::cout << "testEncoderErrors" << std::endl; + std::vector png; unsigned w = 32, h = 32; Image image; generateTestImage(image, w, h); - unsigned error = 0; + + lodepng::State def; lodepng::State state; + + ASSERT_EQUALS(0, lodepng::encode(png, &image.data[0], w, h, state)); + + // test window sizes state.encoder.zlibsettings.windowsize = 0; - error = lodepng::encode(png, &image.data[0], w, h, state); - ASSERT_EQUALS(60, error); + ASSERT_EQUALS(60, lodepng::encode(png, &image.data[0], w, h, state)); state.encoder.zlibsettings.windowsize = 65536; - error = lodepng::encode(png, &image.data[0], w, h, state); - ASSERT_EQUALS(60, error); + ASSERT_EQUALS(60, lodepng::encode(png, &image.data[0], w, h, state)); state.encoder.zlibsettings.windowsize = 1000; // not power of two - error = lodepng::encode(png, &image.data[0], w, h, state); - ASSERT_EQUALS(90, error); + ASSERT_EQUALS(90, lodepng::encode(png, &image.data[0], w, h, state)); state.encoder.zlibsettings.windowsize = 256; - error = lodepng::encode(png, &image.data[0], w, h, state); - ASSERT_EQUALS(0, error); + ASSERT_EQUALS(0, lodepng::encode(png, &image.data[0], w, h, state)); + + state = def; + state.info_png.color.bitdepth = 3; + ASSERT_EQUALS(37, lodepng::encode(png, &image.data[0], w, h, state)); + + state = def; + state.info_png.color.colortype = (LodePNGColorType)5; + ASSERT_EQUALS(31, lodepng::encode(png, &image.data[0], w, h, state)); + + state = def; + state.info_png.color.colortype = LCT_PALETTE; + ASSERT_EQUALS(68, lodepng::encode(png, &image.data[0], w, h, state)); + + state = def; + state.info_png.interlace_method = 0; + ASSERT_EQUALS(0, lodepng::encode(png, &image.data[0], w, h, state)); + state.info_png.interlace_method = 1; + ASSERT_EQUALS(0, lodepng::encode(png, &image.data[0], w, h, state)); + state.info_png.interlace_method = 2; + ASSERT_EQUALS(71, lodepng::encode(png, &image.data[0], w, h, state)); + + state = def; + state.encoder.zlibsettings.btype = 0; + ASSERT_EQUALS(0, lodepng::encode(png, &image.data[0], w, h, state)); + state.encoder.zlibsettings.btype = 1; + ASSERT_EQUALS(0, lodepng::encode(png, &image.data[0], w, h, state)); + state.encoder.zlibsettings.btype = 2; + ASSERT_EQUALS(0, lodepng::encode(png, &image.data[0], w, h, state)); + state.encoder.zlibsettings.btype = 3; + ASSERT_EQUALS(61, lodepng::encode(png, &image.data[0], w, h, state)); } void addColor(std::vector& colors, unsigned char r, unsigned char g, unsigned char b, unsigned char a) @@ -1996,26 +2031,26 @@ void testPaletteToPaletteDecode2() { lodepng_palette_add(&state.info_raw, 3, 3, 3, 255); unsigned char* image2 = 0; unsigned error2 = lodepng_decode(&image2, &width, &height, &state, &png[0], png.size()); - ASSERT_EQUALS(82, error2); lodepng_state_cleanup(&state); + ASSERT_EQUALS(82, error2); free(image2); } void doMain() { //PNG - testPNGCodec(); + testPNGCodec(); // this one is slow for valgrind testPngSuiteTiny(); testPaletteFilterTypesZero(); testComplexPNG(); testPredefinedFilters(); testFuzzing(); - testWrongWindowSizeGivesError(); + testEncoderErrors(); testPaletteToPaletteDecode(); testPaletteToPaletteDecode2(); //Colors - testFewColors(); + testFewColors(); // this one is slow for valgrind testColorKeyConvert(); testColorConvert(); testColorConvert2(); -- cgit v1.2.3