Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed a crash when reading PNG files with an invalid header. #385

merged 1 commit into from Aug 26, 2019


Copy link

macmade commented Aug 26, 2019


Use of BOOST_ASSERT in png_ptr_read_deleter and png_ptr_write_deleter in ‎⁨include/boost/gil/extension/⁨io/png/⁨detail⁩/reader_backend.hpp will produce a crash with PNG files with an invalid header.

In such a case (bad PNG file), we expect a std::ios_base::failure exception (see below).
Unfortunately, the assertions will prevent the exception to be caught by terminating the program.

This hotfix replaces the assertions with conditional checks, so we can get the expected exception handling.

Steps to reproduce

  1. Create a text file with at least 4 characters (like ABCD).
  2. Try to read the file as PNG:
using backend_t   = typename boost::gil::get_reader_backend< std::string, boost::gil::png_tag >::type;
backend_t backend = boost::gil::read_image_info( "path/to/invalid/png", boost::gil::png_tag() );


A reader_backend object is created: ‎⁨include/boost/gil/extension/⁨io/png/⁨detail⁩/reader_backend.hpp.

The base class' constructor (png_struct_info_wrapper) has a std::shared_ptr member for the png_ptr_wrapper.
The shared pointer is created with a custom deleter (png_ptr_read_deleter and png_ptr_write_deleter).

So inside the backend constructor, the png_ptr_wrapper is non-null.
Then, still from the constructor, the PNG header is read by calling read_header.

    io_error_if( png_sig_cmp( png_bytep(buf)
                            , png_size_t(0)
                            , PNG_BYTES_TO_CHECK
                            ) != 0
               , "png_check_validity: invalid png image"

So for an invalid header, io_error_if will throw an exception.
This is the expected behavior.

But as the exception is thrown, the backend object gets deallocated.
So is the std::shared_ptr. And as the deleter is called:

static void png_ptr_read_deleter( png_ptr_wrapper* png_ptr )
    if( png_ptr )
        BOOST_ASSERT(png_ptr->_struct && png_ptr->_info);

png_ptr is valid, but all fields will be null, as we haven't read the PNG file yet.
Assertion will fail, making the program crash, and thus preventing the expected exception to be caught.



  • Ensure all CI builds pass
  • Review and approve
Removed assertions, as they prevent the expected std::ios_base::failure exception to be caught in such a case.

This comment has been minimized.

Copy link

mloskot commented Aug 26, 2019


Assertion will fail, making the program crash

It should have also stated "only if compiled with -DNDEBUG", no?

Thanks for the report

@mloskot mloskot added this to the Boost 1.72+ milestone Aug 26, 2019
Copy link

mloskot left a comment

LGTM. Thanks for the fix.

@mloskot mloskot merged commit bd00f91 into boostorg:develop Aug 26, 2019
9 checks passed
9 checks passed
boostorg.gil Build #20190826.1 succeeded
boostorg.gil (macos1013_xcode91_cmake) macos1013_xcode91_cmake succeeded
boostorg.gil (ubuntu1604_gcc5_cxx11_cmake) ubuntu1604_gcc5_cxx11_cmake succeeded
boostorg.gil (ubuntu1604_gcc8_cxx14_cmake) ubuntu1604_gcc8_cxx14_cmake succeeded
boostorg.gil (win2012_vs2015_cmake) win2012_vs2015_cmake succeeded
boostorg.gil (win2016_vs2017_cxx14_cmake) win2016_vs2017_cxx14_cmake succeeded
boostorg.gil (win2016_vs2017_cxx17_cmake) win2016_vs2017_cxx17_cmake succeeded
continuous-integration/appveyor/pr AppVeyor build succeeded
continuous-integration/travis-ci/pr The Travis CI build passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
2 participants
You can’t perform that action at this time.