Skip to content

Commit bc6e636

Browse files
committed
Avoid mixing incompatible CRTs when linking to libpng.dll
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.
1 parent d5e4915 commit bc6e636

File tree

7 files changed

+176
-71
lines changed

7 files changed

+176
-71
lines changed

png.c

+33
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,9 @@ png_get_io_ptr(png_const_structrp png_ptr)
699699
* PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a
700700
* function of your own because "FILE *" isn't necessarily available.
701701
*/
702+
#ifdef png_init_io
703+
#undef png_init_io
704+
#endif
702705
void PNGAPI
703706
png_init_io(png_structrp png_ptr, png_FILE_p fp)
704707
{
@@ -711,6 +714,36 @@ png_init_io(png_structrp png_ptr, png_FILE_p fp)
711714
}
712715
# endif
713716

717+
void PNGAPI
718+
png_init_io2(png_structrp png_ptr, png_FILE_p fp, png_fread_ptr fread_fn,
719+
png_fwrite_ptr fwrite_fn, png_fflush_ptr fflush_fn)
720+
{
721+
if (png_ptr->read_data_fn != NULL)
722+
{
723+
png_init_read_io(png_ptr, fp, fread_fn);
724+
}
725+
else
726+
{
727+
png_init_write_io(png_ptr, fp, fwrite_fn, fflush_fn);
728+
}
729+
}
730+
731+
void PNGAPI
732+
png_init_read_io(png_structrp png_ptr, png_FILE_p fp, png_fread_ptr fread_fn)
733+
{
734+
png_debug(1, "in png_init_read_io");
735+
png_set_read_fn2(png_ptr, fp, png_default_read_data, fread_fn);
736+
}
737+
738+
void PNGAPI
739+
png_init_write_io(png_structrp png_ptr, png_FILE_p fp, png_fwrite_ptr fwrite_fn,
740+
png_fflush_ptr fflush_fn)
741+
{
742+
png_debug(1, "in png_init_write_io");
743+
png_set_write_fn2(png_ptr, fp, png_default_write_data, png_default_flush,
744+
fwrite_fn, fflush_fn);
745+
}
746+
714747
# ifdef PNG_SAVE_INT_32_SUPPORTED
715748
/* PNG signed integers are saved in 32-bit 2's complement format. ANSI C-90
716749
* defines a cast of a signed integer to an unsigned integer either to preserve

png.h

+38-1
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,12 @@ typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32,
811811
typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32,
812812
int));
813813

814+
typedef PNG_CALLBACK(size_t, *png_fread_ptr, (png_voidp, png_size_t,
815+
png_size_t, png_FILE_p));
816+
typedef PNG_CALLBACK(size_t, *png_fwrite_ptr, (png_const_voidp, png_size_t,
817+
png_size_t, png_FILE_p));
818+
typedef PNG_CALLBACK(int, *png_fflush_ptr, (png_FILE_p));
819+
814820
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
815821
typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
816822
typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
@@ -1589,6 +1595,29 @@ PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr,
15891595
#ifdef PNG_STDIO_SUPPORTED
15901596
/* Initialize the input/output for the PNG file to the default functions. */
15911597
PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp));
1598+
PNG_EXPORT(250, void, png_init_io2, (png_structrp png_ptr, png_FILE_p fp,
1599+
png_fread_ptr fread_fn, png_fwrite_ptr fwrite_fn,
1600+
png_fflush_ptr fflush_fn));
1601+
1602+
static inline png_size_t
1603+
png_fread_(png_voidp buf, png_size_t sz, png_size_t count, png_FILE_p fp)
1604+
{
1605+
return fread(buf, sz, count, fp);
1606+
}
1607+
1608+
static inline png_size_t
1609+
png_fwrite_(png_const_voidp buf, png_size_t sz, png_size_t count, png_FILE_p fp)
1610+
{
1611+
return fwrite(buf, sz, count, fp);
1612+
}
1613+
1614+
static inline int png_fflush_(png_FILE_p fp)
1615+
{
1616+
return fflush(fp);
1617+
}
1618+
1619+
#define png_init_io(png_ptr, fp) png_init_io2((png_ptr), (fp), png_fread_, \
1620+
png_fwrite_, png_fflush_)
15921621
#endif
15931622

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

