Closed madebr closed 8 months ago
In addition to those, gcc-4.9 also warns for row_pointers
and surface
in IMG_LoadPNG_RW
(lines 240 and 247) for me:
/tmp/SDL_image/src/IMG_png.c: In function 'IMG_SavePNG_RW_libpng':
/tmp/SDL_image/src/IMG_png.c:580:16: warning: variable 'color_ptr' might be clobbered by 'longjmp' or 'vfork' [-Wclobbered]
png_colorp color_ptr = NULL;
^
/tmp/SDL_image/src/IMG_png.c:584:9: warning: variable 'png_color_type' might be clobbered by 'longjmp' or 'vfork' [-Wclobbered]
int png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
^
/tmp/SDL_image/src/IMG_png.c: In function 'IMG_LoadPNG_RW':
/tmp/SDL_image/src/IMG_png.c:240:18: warning: variable 'surface' might be clobbered by 'longjmp' or 'vfork' [-Wclobbered]
SDL_Surface *surface;
^
/tmp/SDL_image/src/IMG_png.c:247:16: warning: variable 'row_pointers' might be clobbered by 'longjmp' or 'vfork' [-Wclobbered]
png_bytep *row_pointers;
^
~Warning from IMG_SavePNG_RW_libpng
is easy to fix:~
~Not exactly sure about what to do with the ones from IMG_LoadPNG_RW
~
~because of the goto done
clean-ups.~
Does adding the volatile keyword to the cleanup variables work?
Does adding the volatile keyword to the cleanup variables work?
Tried adding volatile to surface
and row_pointers
at lines 240 and 247: no, doesn't eliminate those two -Wclobbered
, and adds new discards 'volatile' qualifier
warnings.
What if those variables are stored in a malloc'd structure, allocated at the top of the function?
My understanding is that warning is telling us that any changes to the stack variables could be undone when the longjmp returns. But if we allocate a pointer at the beginning and free it at the end and reference the malloced memory in between, we should avoid that.
Well, your first reaction about volatile use was correct: I seem to have placed volatile wrongly and it does help: I pushed https://github.com/libsdl-org/SDL_image/commit/a4ae71897bcf1d8320a9bad9d39362d3977322e1 (which is a partial revert of https://github.com/libsdl-org/SDL_image/commit/a61c2fc38f768b509d204182b4e988669036eb14) and https://github.com/libsdl-org/SDL_image/commit/5dc391d750e63711f2ebd6f44bd193e6845fd06f which silences the warnings. I.e. the final result turned into this:
diff --git a/src/IMG_png.c b/src/IMG_png.c
index d09e312..640cc5b 100644
--- a/src/IMG_png.c
+++ b/src/IMG_png.c
@@ -237,14 +237,14 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
{
Sint64 start;
const char *error;
- SDL_Surface *surface;
+ SDL_Surface *volatile surface;
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type, num_channels;
Uint32 format;
SDL_Palette *palette;
- png_bytep *row_pointers;
+ png_bytep *volatile row_pointers;
int row, i;
int ckey;
png_color_16 *transv;
@@ -577,11 +577,11 @@ static int IMG_SavePNG_RW_libpng(SDL_Surface *surface, SDL_RWops *dst)
{
png_structp png_ptr;
png_infop info_ptr;
- png_colorp color_ptr = NULL;
+ png_colorp volatile color_ptr = NULL;
Uint8 transparent_table[256];
- SDL_Surface *source = surface;
+ SDL_Surface * volatile source = surface;
SDL_Palette *palette;
- int png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ int png_color_type;
if (!IMG_Init(IMG_INIT_PNG)) {
return -1;
@@ -652,6 +652,7 @@ static int IMG_SavePNG_RW_libpng(SDL_Surface *surface, SDL_RWops *dst)
else if (surface->format->format != png_format) {
/* Otherwise, (surface has alpha data), and it is not in the exact right
format , so it should be converted to that */
+ png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
source = SDL_ConvertSurfaceFormat(surface, png_format);
}
Is this correct? If it is, then we can close this ticket.
P.S.: IMG_SavePNG_RW_libpng()
parts may go into SDL2 branch too.
(CC: @1bsyl about the partial revert of https://github.com/libsdl-org/SDL_image/commit/a61c2fc38f768b509d204182b4e988669036eb1)
setjmp() isn't really nice to read. In the code, it means, upon error, the libpng functions can go back to the jump position: in the failing section: setjmp() {... goto done; }.
I can't get the same error with "Werror=clobbered" (only IMG_SavePNG_RW_libpng has the error.) ...
maybe repeating the initialization after setjmp() is ok to fix the warning:
diff --git a/src/IMG_png.c b/src/IMG_png.c
index 640cc5b..00828ee 100644
--- a/src/IMG_png.c
+++ b/src/IMG_png.c
@@ -237,14 +237,14 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
{
Sint64 start;
const char *error;
- SDL_Surface *volatile surface;
+ SDL_Surface *surface;
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type, num_channels;
Uint32 format;
SDL_Palette *palette;
- png_bytep *volatile row_pointers;
+ png_bytep *row_pointers;
int row, i;
int ckey;
png_color_16 *transv;
@@ -297,6 +297,9 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
goto done;
}
#endif
+
+ row_pointers = NULL; surface = NULL;
+
/* Set up the input control */
lib.png_set_read_fn(png_ptr, src, png_read_data);
@@ -577,9 +580,9 @@ static int IMG_SavePNG_RW_libpng(SDL_Surface *surface, SDL_RWops *dst)
{
png_structp png_ptr;
png_infop info_ptr;
- png_colorp volatile color_ptr = NULL;
+ png_colorp color_ptr = NULL;
Uint8 transparent_table[256];
- SDL_Surface * volatile source = surface;
+ SDL_Surface * source = surface;
SDL_Palette *palette;
int png_color_type;
@@ -609,6 +612,11 @@ static int IMG_SavePNG_RW_libpng(SDL_Surface *surface, SDL_RWops *dst)
return IMG_SetError("Error writing the PNG file.");
}
+ source = surface;
+ color_ptr = NULL;
+ png_color_type = PNG_COLOR_TYPE_RGB;
+
+
palette = surface->format->palette;
if (palette) {
const int ncolors = palette->ncolors;
setjmp() isn't really nice to read.
Indeed, and it's a mess, ...
In the code, it means, upon error, the libpng functions can go back to the jump position: in the failing section: setjmp() {... goto done; }.
maybe repeating the initialization after setjmp() is ok to fix the warning:
Haven't tried that way, and it really may silence the warning. However
upon rewinding the stack, we will already be leaking the allocated memory,
I don't know exactly how volatile
is silencing gcc here, and I don't know
a better way of handling this mess: libpng doesn't seem to return error but
rely on longjmp as far as I can see??..
I think it relies on longjmp() so the parser can cleanly fail at any time.
my understanding is:
1/ you set the longjmp(). and the first time it returns 0... that starts.
then, any call to the libpng that fail will return
to the first setjmp() call. but with a return code of != 0.
so that the block{...}
is executed. And the block contains either "returns SDL_SetError or goto done;", the "repeated initialization" won't be re-used and it won't leak anything.
And row_pointers
for e.g., won't be leaked upon longjmp, I mean shall it not be clobbered back to NULL?
Anyways, I'm confused enough today :) Leaving this thing to you guys @1bsyl, @slouken, @icculus for now
And
row_pointers
for e.g., won't be leaked upon longjmp, I mean shall it not be clobbered back to NULL
the one from "IMG_SavePNG_RW_libpng" ?? I think, here. it will leak if the setjmp fails in lib.png_write_png() for instance. because, it will returns to setjmp(). and won't call SDL_Free for this local variable (because it's not in the main block). (but maybe png_write_png cannot fails to setjmp())
my understanding is that the stack before setjmp() shouldn't be cleared when the program gets back to setjmp.
Then we can implement @slouken's suggestion somehow, i.e.: create a struct with necessary vars, make the libpng-calling procedure into a helper and pass that struct pointer to it? I might mess with that today later.
I think it's fine to have the volatile ! but IMG_SavePNG_RW_libpng seems to totally wrong since nothing get freed when a setjump error occur
would done something like this:
diff --git a/src/IMG_png.c b/src/IMG_png.c
index 640cc5b..c237ac3 100644
--- a/src/IMG_png.c
+++ b/src/IMG_png.c
@@ -577,11 +577,13 @@ static int IMG_SavePNG_RW_libpng(SDL_Surface *surface, SDL_RWops *dst)
{
png_structp png_ptr;
png_infop info_ptr;
+ const char *error;
png_colorp volatile color_ptr = NULL;
Uint8 transparent_table[256];
SDL_Surface * volatile source = surface;
SDL_Palette *palette;
int png_color_type;
+ png_bytep *row_pointers = NULL;
if (!IMG_Init(IMG_INIT_PNG)) {
return -1;
@@ -605,8 +607,8 @@ static int IMG_SavePNG_RW_libpng(SDL_Surface *surface, SDL_RWops *dst)
#endif
#endif
{
- lib.png_destroy_write_struct(&png_ptr, &info_ptr);
- return IMG_SetError("Error writing the PNG file.");
+ error = "Error writing the PNG file.";
+ goto done;
}
palette = surface->format->palette;
@@ -618,8 +620,8 @@ static int IMG_SavePNG_RW_libpng(SDL_Surface *surface, SDL_RWops *dst)
color_ptr = (png_colorp)SDL_malloc(sizeof(png_color) * ncolors);
if (color_ptr == NULL)
{
- lib.png_destroy_write_struct(&png_ptr, &info_ptr);
- return IMG_SetError("Couldn't create palette for PNG file");
+ error = "Couldn't create palette for PNG file";
+ goto done;
}
for (i = 0; i < ncolors; i++) {
color_ptr[i].red = palette->colors[i].r;
@@ -663,14 +665,11 @@ static int IMG_SavePNG_RW_libpng(SDL_Surface *surface, SDL_RWops *dst)
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
if (source) {
- png_bytep *row_pointers;
int row;
-
row_pointers = (png_bytep *) SDL_malloc(sizeof(png_bytep) * source->h);
if (!row_pointers) {
- SDL_free(color_ptr);
- lib.png_destroy_write_struct(&png_ptr, &info_ptr);
- return IMG_SetError("Out of memory");
+ error = "Out of memory";
+ goto done;
}
for (row = 0; row < (int)source->h; row++) {
row_pointers[row] = (png_bytep) (Uint8 *) source->pixels + row * source->pitch;
@@ -678,16 +677,31 @@ static int IMG_SavePNG_RW_libpng(SDL_Surface *surface, SDL_RWops *dst)
lib.png_set_rows(png_ptr, info_ptr, row_pointers);
lib.png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
+ }
- SDL_free(row_pointers);
- if (source != surface) {
- SDL_DestroySurface(source);
- }
+done:/* Clean up and return */
+
+ if (png_ptr) {
+ lib.png_destroy_write_struct(&png_ptr, &info_ptr);
}
- lib.png_destroy_write_struct(&png_ptr, &info_ptr);
+
if (color_ptr) {
SDL_free(color_ptr);
}
+
+ if (row_pointers) {
+ SDL_free(row_pointers);
+ }
+
+ if (source != surface) {
+ SDL_DestroySurface(source);
+ }
+
+ if (error) {
+ IMG_SetError("%s", error);
+ return -1;
+ }
+
return 0;
}
here's a PR: https://github.com/libsdl-org/SDL_image/pull/417 only test that it correctly save png file
And bug fixed: uninitialized color type when saving SDL_PIXELFORMAT_RGBA32 surface
Alternative patch: patch-416.txt Generated after applying your #417 and splitting the procedures. Should handle longjmp funnies, I hope. Can you review?
@slouken: Is this close to your suggestion above?
Inlining below for convenience: What do you think?
Do both of these patches resolve the setjmp/longjmp warnings?
i.e. is @1bsyl's patch in #416 enough?
Do both of these patches resolve the setjmp/longjmp warnings?
Yes. Created PR #418 now to ensure it. Let's see how it goes. (Please review it, btw.)
i.e. is @1bsyl's patch in #416 enough?
AFAICS, it doesn't handle leaks upon a longjmp (but it's just me.)
Fixed by #418, closing.
The following errors appear on ci:
https://github.com/libsdl-org/SDL_image/actions/runs/7661898175/job/20882153620#step:13:29
https://github.com/libsdl-org/SDL_image/blob/abbf3a2addfe8ca9fdd3dd3e1551c14940f0f5e8/src/IMG_png.c#L580-L605