Skip to content

Commit

Permalink
Avoid mixing incompatible CRTs when linking to libpng.dll
Browse files Browse the repository at this point in the history
If libpng.dll is built using static linking (without importing C runtimes from whatever version of ms compiler that was used to build it), or when it was build by mingw then such dll won't work properly as stdio fread/fwrite will try to interpret FILE pointers from unrelated CRT and will result in undefined behavior.
  • Loading branch information
pps83 committed Feb 17, 2018
1 parent d5e4915 commit bc6e636
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 71 deletions.
33 changes: 33 additions & 0 deletions png.c
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,9 @@ png_get_io_ptr(png_const_structrp png_ptr)
* PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a
* function of your own because "FILE *" isn't necessarily available.
*/
#ifdef png_init_io
#undef png_init_io
#endif
void PNGAPI
png_init_io(png_structrp png_ptr, png_FILE_p fp)
{
Expand All @@ -711,6 +714,36 @@ png_init_io(png_structrp png_ptr, png_FILE_p fp)
}
# endif

void PNGAPI
png_init_io2(png_structrp png_ptr, png_FILE_p fp, png_fread_ptr fread_fn,
png_fwrite_ptr fwrite_fn, png_fflush_ptr fflush_fn)
{
if (png_ptr->read_data_fn != NULL)
{
png_init_read_io(png_ptr, fp, fread_fn);
}
else
{
png_init_write_io(png_ptr, fp, fwrite_fn, fflush_fn);
}
}

void PNGAPI
png_init_read_io(png_structrp png_ptr, png_FILE_p fp, png_fread_ptr fread_fn)
{
png_debug(1, "in png_init_read_io");
png_set_read_fn2(png_ptr, fp, png_default_read_data, fread_fn);
}

void PNGAPI
png_init_write_io(png_structrp png_ptr, png_FILE_p fp, png_fwrite_ptr fwrite_fn,
png_fflush_ptr fflush_fn)
{
png_debug(1, "in png_init_write_io");
png_set_write_fn2(png_ptr, fp, png_default_write_data, png_default_flush,
fwrite_fn, fflush_fn);
}

# ifdef PNG_SAVE_INT_32_SUPPORTED
/* PNG signed integers are saved in 32-bit 2's complement format. ANSI C-90
* defines a cast of a signed integer to an unsigned integer either to preserve
Expand Down
39 changes: 38 additions & 1 deletion png.h
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,12 @@ typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32,
typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32,
int));

typedef PNG_CALLBACK(size_t, *png_fread_ptr, (png_voidp, png_size_t,
png_size_t, png_FILE_p));
typedef PNG_CALLBACK(size_t, *png_fwrite_ptr, (png_const_voidp, png_size_t,
png_size_t, png_FILE_p));
typedef PNG_CALLBACK(int, *png_fflush_ptr, (png_FILE_p));

#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
Expand Down Expand Up @@ -1589,6 +1595,29 @@ PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr,
#ifdef PNG_STDIO_SUPPORTED
/* Initialize the input/output for the PNG file to the default functions. */
PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp));
PNG_EXPORT(250, void, png_init_io2, (png_structrp png_ptr, png_FILE_p fp,
png_fread_ptr fread_fn, png_fwrite_ptr fwrite_fn,
png_fflush_ptr fflush_fn));

static inline png_size_t
png_fread_(png_voidp buf, png_size_t sz, png_size_t count, png_FILE_p fp)
{
return fread(buf, sz, count, fp);
}

static inline png_size_t
png_fwrite_(png_const_voidp buf, png_size_t sz, png_size_t count, png_FILE_p fp)
{
return fwrite(buf, sz, count, fp);
}

static inline int png_fflush_(png_FILE_p fp)
{
return fflush(fp);
}

#define png_init_io(png_ptr, fp) png_init_io2((png_ptr), (fp), png_fread_, \
png_fwrite_, png_fflush_)
#endif

/* Replace the (error and abort), and warning functions with user
Expand Down Expand Up @@ -1618,10 +1647,18 @@ PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr));
PNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr,
png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn));

/* Initialize the output for the PNG file. */
PNG_EXPORT(251, void, png_init_write_io, (png_structrp png_ptr, png_FILE_p fp,
png_fwrite_ptr fwrite_fn, png_fflush_ptr fflush_fn));

/* Replace the default data input function with a user supplied one. */
PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr,
png_rw_ptr read_data_fn));

