libpng crashes on png_read_info()

匿名 (未验证) 提交于 2019-12-03 00:57:01

问题:

I'm trying to read a png file using libpng 1.2.10 in vs2013. I downloaded the latest zlib and compiled pnglib, which worked fine. Now I'm trying to load a file:

int *w = &width; int *h = &height; const char* name = file.c_str(); FILE *png_file = fopen(name, "rb"); if (!png_file) {     std::cerr << "Could not open " + file << std::endl;     return; }  unsigned char header[PNG_SIG_BYTES];  fread(header, 1, PNG_SIG_BYTES, png_file); if (png_sig_cmp(header, 0, PNG_SIG_BYTES)) {     std::cerr << "PNG signature fail " + file << std::endl;     return; }  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(png_ptr == NULL) {     std::cerr << "PNG read fail " + file << std::endl;     return; } png_infop info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) {     std::cerr << "PNG info fail " + file << std::endl;     return; } png_infop end_info = png_create_info_struct(png_ptr); if(!end_info) {     std::cerr << "PNG info end fail " + file << std::endl;     return; } if (setjmp(png_jmpbuf(png_ptr))) {     std::cerr << "PNG setjmp fail " + file << std::endl;     return; } png_init_io(png_ptr, png_file); png_set_sig_bytes(png_ptr, PNG_SIG_BYTES); png_read_info(png_ptr, info_ptr);  *w = png_get_image_width(png_ptr, info_ptr); *h = png_get_image_height(png_ptr, info_ptr);  png_uint_32 bit_depth, color_type; bit_depth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr);  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {     std::cerr << "Grayscale PNG not supported " + file << std::endl;     return; }  if (bit_depth == 16)     png_set_strip_16(png_ptr);  if (color_type == PNG_COLOR_TYPE_PALETTE)     png_set_palette_to_rgb(png_ptr); else if (color_type == PNG_COLOR_TYPE_GRAY ||     color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {     png_set_gray_to_rgb(png_ptr); }  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))     png_set_tRNS_to_alpha(png_ptr); else     png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);  png_read_update_info(png_ptr, info_ptr);  png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_uint_32 numbytes = rowbytes*(height); png_byte* pixels = (png_byte*)malloc(numbytes); png_byte** row_ptrs = (png_byte**)malloc((height)* sizeof(png_byte*));  int i; for (i = 0; i<height; i++)     row_ptrs[i] = pixels + (height - 1 - i)*rowbytes;  png_read_image(png_ptr, row_ptrs);  free(row_ptrs); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(png_file);  //return (char *)pixels;  Create(*w, *h, 4, pixels, GL_UNSIGNED_BYTE); 

Unfortunately I get

Unhandled exception at 0x77D78E19 (ntdll.dll) in SimpleShader.exe: 0xC0000005: Access violation writing location 0x00000014.

on the line

    png_read_info(png_ptr, info_ptr); 

Specifically the error occurs here:

#ifdef PNG_STDIO_SUPPORTED /* This is the function that does the actual reading of data.  If you are  * not reading from a standard C stream, you should create a replacement  * read_data function and use it at run time with png_set_read_fn(), rather  * than changing the library.  */ void PNGCBAPI png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {    png_size_t check;     if (png_ptr == NULL)       return;     /* fread() returns 0 on error, so it is OK to store this in a png_size_t     * instead of an int, which is what fread() actually returns.     */    check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr)); // <---------- ERROR HERE     if (check != length)       png_error(png_ptr, "Read Error"); } #endif 

What could be the problem?

EDIT: Okay, it does NOT crash when I compile both libpng and my project in release mode. I need to run my project in debug mode though...

回答1:

This is caused by a mismatch in the compiler settings between libpng and your project. In particular, the Runtime Library setting, that has to be Multi-threaded DLL (/MD) in both libpng and your project. The readme states:

If you don't use the Visual Studio defaults your application must still be built with the default runtime option (/MD). If, for some reason, it is not then your application will crash inside libpng16.dll as soon as libpng tries to read from a file handle you pass in.

The simpliest way to avoid crashes AND to retain the debugging possibilities is to copy the "Release" configuration in your project and change a few properties so you can easily debug in Visual Studio. Here's how to do it:

  1. Click RMB on the project -> Properties -> Configuration Manager -> Expand Active solution configuration and click . Pick a new name and copy settings from Release.
  2. Now in the project settings, pick the newly created configuration and change the following properties:
    • C/C++ -> General -> Debug Information Format: Program Database for Edit And Continue (/ZI)
    • C/C++ -> Optimization -> Optimization: Disabled (/Od), Whole Program Optimization: No
    • That's all that's necessary. You can additionally disable linker optimization (references and COMDAT folding), enable minimal rebuild and so on.

That's it, good luck!



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!