1650+
/* Initialize the output for the PNG file. */
1651+
PNG_EXPORT(251, void, png_init_write_io, (png_structrp png_ptr, png_FILE_p fp,
1652+
png_fwrite_ptr fwrite_fn, png_fflush_ptr fflush_fn));
1653+
16211654
/* Replace the default data input function with a user supplied one. */
16221655
PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr,
16231656
png_rw_ptr read_data_fn));
16241657

1658+
/* Initialize the input for the PNG file. */
1659+
PNG_EXPORT(252, void, png_init_read_io, (png_structrp png_ptr, png_FILE_p fp,
1660+
png_fread_ptr fread_fn));
1661+
16251662
/* Return the user pointer associated with the I/O functions */
16261663
PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr));
16271664

@@ -3266,7 +3303,7 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
32663303
* one to use is one more than this.)
32673304
*/
32683305
#ifdef PNG_EXPORT_LAST_ORDINAL
3269-
PNG_EXPORT_LAST_ORDINAL(249);
3306+
PNG_EXPORT_LAST_ORDINAL(252);
32703307
#endif
32713308

32723309
#ifdef __cplusplus

pngpriv.h

+8
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,14 @@ PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY);
10541054
PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr,
10551055
png_bytep data, png_size_t length),PNG_EMPTY);
10561056

1057+
PNG_INTERNAL_FUNCTION(void PNGCBAPI, png_set_read_fn2, (png_structrp png_ptr,
1058+
png_voidp io_ptr, png_rw_ptr read_data_fn, png_fread_ptr fread_fn),
1059+
PNG_EMPTY);
1060+
1061+
PNG_INTERNAL_FUNCTION(void PNGCBAPI, png_set_write_fn2, (png_structrp png_ptr,
1062+
png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn,
1063+
png_fwrite_ptr fwrite_fn, png_fflush_ptr fflush_fn), PNG_EMPTY);
1064+
10571065
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
10581066
PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr,
10591067
png_bytep buffer, png_size_t length),PNG_EMPTY);

pngrio.c

+36-28
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ png_read_data(png_structrp png_ptr, png_bytep data, png_size_t length)
4040
png_error(png_ptr, "Call to NULL read function");
4141
}
4242

43-
#ifdef PNG_STDIO_SUPPORTED
4443
/* This is the function that does the actual reading of data. If you are
4544
* not reading from a standard C stream, you should create a replacement
4645
* read_data function and use it at run time with png_set_read_fn(), rather
@@ -51,18 +50,47 @@ png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
5150
{
5251
png_size_t check;
5352

54-
if (png_ptr == NULL)
53+
if (png_ptr == NULL || png_ptr->fread_fn == NULL)
5554
return;
5655

5756
/* fread() returns 0 on error, so it is OK to store this in a png_size_t
5857
* instead of an int, which is what fread() actually returns.
5958
*/
60-
check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr));
59+
check = png_ptr->fread_fn(data, 1, length, png_voidcast(png_FILE_p,
60+
png_ptr->io_ptr));
6161

