BUG: fixed undefined behaviour with corrupted JPEG file#2933
BUG: fixed undefined behaviour with corrupted JPEG file#2933hjmjohnson merged 1 commit intoInsightSoftwareConsortium:masterfrom
Conversation
ad226df to
7e80aae
Compare
|
Have not followed closely the issue/source of the problem, but 💯 to all involved for investigating this and proposing a fix. Can the image file that demonstrates the issue or an appropriate one (i.e. having some compatible license) be added to the test images and be provided to the test as another case so that to ensure that the issue does not leak back into the code ? |
|
S. link to the file #2928 |
|
A warning: |
Here it is: issakomi#1 |
|
@Hconk hope it is OK to use the image you shared. Let us know otherwise. |
|
Thank you, i have merged the test. I am still working on the branch. It is WIP, please don't merge into ITK master just now. The image is interesting. In fact if someone just cut in hex editor parts of a image, JPEG library can survive, i tried to produce corrupted images, there were only warnings. BTW, warnings are unfortunately invisible in current JPEG IO, messages are supressed. This particular image has 2 issues Don't know exactly, maybe the second causes the critical error, not 100% sure. |
|
To demonstrate the bug with setjmp wrapping, Debian 10, GCC 8.3 This program #include <cstdio>
#include <csetjmp>
namespace
{
bool wrap(jmp_buf env)
{
if (setjmp(env))
{
return true;
}
return false;
}
}
int main(int, char**)
{
jmp_buf env;
volatile int x = 0;
// if (wrap(env))
if (setjmp(env))
{
++x;
printf("%d\n", x);
}
longjmp(env, 1);
return 0;
}with with Similar program #include <cstdio>
#include <csetjmp>
namespace
{
bool wrap(jmp_buf env)
{
if (setjmp(env))
{
return true;
}
return false;
}
}
int main(int, char**)
{
jmp_buf env;
volatile int x = 0;
// if (wrap(env))
if (setjmp(env))
{
++x;
if (x <= 5)
{
printf("%d\n", x);
}
else
{
printf("return point 1\n");
return 0;
}
}
longjmp(env, 1);
printf("return point 2\n");
return 0;
}with with prints nothing somehow. |
Yes,it's OK. I hava some similar images, If necessary, I will share it when I have time. |
I found easy way to produce corrupted jpeg file. insert corrupted image hex: |
2889f5c to
eb6bda6
Compare
| reader->SetFileName(argv[1]); | ||
| reader->SetImageIO(io); | ||
|
|
||
| ITK_TRY_EXPECT_NO_EXCEPTION(reader->Update()); |
There was a problem hiding this comment.
@jhlegarreta This particular file doesn't trigger exception, so the test works, other broken files can trigger exception, before entering the scan-lines while loop. Important is to avoid segmentation fault or crash, exception is OK. Just FYI.
There was a problem hiding this comment.
Hats off to the effort to investigate this @issakomi. I cannot investigate as closely. I can only point to a few things:
- I am not sure about the debug/release compilation of the CI builds, so it might well be that the image provided by @Hconk does not trigger any issue in our CI builds. However, many CDash builds are build in release mode, so any (appropriately) corrupted file without this fix should trigger the issue as I understand it.
- If prior to this patch set a given test file was generating a segmentation fault or crash of any nature, then that test file should be added to the test images, and ensure that it does not produce a segfault with this patch set, and is dealt with nicely, either being read if it can be read or generating an exception (and I'd say exception and not warning) saying that it cannot be read. That exception can be tested with the
ITK_TRY_EXPECT_EXCEPTIONmacro. - If the image provided by @Hconk is now being dealt with nicely and can be read without issues, the
ITK_TRY_EXPECT_NO_EXCEPTIONis OK. - Otherwise, I do not see that this patch set adds new exceptions. If any of the existing ones were not being tested, and we would like them to be tested, images triggering them should be added. See here the exceptions that are not being exercised (any line in red is not exercised/tested):
https://open.cdash.org/viewCoverageFile.php?buildid=7620043&fileid=49347999
Hope this casts some light on what is desired to fully test these cases, and to ensure that the behavior is predictable and conforming to the expectations.
There was a problem hiding this comment.
The issue with undefined behavior is fixed, incorrect setjmp implementation caused it. It works in debug, release etc. the same way.
See here the exceptions that are not being exercised (any line in red is not exercised/tested):
https://open.cdash.org/viewCoverageFile.php?buildid=7620043&fileid=49347999
I can give you an image that will trigger exception. This one, for example.
https://drive.google.com/file/d/1zGobe2UkAo1nEYMfEv5IV1TM5bhMYx7G/view?usp=sharing
There was a problem hiding this comment.
OK. Thanks. Then testing the exceptions would be best addressed in a separate PR. I will keep a note and propose a separate PR that uses the shared image (thanks for doing it) as time permits.
| #if (defined JPEGIO_JPEG_MESSAGES && JPEGIO_JPEG_MESSAGES == 1) | ||
| char buffer[JMSG_LENGTH_MAX + 1]; | ||
| (*cinfo->err->format_message)(cinfo, buffer); | ||
| printf("%s\n", buffer); |
There was a problem hiding this comment.
I'd say that printing messages should be done through itkDebugMacro macro calls instead of prints. But have not checked/tested in which circumstances the message should be printed.
There was a problem hiding this comment.
itkDebugMacro is C++ code (std::ostringstream itkmsg), i would prefer to avoid C++ code here in extern "C", it is callback for JPEG library. Also name of function and line number are not informative in particular case.
There was a problem hiding this comment.
But have not checked/tested in which circumstances the message should be printed.
The image used in test:
Corrupt JPEG data: premature end of data segment
Unsupported marker type 0x02
2021-12-12T14:24:25.2286750Z 988: Test command: /home/vsts/work/1/s-build/bin/ITKIOJPEGTestDriver "itkJPEGImageIODegenerateCasesTest" "/home/vsts/work/1/s-build/ExternalData/Modules/IO/JPEG/test/Input/corrupted_image.jpg"
2021-12-12T14:24:25.2287348Z 988: Test timeout computed to be: 1500
2021-12-12T14:24:25.2807228Z 988: Trying reader->Update()
2021-12-12T14:24:25.2878165Z 988: Corrupt JPEG data: premature end of data segment
2021-12-12T14:24:25.2879804Z 988: Unsupported marker type 0x02
2021-12-12T14:24:25.2880768Z 988: WARNING: In /home/vsts/work/1/s/Modules/IO/JPEG/src/itkJPEGImageIO.cxx, line 223
2021-12-12T14:24:25.2882128Z 988: JPEGImageIO (0x564bc75c26b0): JPEG error in the file /home/vsts/work/1/s-build/ExternalData/Modules/IO/JPEG/test/Input/corrupted_image.jpg
2021-12-12T14:24:25.2882707Z 988:
2021-12-12T14:24:25.2882965Z 988: Test finished.
The second (triggers exception) from the post
Corrupt JPEG data: 152 extraneous bytes before marker 0xda
Unsupported marker type 0x02
This images https://drive.google.com/file/d/1zEIEtpDai_FUtChhm1WQR_eUuePbmSVB/view?usp=sharing
doesn't trigger jump, only internal JPEG message
Corrupt JPEG data: premature end of data segment
|
I don't know whether this is ready for review and merge or not. If it is not, please convert it into a draft PR. |
Yes, it is. |
|
Just realized that in class JPEGFileWrapper
{
public:
JPEGFileWrapper(const char * const fname, const char * const openMode)
: m_FilePointer(nullptr)
{
m_FilePointer = fopen(fname, openMode);
}
virtual ~JPEGFileWrapper()
{
if (m_FilePointer != nullptr)
{
fclose(m_FilePointer);
}
}
FILE * m_FilePointer;
};
I still have doubts: do you wish JPEG messages or not. If not, i shall change JPEGIO_JPEG_MESSAGES to 0 Edit: some parts in WriteSlice could be updated too, but probably better in separate PR, this PR is already big. |
|
itkPyBufferMemoryLeakTest with ITK.macOS.Python fails again. It happens with many PRs. Not related. |
dzenanz
left a comment
There was a problem hiding this comment.
LGTM, but since I opened the PR I cannot formally approve it.
hjmjohnson
left a comment
There was a problem hiding this comment.
Approving based on @dzenanz LGTM statement :).
See #2928.