Fix longjmp handling when calling libpng

This commit is contained in:
Kovid Goyal 2017-09-28 10:45:31 +05:30
parent 7da08d37d2
commit f3ee3784f7
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -182,15 +182,13 @@ read_png_from_buffer(png_structp png, png_bytep out, png_size_t length) {
} }
} }
static inline bool struct png_jmp_data { uint8_t *decompressed; bool ok; png_bytep *row_pointers; int width, height; size_t sz; };
inflate_png(GraphicsManager UNUSED *self, Image *img, uint8_t *buf, size_t bufsz) {
bool ok = false; static void
uint8_t *decompressed = NULL; inflate_png_inner(struct png_jmp_data *d, uint8_t *buf, size_t bufsz) {
struct fake_file f = {.buf = buf, .sz = bufsz};
png_structp png = NULL; png_structp png = NULL;
png_infop info = NULL; png_infop info = NULL;
png_bytep * row_pointers = NULL;
struct fake_file f = {.buf = buf, .sz = bufsz};
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) ABRT(ENOMEM, "Failed to create PNG read structure"); if (!png) ABRT(ENOMEM, "Failed to create PNG read structure");
info = png_create_info_struct(png); info = png_create_info_struct(png);
@ -200,10 +198,9 @@ inflate_png(GraphicsManager UNUSED *self, Image *img, uint8_t *buf, size_t bufsz
png_set_read_fn(png, &f, read_png_from_buffer); png_set_read_fn(png, &f, read_png_from_buffer);
png_read_info(png, info); png_read_info(png, info);
int width, height;
png_byte color_type, bit_depth; png_byte color_type, bit_depth;
width = png_get_image_width(png, info); d->width = png_get_image_width(png, info);
height = png_get_image_height(png, info); d->height = png_get_image_height(png, info);
color_type = png_get_color_type(png, info); color_type = png_get_color_type(png, info);
bit_depth = png_get_bit_depth(png, info); bit_depth = png_get_bit_depth(png, info);
@ -222,25 +219,34 @@ inflate_png(GraphicsManager UNUSED *self, Image *img, uint8_t *buf, size_t bufsz
png_read_update_info(png, info); png_read_update_info(png, info);
int rowbytes = png_get_rowbytes(png, info); int rowbytes = png_get_rowbytes(png, info);
size_t sz = rowbytes * height * sizeof(png_byte); d->sz = rowbytes * d->height * sizeof(png_byte);
decompressed = malloc(sz + 16); d->decompressed = malloc(d->sz + 16);
if (decompressed == NULL) ABRT(ENOMEM, "Out of memory allocating decompression buffer for PNG"); if (d->decompressed == NULL) ABRT(ENOMEM, "Out of memory allocating decompression buffer for PNG");
row_pointers = malloc(height * sizeof(png_bytep)); d->row_pointers = malloc(d->height * sizeof(png_bytep));
if (row_pointers == NULL) ABRT(ENOMEM, "Out of memory allocating row_pointers buffer for PNG"); if (d->row_pointers == NULL) ABRT(ENOMEM, "Out of memory allocating row_pointers buffer for PNG");
for (int i = 0; i < height; i++) row_pointers[height - 1 - i] = decompressed + i * rowbytes; for (int i = 0; i < d->height; i++) d->row_pointers[d->height - 1 - i] = d->decompressed + i * rowbytes;
png_read_image(png, row_pointers); png_read_image(png, d->row_pointers);
free_load_data(&img->load_data); d->ok = true;
img->load_data.buf_capacity = sz;
img->load_data.buf = decompressed;
img->load_data.buf_used = sz;
img->width = width; img->height = height;
ok = true;
err: err:
if (png) png_destroy_read_struct(&png, info ? &info : NULL, NULL); if (png) png_destroy_read_struct(&png, info ? &info : NULL, NULL);
if (!ok) free(decompressed); return;
free(row_pointers); }
return ok;
static inline bool
inflate_png(GraphicsManager UNUSED *self, Image *img, uint8_t *buf, size_t bufsz) {
struct png_jmp_data d = {0};
inflate_png_inner(&d, buf, bufsz);
if (d.ok) {
free_load_data(&img->load_data);
img->load_data.buf_capacity = d.sz;
img->load_data.buf = d.decompressed;
img->load_data.buf_used = d.sz;
img->width = d.width; img->height = d.height;
}
else free(d.decompressed);
free(d.row_pointers);
return d.ok;
} }
#undef ABRT #undef ABRT