Seg fault reading jpeg in 9.2.2

jpg-bug.zip (2.2 KB)

I just was playing with Python 3.10.7, pip installed VTK 9.2.2 and ran one of our image reader tests. With VTK 9.1, when reading the bad one, Samsung.jpg, I’d see some error messages and get appropriate status, but with 9.2.2 I get a crash, Segmentation fault. I diffed vtkJPEGReader.cxx between the versions and nothing has changed there.

Attached zip contains a short script with three jpgs that read just fine, along with the offending one.

Here’s what I see in VTK 9.1. Can anyone confirm the seg fault in 9.2.2?

Samsung.jpg
2022-12-28 22:03:02.558 (   0.211s) [                ]      vtkJPEGReader.cxx:168    ERR| vtkJPEGReader (0000018D55A18F80): libjpeg could not read file: Samsung.jpg
2022-12-28 22:03:02.587 (   0.241s) [                ]      vtkJPEGReader.cxx:353    ERR| vtkJPEGReader (0000018D55A18F80): libjpeg could not read file: Samsung.jpg
2022-12-28 22:03:02.591 (   0.244s) [                ]       vtkExecutive.cxx:753    ERR| vtkCompositeDataPipeline (0000018D5274E420): Algorithm vtkJPEGReader(0000018D55A18F80) returned failure for request: vtkInformation (0000018D55C47D60)

I cannot reproduce on Linux with Python 3.10.8 with 9.2.2 or what is about to become 9.2.3.

Yeah, I missed OS, sorry. I tried a couple other configs, looks like it’s a Windows issue.

Ubuntu 20.04 Py 3.8   VTK 9.2.2  works
Win 10       Py 3.10  VTK 9.1    works
Win 10       Py 3.8   VTK 9.1    works

Win 10       Py 3.10  VTK 9.2.2  seg fault
Win 10       Py 3.8   VTK 9.2.2  seg fault

I’m building a debug version of 9.2.2 right now, maybe I can get a meaningful stack trace.

Oddly enough, the pointer reported as generating the seg fault changes between runs. I thought it was a null ptr at first, but then noticed it was non-null on a subsequent run, so started watching it and it appears to change each time. I also got the test to complete successfully once, apparently the stray pointer ended up pointing to user space, so it didn’t seg fault that time. Based on this, my initial guess is an uninitialized variable somewhere…

image

What’s the best way to dump this info from a Windows debug session? Pasting stuff copied from the debugger seems pretty unwieldy, I only rarely (maybe once a year) run Visual Studio so I’m completely unfamiliar with any of its capabilities wrt saving this in a form that someone else could grab and make use of…

Also, I couldn’t get VTK to build with Debug, so used RelWithDebInfo and non-debug Win10 Python 3.10.7.

