libpng 在 png_read_info() 上崩溃 [英] libpng crashes on png_read_info()

查看:35
本文介绍了libpng 在 png_read_info() 上崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 vs2013 中使用 libpng 1.2.10 读取 png 文件.我下载了最新的 zlib 并编译了 pnglib,效果很好.现在我正在尝试加载一个文件:

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);

不幸的是我得到了

SimpleShader.exe 中 0x77D78E19 (ntdll.dll) 处未处理的异常:0xC0000005:访问冲突写入位置 0x00000014.

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

上线

    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

可能是什么问题?

好的,当我在发布模式下编译 libpng 和我的项目时,它不会崩溃.我需要在调试模式下运行我的项目...

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...

推荐答案

这是由 libpng 和您的项目之间的编译器设置不匹配引起的.特别是 Runtime Library 设置,在 libpng 和您的项目中都必须是 多线程 DLL (/MD).自述文件指出:

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:

如果您不使用 Visual Studio 默认值,您的应用程序仍必须构建使用默认运行时选项 (/MD).如果由于某种原因,它不是那么你的一旦 libpng 尝试读取,应用程序将在 libpng16.dll 中崩溃来自您传入的文件句柄.

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.

避免崩溃并保留调试可能性的最简单方法是复制项目中的发布"配置并更改一些属性,以便您可以在 Visual Studio 中轻松调试.操作方法如下:

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. 在项目上单击 RMB -> Properties -> Configuration Manager -> 展开 Active solution configuration 并单击 .从 Release 中选择一个新名称并复制设置.
  2. 现在在项目设置中,选择新创建的配置并更改以下属性:
    • C/C++ -> General -> 调试信息格式:用于编辑和继续的程序数据库(/ZI)
    • C/C++ -> 优化 -> 优化:禁用(/Od),整个程序优化:否
    • 仅此而已.您还可以禁用链接器优化(引用和 COMDAT 折叠)、启用最少重建等.
  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.

就是这样,祝你好运!

这篇关于libpng 在 png_read_info() 上崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