Fix stack smaller in write png_copy_row

This also resulted in PNG data with random row bytes.

Signed-off-by: John Bowler <jbowler@acm.org>
This commit is contained in:
John Bowler 2015-12-06 11:12:17 -08:00
parent 66b53bdd37
commit b8ab93dc6f
4 changed files with 24 additions and 13 deletions

24
png.c
View File

@ -2402,12 +2402,14 @@ png_max_pixel_block(png_const_structrp png_ptr)
void /* PRIVATE */ void /* PRIVATE */
png_copy_row(png_const_structrp png_ptr, png_bytep dp, png_const_bytep sp, png_copy_row(png_const_structrp png_ptr, png_bytep dp, png_const_bytep sp,
png_uint_32 x/*in INPUT*/, png_uint_32 width/*of INPUT*/, png_uint_32 x/*in INPUT*/, png_uint_32 width/*of INPUT*/,
unsigned int pixel_depth, int clear/*clear the final byte*/) unsigned int pixel_depth, int clear/*clear the final byte*/, int x_in_dest)
/* Copy the row in row_buffer; this is the non-interlaced copy used in both /* Copy the row in row_buffer; this is the non-interlaced copy used in both
* the read and write code. * the read and write code. 'x_in_dest' specifies whether the 'x' applies to
* the destination (sp->dp[x], x_in_dest tru) or the source (sp[x]->dp,
* x_in_dest false).
*/ */
{ {
png_alloc_size_t cb; png_alloc_size_t cb, offset;
unsigned int remaining; /* remaining bits in a partial byte */ unsigned int remaining; /* remaining bits in a partial byte */
/* Copy 'cb' pixels, but take care with the last byte because it may /* Copy 'cb' pixels, but take care with the last byte because it may
@ -2419,28 +2421,34 @@ png_copy_row(png_const_structrp png_ptr, png_bytep dp, png_const_bytep sp,
case 1U: remaining = width & 7U; case 1U: remaining = width & 7U;
debug((x & 7U) == 0U); debug((x & 7U) == 0U);
cb = width >> 3; cb = width >> 3;
dp += x >> 3; offset = x >> 3;
break; break;
case 2U: remaining = (width << 1) & 6U; case 2U: remaining = (width << 1) & 6U;
debug((x & 3U) == 0U); debug((x & 3U) == 0U);
cb = width >> 2; cb = width >> 2;
dp += x >> 2; offset = x >> 2;
break; break;
case 4U: remaining = (width << 2) & 4U; case 4U: remaining = (width << 2) & 4U;
debug((x & 1U) == 0U); debug((x & 1U) == 0U);
cb = width >> 1; cb = width >> 1;
dp += x >> 1; offset = x >> 1;
break; break;
case 8U: remaining = 0U; case 8U: remaining = 0U;
cb = width; cb = width;
dp += x; offset = x;
break; break;
default: remaining = 0U; default: remaining = 0U;
cb = png_calc_rowbytes(png_ptr, pixel_depth, width); cb = png_calc_rowbytes(png_ptr, pixel_depth, width);
dp += png_calc_rowbytes(png_ptr, pixel_depth, x); offset = png_calc_rowbytes(png_ptr, pixel_depth, x);
break; break;
} }
if (x_in_dest)
dp += offset;
else
sp += offset;
memcpy(dp, sp, cb); memcpy(dp, sp, cb);
if (remaining > 0U) if (remaining > 0U)

View File

@ -943,13 +943,15 @@ PNG_INTERNAL_FUNCTION(png_alloc_size_t,png_calc_rowbytes,
PNG_INTERNAL_FUNCTION(unsigned int,png_max_pixel_block, PNG_INTERNAL_FUNCTION(unsigned int,png_max_pixel_block,
(png_const_structrp png_ptr),PNG_EMPTY); (png_const_structrp png_ptr),PNG_EMPTY);
/* Copy the row in row_buffer; this is the non-interlaced copy used in both /* Copy the row in row_buffer; this is the non-interlaced copy used in both the
* the read and write code. * read and write code. 'x_in_dest' specifies whether the 'x' applies to
* the destination (sp->dp[x], x_in_dest tru) or the source (sp[x]->dp,
* x_in_dest false).
*/ */
PNG_INTERNAL_FUNCTION(void, png_copy_row,(png_const_structrp png_ptr, PNG_INTERNAL_FUNCTION(void, png_copy_row,(png_const_structrp png_ptr,
png_bytep dp, png_const_bytep sp, png_uint_32 x/*in INPUT*/, png_bytep dp, png_const_bytep sp, png_uint_32 x/*in INPUT*/,
png_uint_32 width/*of INPUT*/, unsigned int pixel_depth, png_uint_32 width/*of INPUT*/, unsigned int pixel_depth,
int clear/*clear the final byte*/),PNG_EMPTY); int clear/*clear the final byte*/, int x_in_dest),PNG_EMPTY);
/* Zlib support */ /* Zlib support */
#define PNG_UNEXPECTED_ZLIB_RETURN (-7) #define PNG_UNEXPECTED_ZLIB_RETURN (-7)

View File

@ -3114,7 +3114,7 @@ copy_row(png_const_structrp png_ptr, png_bytep dp, png_const_bytep sp,
# else # else
PNG_PIXEL_DEPTH(*png_ptr), PNG_PIXEL_DEPTH(*png_ptr),
# endif # endif
clear/*clear partial byte at end of row*/); clear/*clear partial byte at end of row*/, 1/*sp -> dp[x]*/);
} }
#ifdef PNG_READ_INTERLACING_SUPPORTED #ifdef PNG_READ_INTERLACING_SUPPORTED

View File

@ -720,7 +720,8 @@ copy_row(png_const_structrp png_ptr, png_bytep row_buffer,
unsigned int pixel_depth) unsigned int pixel_depth)
{ {
/* Copy row[x..x+count] pixels to row_buffer. */ /* Copy row[x..x+count] pixels to row_buffer. */
png_copy_row(png_ptr, row_buffer, row, x, count, pixel_depth, 1/*clear*/); png_copy_row(png_ptr, row_buffer, row, x, count, pixel_depth, 1/*clear*/,
0/* x_in_dest; row[x]->row_buffer */);
} }
#endif /* WRITE_TRANSFORMS */ #endif /* WRITE_TRANSFORMS */