6262
if (check != length)
6363
png_error(png_ptr, "Read Error");
6464
}
65+
66+
void /* PRIVATE */
67+
png_set_read_fn2(png_structrp png_ptr, png_voidp io_ptr,
68+
png_rw_ptr read_data_fn, png_fread_ptr fread_fn)
69+
{
70+
if (png_ptr == NULL)
71+
return;
72+
73+
png_ptr->io_ptr = io_ptr;
74+
png_ptr->read_data_fn = read_data_fn;
75+
png_ptr->fread_fn = fread_fn;
76+
77+
#ifdef PNG_WRITE_SUPPORTED
78+
/* It is an error to write to a read device */
79+
if (png_ptr->write_data_fn != NULL)
80+
{
81+
png_ptr->write_data_fn = NULL;
82+
png_ptr->fwrite_fn = NULL;
83+
png_warning(png_ptr,
84+
"Can't set both read_data_fn and write_data_fn in the"
85+
" same structure");
86+
}
87+
#endif
88+
89+
#ifdef PNG_WRITE_FLUSH_SUPPORTED
90+
png_ptr->output_flush_fn = NULL;
91+
png_ptr->fflush_fn = NULL;
6592
#endif
93+
}
6694

6795
/* This function allows the application to supply a new input function
6896
* for libpng if standard C streams aren't being used.
@@ -87,34 +115,14 @@ void PNGAPI
87115
png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr,
88116
png_rw_ptr read_data_fn)
89117
{
90-
if (png_ptr == NULL)
91-
return;
92-
93-
png_ptr->io_ptr = io_ptr;
94-
118+
png_fread_ptr fread_fn = NULL;
95119
#ifdef PNG_STDIO_SUPPORTED
96-
if (read_data_fn != NULL)
97-
png_ptr->read_data_fn = read_data_fn;
98-
99-
else
100-
png_ptr->read_data_fn = png_default_read_data;
101-
#else
102-
png_ptr->read_data_fn = read_data_fn;
103-
#endif
104-
105-
#ifdef PNG_WRITE_SUPPORTED
106-
/* It is an error to write to a read device */
107-
if (png_ptr->write_data_fn != NULL)
120+
if (read_data_fn == NULL)
108121
{
109-
png_ptr->write_data_fn = NULL;
110-
png_warning(png_ptr,
111-
"Can't set both read_data_fn and write_data_fn in the"
112-
" same structure");
122+
read_data_fn = png_default_read_data;
123+
fread_fn = png_fread_;
113124
}
114125
#endif
115-
116-
#ifdef PNG_WRITE_FLUSH_SUPPORTED
117-
png_ptr->output_flush_fn = NULL;
118-
#endif
126+
png_set_read_fn2(png_ptr, io_ptr, read_data_fn, fread_fn);
119127
}
120128
#endif /* READ */

pngstruct.h

+6
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,12 @@ struct png_struct_def
478478
#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)
479479
png_colorspace colorspace;
480480
#endif
481+
#endif
482+
483+
png_fread_ptr fread_fn; /* function for reading input data */
484+
png_fwrite_ptr fwrite_fn; /* function for writing output data */
485+
#ifdef PNG_WRITE_FLUSH_SUPPORTED
486+
png_fflush_ptr fflush_fn; /* Function for flushing output */
481487
#endif
482488
};
483489
#endif /* PNGSTRUCT_H */

pngwio.c

+52-42
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
5252
{
5353
png_size_t check;
5454

55-
if (png_ptr == NULL)
55+
if (png_ptr == NULL || png_ptr->fwrite_fn == NULL)
5656
return;
5757

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

6060
if (check != length)
6161
png_error(png_ptr, "Write Error");
@@ -74,21 +74,54 @@ png_flush(png_structrp png_ptr)
7474
(*(png_ptr->output_flush_fn))(png_ptr);
7575
}
7676

77-
# ifdef PNG_STDIO_SUPPORTED
7877
void PNGCBAPI
7978
png_default_flush(png_structp png_ptr)
8079
{
8180
png_FILE_p io_ptr;
8281

83-
if (png_ptr == NULL)
82+
if (png_ptr == NULL || png_ptr->fflush_fn == NULL)
8483
return;
8584

8685
io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr));
87-
fflush(io_ptr);
86+
png_ptr->fflush_fn(io_ptr);
8887
}
89-
# endif
9088
#endif
9189