Unhandled exception at 0x00007FFE0129A95B (vtkCommonCore-9.2.dll) in python.exe: 
0xC0000005: Access violation reading location 0x0000000000000030. occurred
|>|vtkCommonCore-9.2.dll!vtkOStrStreamWrapper::~vtkOStrStreamWrapper() Line 39|C++|
|---|---|---|
| |[External Code]||
| |vtkIOImage-9.2.dll!vtk_jpeg_error_exit(jpeg_common_struct * cinfo) Line 56|C++|
| |vtkjpeg-9.2.dll!get_dqt(jpeg_decompress_struct * cinfo) Line 559|C|
| |vtkjpeg-9.2.dll!read_markers(jpeg_decompress_struct * cinfo) Line 1049|C|
| |vtkjpeg-9.2.dll!consume_markers(jpeg_decompress_struct * cinfo) Line 325|C|
| |vtkjpeg-9.2.dll!vtkjpeg_jpeg_consume_input(jpeg_decompress_struct * cinfo) Line 313|C|
| |vtkjpeg-9.2.dll!vtkjpeg_jpeg_read_header(jpeg_decompress_struct * cinfo, unsigned char require_image) Line 263|C|
| |vtkIOImage-9.2.dll!vtkJPEGReader::ExecuteInformation() Line 200|C++|
| |vtkIOImage-9.2.dll!vtkImageReader2::RequestInformation(vtkInformation * __formal, vtkInformationVector * * __formal, vtkInformationVector * outputVector) Line 468|C++|
| |vtkCommonExecutionModel-9.2.dll!vtkImageAlgorithm::ProcessRequest(vtkInformation * request, vtkInformationVector * * inputVector, vtkInformationVector * outputVector) Line 100|C++|
| |vtkCommonExecutionModel-9.2.dll!vtkExecutive::CallAlgorithm(vtkInformation * request, int direction, vtkInformationVector * * inInfo, vtkInformationVector * outInfo) Line 734|C++|
| |vtkCommonExecutionModel-9.2.dll!vtkDemandDrivenPipeline::ExecuteInformation(vtkInformation * request, vtkInformationVector * * inInfoVec, vtkInformationVector * outInfoVec) Line 452|C++|
| |vtkCommonExecutionModel-9.2.dll!vtkStreamingDemandDrivenPipeline::ExecuteInformation(vtkInformation * request, vtkInformationVector * * inInfoVec, vtkInformationVector * outInfoVec) Line 461|C++|
| |vtkCommonExecutionModel-9.2.dll!vtkDemandDrivenPipeline::ProcessRequest(vtkInformation * request, vtkInformationVector * * inInfoVec, vtkInformationVector * outInfoVec) Line 223|C++|
| |vtkCommonExecutionModel-9.2.dll!vtkStreamingDemandDrivenPipeline::ProcessRequest(vtkInformation * request, vtkInformationVector * * inInfoVec, vtkInformationVector * outInfoVec) Line 369|C++|
| |vtkCommonExecutionModel-9.2.dll!vtkStreamingDemandDrivenPipeline::Update(int port, vtkInformationVector * requests) Line 386|C++|
| |vtkCommonExecutionModel.cp310-win_amd64.pyd!PyvtkAlgorithm_Update_s2(_object * self, _object * args) Line 2311|C++|
| |python310.dll!cfunction_call(_object * func, _object * args, _object * kwargs) Line 552|C|

Seems to be a problem with libjpeg itself? I see that there is 2.1.4 available whereas VTK imports 2.1.0. I don’t see anything immediately important in the history of jdmarker.c (where get_dqt lives) though. Does a sanitizer build have any suggestions?

I had not used the sanitizer, so looked at the CMake config. It appears to only support gcc and clang, but I’m using msvc, so processing -D VTK_ENABLE_SANITIZER:BOOL=ON reports:

CMake Warning:
  Manually-specified variables were not used by the project:
    VTK_ENABLE_SANITIZER

Is there something else I need to do, or just outta luck on Windows?

From your stack trace, it looks like the crash occurs in the final line of the vtkOStrStreamWrapper because its ostr pointer has been corrupted:

vtkOStrStreamWrapper::~vtkOStrStreamWrapper()
{
  if (!this->Frozen)
  {
    delete[] this->Result;
  }
  delete &this->ostr;
}

In vtkJPEGReader, the vtkOStrStreamWrapper is used via the vtkErrorWithObjectMacro. I believe the following block of code in vtkJPEGReader::ExecuteInformation() is executed via a longjmp from the libjpeg error handler:

  if (setjmp(jerr.setjmp_buffer))
  {
    // clean up
    jpeg_destroy_decompress(&cinfo);
    // close the file
    if (jerr.fp)
    {
      fclose(jerr.fp);
      // this is not a valid jpeg file
      vtkErrorWithObjectMacro(this, "libjpeg could not read file: " << this->InternalFileName);
    }
    else
    {
      vtkErrorWithObjectMacro(this,
        "libjpeg could not read file from memory buffer: " << (this->MemoryBuffer ? "<ptr>"
                                                                                  : "(null)"));
    }
    return;
  }

Note that the longjmp unwinds the stack from vtk_jpeg_error_exit() back to the setjmp() in vtkJPEGReader::ExecuteInformation(), but this isn’t shown on the stack trace since a longjmp isn’t a function call.

Frankly, I can’t see how anything in libjpeg could be causing corruption of the vtkOStrStreamWrapper object, because all libjpeg calls are done before it is constructed. Seems more likely that the culprit is the vtkOutputWindowDisplayErrorText invocation in vtkErrorWithObjectMacro, since it is the only notable thing that occurs between the creation and destruction of the vtkOStrStreamWrapper.

However, if the segfault is related to vtkOutputWindowDisplayErrorText, then it should be popping up in more places than just vtkJPEGReader