Undefined behavior in io-jpeg.c
Hi,
During some unrelated code analysis in Qt I've spotted that the (sig)setjmp / longjmp pairs in io-jpeg.c are triggering undefind behavior.
The analysis is as follows: in this snippet
https://gitlab.gnome.org/GNOME/gdk-pixbuf/blob/master/gdk-pixbuf/io-jpeg.c#L581
we have a variable (cinfo
) which declared local to the function where the setjmp is called. This variable is written into after the setjmp (line 596) and read again after the longjmp (line 586). Since the object nor any of its subobjects is declared volatile
, its status after the longjmp is indeterminate, and the read causes undefined behavior (cf. man 3 longjmp and paragraph §7.13.2.1.3 of www.open-std.org/jtc1/sc22/wg14/www/docs/n2346.pdf ).
Unfortunately one cannot simply mark cinfo
as volatile
-- the libjpeg's API don't want pointer-to-volatile-whatever (and casting volatile
away and then touching the resulting object is undefined behavior again).
A very simple workaround is to declare cinfo
(as well as any other non-volatile
object touched after the longjmp) in a helper function, and pass them as a parameters to the function that does the actual work.
This is what happened in Qt here https://codereview.qt-project.org/c/qt/qtbase/+/276244/5/src/plugins/imageformats/jpeg/qjpeghandler.cpp#729 as well as in libjpeg-turbo's own example code, which is likely the "root cause" of this similar code present everywhere https://github.com/libjpeg-turbo/libjpeg-turbo/commit/410c028f3396d1fa9bcc72608079ff4d3d76b03e .
I don't think there's any compiler or tool in the planet failing on this UB (or using it for malicious purpose) so this shouldn't be a really important issue.
Thanks for reading.