/* Initialize the input for the PNG file. */
PNG_EXPORT(252, void, png_init_read_io, (png_structrp png_ptr, png_FILE_p fp,
png_fread_ptr fread_fn));

/* Return the user pointer associated with the I/O functions */
PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr));

Expand Down Expand Up @@ -3266,7 +3303,7 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
* one to use is one more than this.)
*/
#ifdef PNG_EXPORT_LAST_ORDINAL
PNG_EXPORT_LAST_ORDINAL(249);
PNG_EXPORT_LAST_ORDINAL(252);
#endif

#ifdef __cplusplus
Expand Down
8 changes: 8 additions & 0 deletions pngpriv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,14 @@ PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr,
png_bytep data, png_size_t length),PNG_EMPTY);

PNG_INTERNAL_FUNCTION(void PNGCBAPI, png_set_read_fn2, (png_structrp png_ptr,
png_voidp io_ptr, png_rw_ptr read_data_fn, png_fread_ptr fread_fn),
PNG_EMPTY);

PNG_INTERNAL_FUNCTION(void PNGCBAPI, png_set_write_fn2, (png_structrp png_ptr,
png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn,
png_fwrite_ptr fwrite_fn, png_fflush_ptr fflush_fn), PNG_EMPTY);

#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr,
png_bytep buffer, png_size_t length),PNG_EMPTY);
Expand Down
64 changes: 36 additions & 28 deletions pngrio.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ png_read_data(png_structrp png_ptr, png_bytep data, png_size_t length)
png_error(png_ptr, "Call to NULL read function");
}

#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
Expand All @@ -51,18 +50,47 @@ png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
png_size_t check;

if (png_ptr == NULL)
if (png_ptr == NULL || png_ptr->fread_fn == 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));
check = png_ptr->fread_fn(data, 1, length, png_voidcast(png_FILE_p,
png_ptr->io_ptr));

if (check != length)
png_error(png_ptr, "Read Error");
}

void /* PRIVATE */
png_set_read_fn2(png_structrp png_ptr, png_voidp io_ptr,
png_rw_ptr read_data_fn, png_fread_ptr fread_fn)
{
if (png_ptr == NULL)
return;

png_ptr->io_ptr = io_ptr;
png_ptr->read_data_fn = read_data_fn;
png_ptr->fread_fn = fread_fn;

#ifdef PNG_WRITE_SUPPORTED
/* It is an error to write to a read device */
if (png_ptr->write_data_fn != NULL)
{
png_ptr->write_data_fn = NULL;
png_ptr->fwrite_fn = NULL;
png_warning(png_ptr,
"Can't set both read_data_fn and write_data_fn in the"
" same structure");
}
#endif

#ifdef PNG_WRITE_FLUSH_SUPPORTED
png_ptr->output_flush_fn = NULL;
png_ptr->fflush_fn = NULL;
#endif
}

/* This function allows the application to supply a new input function
* for libpng if standard C streams aren't being used.
Expand All @@ -87,34 +115,14 @@ void PNGAPI
png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr,
png_rw_ptr read_data_fn)
{
if (png_ptr == NULL)
return;

png_ptr->io_ptr = io_ptr;

png_fread_ptr fread_fn = NULL;
#ifdef PNG_STDIO_SUPPORTED
if (read_data_fn != NULL)
png_ptr->read_data_fn = read_data_fn;

else
png_ptr->read_data_fn = png_default_read_data;
#else
png_ptr->read_data_fn = read_data_fn;
#endif

#ifdef PNG_WRITE_SUPPORTED
/* It is an error to write to a read device */
if (png_ptr->write_data_fn != NULL)
if (read_data_fn == NULL)
{
png_ptr->write_data_fn = NULL;
png_warning(png_ptr,
"Can't set both read_data_fn and write_data_fn in the"
" same structure");
read_data_fn = png_default_read_data;
fread_fn = png_fread_;
}
#endif

#ifdef PNG_WRITE_FLUSH_SUPPORTED
png_ptr->output_flush_fn = NULL;
#endif
png_set_read_fn2(png_ptr, io_ptr, read_data_fn, fread_fn);
}
#endif /* READ */
6 changes: 6 additions & 0 deletions pngstruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,12 @@ struct png_struct_def
#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)
png_colorspace colorspace;
#endif
#endif

png_fread_ptr fread_fn; /* function for reading input data */
png_fwrite_ptr fwrite_fn; /* function for writing output data */
#ifdef PNG_WRITE_FLUSH_SUPPORTED
png_fflush_ptr fflush_fn; /* Function for flushing output */
#endif
};
#endif /* PNGSTRUCT_H */
94 changes: 52 additions & 42 deletions pngwio.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
png_size_t check;

