Search code examples
c++visual-c++unhandled-exceptionlibpng

Unhandled exception at 0x77662D37 (ntdll.dll) when reading png image with dimensions greater than 200x200 px


I'm using libpng to read png files in Visual C++. The program works fine when reading image with dimensions 195x195px or less but crashes for higher dimensions.

This is the error message:

First-chance exception at 0x77662D37 (ntdll.dll) in myprog.exe: 0xC0000005: Access violation reading location 0xB4BFDDFF. Unhandled exception at 0x77662D37 (ntdll.dll) in myprog.exe: 0xC0000005: Access violation reading location 0xB4BFDDFF.

and here this the code:

bool PngImage::load(void)
{
    png_structp pngPtr(NULL);
    png_infop infoPtr(NULL);
    FILE* fp(NULL);

    png_uint_32 w = 0, h = 0;
    int bit_depth, color_type, interlace_type;

    fp = fopen(fileName_.c_str(), "rb");
    if (!fp)
        return false;

    pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!pngPtr)
    {
        fclose(fp);
        return false;
    }

    infoPtr = png_create_info_struct(pngPtr);
    if (!infoPtr)
    {
        fclose(fp);
        png_destroy_read_struct(&pngPtr, png_infopp_NULL, png_infopp_NULL);
        return false;
    }

    if (setjmp(png_jmpbuf(pngPtr)))
    {
        png_destroy_read_struct(&pngPtr, &infoPtr, png_infopp_NULL);
        fclose(fp);
        return false;
    }

    png_init_io(pngPtr, fp);

    if (setjmp(png_jmpbuf(pngPtr)))
    {
        png_destroy_read_struct(&pngPtr, &infoPtr, png_infopp_NULL);
        fclose(fp);
        return false;
    }

    png_read_info(pngPtr, infoPtr);

    png_get_IHDR(pngPtr, infoPtr, &w, &h,
        &bit_depth, &color_type, &interlace_type,
        int_p_NULL, int_p_NULL);

    if (setjmp(png_jmpbuf(pngPtr)))
    {
        png_destroy_read_struct(&pngPtr, &infoPtr, png_infopp_NULL);
        fclose(fp);
        return false;
    }

    width_ = static_cast<size_t>(w);
    height_ = static_cast<size_t>(h);

    data_ = new png_bytep[height_];
    for (size_t i = 0; i < height_; ++i)
        data_[i] = new png_byte[width_ * BYTE_PER_PIXEL];

    png_read_image(pngPtr, data_);

    if (setjmp(png_jmpbuf(pngPtr)))
    {
        png_destroy_read_struct(&pngPtr, &infoPtr, png_infopp_NULL);
        fclose(fp);
        for (size_t i = 0; i < height_; ++i)
            delete[] data_[i];
        delete[] data_;
        data_ = NULL;
        width_ = height_ = 0;
        return false;
    }

    png_read_end(pngPtr, infoPtr);

    png_destroy_read_struct(&pngPtr, &infoPtr, png_infopp_NULL);

    fclose(fp);

    return true;
}

value of the constants:

const size_t BYTE_PER_PIXEL = 3;
const size_t RED_OFFSET = 0;
const size_t GREEN_OFFSET = 1;
const size_t BLUE_OFFSET = 2;
const png_byte BIT_DEPTH = 8;

The code seem to stop at png_destroy_read_struct(&pngPtr, &infoPtr, png_infopp_NULL); before fclose(fp).

What could be the reason why I am getting an Unhandled exception? Hope you can help with this. Thank you in advance.

PS: I am not that familiar with libpng


Solution

  • Hypothesis: This code assumes that every image is in 24-bit/pixel RGB format.

    If you read a 32-bit/pixel RGBA image or a 48-bit/pixel RGB image, then the allocation

    data_[i] = new png_byte[width_ * BYTE_PER_PIXEL];

    will not allocate enough bytes for each scan line.

    C++ being the unsafe language that it is, the buffer overrun when reading into these too-short arrays will trash the heap data structures, which may not trigger a symptom until you try to free something.

    Also, it looks like this code forgets to free the arrays in the successful case, or is data_ an instance variable intended to hold the image in memory?