90+
void /* PRIVATE */
91+
png_set_write_fn2(png_structrp png_ptr, png_voidp io_ptr,
92+
png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn,
93+
png_fwrite_ptr fwrite_fn, png_fflush_ptr fflush_fn)
94+
{
95+
if (png_ptr == NULL)
96+
return;
97+
98+
png_ptr->io_ptr = io_ptr;
99+
100+
png_ptr->write_data_fn = write_data_fn;
101+
png_ptr->fwrite_fn = fwrite_fn;
102+
103+
#ifdef PNG_WRITE_FLUSH_SUPPORTED
104+
png_ptr->output_flush_fn = output_flush_fn;
105+
png_ptr->fflush_fn = fflush_fn;
106+
#else
107+
PNG_UNUSED(output_flush_fn)
108+
PNG_UNUSED(fflush_fn)
109+
#endif /* WRITE_FLUSH */
110+
111+
#ifdef PNG_READ_SUPPORTED
112+
/* It is an error to read while writing a png file */
113+
if (png_ptr->read_data_fn != NULL)
114+
{
115+
png_ptr->read_data_fn = NULL;
116+
png_ptr->fread_fn = NULL;
117+
118+
png_warning(png_ptr,
119+
"Can't set both read_data_fn and write_data_fn in the"
120+
" same structure");
121+
}
122+
#endif
123+
}
124+
92125
/* This function allows the application to supply new output functions for
93126
* libpng if standard C streams aren't being used.
94127
*
@@ -122,47 +155,24 @@ void PNGAPI
122155
png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr,
123156
png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)
124157
{
125-
if (png_ptr == NULL)
126-
return;
127-
128-
png_ptr->io_ptr = io_ptr;
129-
158+
png_fwrite_ptr fwrite_fn = NULL;
159+
png_fflush_ptr fflush_fn = NULL;
130160
#ifdef PNG_STDIO_SUPPORTED
131-
if (write_data_fn != NULL)
132-
png_ptr->write_data_fn = write_data_fn;
133-
134-
else
135-
png_ptr->write_data_fn = png_default_write_data;
136-
#else
137-
png_ptr->write_data_fn = write_data_fn;
161+
if (write_data_fn == NULL)
162+
{
163+
write_data_fn = png_default_write_data;
164+
fwrite_fn = png_fwrite_;
165+
}
138166
#endif
139167

140-
#ifdef PNG_WRITE_FLUSH_SUPPORTED
141-
# ifdef PNG_STDIO_SUPPORTED
142-
143-
if (output_flush_fn != NULL)
144-
png_ptr->output_flush_fn = output_flush_fn;
145-
146-
else
147-
png_ptr->output_flush_fn = png_default_flush;
148-
149-
# else
150-
png_ptr->output_flush_fn = output_flush_fn;
151-
# endif
152-
#else
153-
PNG_UNUSED(output_flush_fn)
154-
#endif /* WRITE_FLUSH */
155-
156-
#ifdef PNG_READ_SUPPORTED
157-
/* It is an error to read while writing a png file */
158-
if (png_ptr->read_data_fn != NULL)
168+
#if defined(PNG_WRITE_FLUSH_SUPPORTED) && defined(PNG_STDIO_SUPPORTED)
169+
if (output_flush_fn == NULL)
159170
{
160-
png_ptr->read_data_fn = NULL;
161-
162-
png_warning(png_ptr,
163-
"Can't set both read_data_fn and write_data_fn in the"
164-
" same structure");
171+
output_flush_fn = png_default_flush;
172+
fflush_fn = png_fflush_;
165173
}
166174
#endif
175+
png_set_write_fn2(png_ptr, io_ptr, write_data_fn, output_flush_fn,
176+
fwrite_fn, fflush_fn);
167177
}
168178
#endif /* WRITE */

scripts/symbols.def

+3
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,6 @@ EXPORTS
254254
png_set_eXIf @247
255255
png_get_eXIf_1 @248
256256
png_set_eXIf_1 @249
257+
png_init_io2 @250
258+
png_init_write_io @251
259+
png_init_read_io @252

0 commit comments

Comments
 (0)