if (png_ptr == NULL)
if (png_ptr == NULL || png_ptr->fwrite_fn == NULL)
return;

check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr));
check = png_ptr->fwrite_fn(data, 1, length, (png_FILE_p)(png_ptr->io_ptr));

if (check != length)
png_error(png_ptr, "Write Error");
Expand All @@ -74,21 +74,54 @@ png_flush(png_structrp png_ptr)
(*(png_ptr->output_flush_fn))(png_ptr);
}

# ifdef PNG_STDIO_SUPPORTED
void PNGCBAPI
png_default_flush(png_structp png_ptr)
{
png_FILE_p io_ptr;

if (png_ptr == NULL)
if (png_ptr == NULL || png_ptr->fflush_fn == NULL)
return;

io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr));
fflush(io_ptr);
png_ptr->fflush_fn(io_ptr);
}
# endif
#endif

void /* PRIVATE */
png_set_write_fn2(png_structrp png_ptr, png_voidp io_ptr,
png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn,
png_fwrite_ptr fwrite_fn, png_fflush_ptr fflush_fn)
{
if (png_ptr == NULL)
return;

png_ptr->io_ptr = io_ptr;

png_ptr->write_data_fn = write_data_fn;
png_ptr->fwrite_fn = fwrite_fn;

#ifdef PNG_WRITE_FLUSH_SUPPORTED
png_ptr->output_flush_fn = output_flush_fn;
png_ptr->fflush_fn = fflush_fn;
#else
PNG_UNUSED(output_flush_fn)
PNG_UNUSED(fflush_fn)
#endif /* WRITE_FLUSH */

#ifdef PNG_READ_SUPPORTED
/* It is an error to read while writing a png file */
if (png_ptr->read_data_fn != NULL)
{
png_ptr->read_data_fn = NULL;
png_ptr->fread_fn = NULL;

png_warning(png_ptr,
"Can't set both read_data_fn and write_data_fn in the"
" same structure");
}
#endif
}

/* This function allows the application to supply new output functions for
* libpng if standard C streams aren't being used.
*
Expand Down Expand Up @@ -122,47 +155,24 @@ void PNGAPI
png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr,
png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)
{
if (png_ptr == NULL)
return;

png_ptr->io_ptr = io_ptr;

png_fwrite_ptr fwrite_fn = NULL;
png_fflush_ptr fflush_fn = NULL;
#ifdef PNG_STDIO_SUPPORTED
if (write_data_fn != NULL)
png_ptr->write_data_fn = write_data_fn;

else
png_ptr->write_data_fn = png_default_write_data;
#else
png_ptr->write_data_fn = write_data_fn;
if (write_data_fn == NULL)
{
write_data_fn = png_default_write_data;
fwrite_fn = png_fwrite_;
}
#endif

#ifdef PNG_WRITE_FLUSH_SUPPORTED
# ifdef PNG_STDIO_SUPPORTED

if (output_flush_fn != NULL)
png_ptr->output_flush_fn = output_flush_fn;

else
png_ptr->output_flush_fn = png_default_flush;

# else
png_ptr->output_flush_fn = output_flush_fn;
# endif
#else
PNG_UNUSED(output_flush_fn)
#endif /* WRITE_FLUSH */

#ifdef PNG_READ_SUPPORTED
/* It is an error to read while writing a png file */
if (png_ptr->read_data_fn != NULL)
#if defined(PNG_WRITE_FLUSH_SUPPORTED) && defined(PNG_STDIO_SUPPORTED)
if (output_flush_fn == NULL)
{
png_ptr->read_data_fn = NULL;

png_warning(png_ptr,
"Can't set both read_data_fn and write_data_fn in the"
" same structure");
output_flush_fn = png_default_flush;
fflush_fn = png_fflush_;
}
#endif
png_set_write_fn2(png_ptr, io_ptr, write_data_fn, output_flush_fn,
fwrite_fn, fflush_fn);
}
#endif /* WRITE */
3 changes: 3 additions & 0 deletions scripts/symbols.def
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,6 @@ EXPORTS
png_set_eXIf @247
png_get_eXIf_1 @248
png_set_eXIf_1 @249
png_init_io2 @250
png_init_write_io @251
png_init_read_io @252

0 comments on commit bc6e636

Please sign in to comment.