[Insight-users] Very strange crashing bug with JPEG input

Zachary Pincus zpincus at stanford.edu
Tue, 17 Feb 2004 22:00:33 -0800


Hello all,

After a lot of debugging, I think I have isolated a crashing bug in  
ITK's JPEG reader.

SUMARRY: If you try create a new ImageFileReader and use the new reader  
to read in a JPEG more than 84 times, the program crashes. The specific  
file being read doesn't matter -- what's important is that the  
ImageFileReader is created, passed a jpeg file name, Update()'d and  
deleted more than 84 times.

Interestingly, if the program that does this is run within GDB, there  
is no error until after 3411 repeats of the same.

This points to a subtle buffer overflow in some shared memory region.  
When GDB is running, memory is laid out differently, so it takes longer  
for some overflows to manifest themselves (I think).

DETAILS: I'm using a CVS checkout of ITK from Sunday. There weren't any  
major purify errors that day, that I noticed. I'm running on OS X  
10.3.2.

Included is some simple test code that creates new FileReader objects  
each loop and opens the file passed in as an argument. The program will  
do fine on my machine with any file type except jpegs, with which the  
afformentioned crash happens. Any jpeg will elicit this behavior. The  
size of the image is immaterial to this crash. The templated pixel type  
doesn't matter either.

If you modify the test code to alternate between two different files  
(e.g. fileReader->SetFileName(argv[1 + i % 2])) , it will still crash  
after the 84th loop, provided both files are jpegs. If one isn't a  
jpeg, it crashes after 168th loop. If you create two file readers each  
loop, it crashes after the 42nd loop. Ditto even if the file readers  
are reading different jpeg files. If one of the two file readers isn't  
reading a jpeg, it takes 84 loops to crash again.

Again, this points to an overflow in some shared buffer that is  
accessed by JPEG readers.

If Update() is not called each loop, there is no crash. If the  
ImageFileReader::Pointer is created outside of the loop's scope (so the  
reader isn't destructed every loop) there is no crash.

If the program is run from within GDB, it takes 3411 loops for the  
crash to occur. The GDB backtrace of the core dump of a crash after 84  
loops outside of GDB and of a crash after 3411 loops within GDB are  
substantially different. I have also attached these backtraces to this  
message, in case anyone can make use of them.

Any thoughts?

Zach Pincus

Department of Biochemistry and Program in Biomedical Informatics
Stanford University School of Medicine


TEST CODE:
//-----------------------------
#include "itkImage.h"
#include "itkImageFileReader.h"

int main(int argc, char **argv){
	for(int i = 0; i < 4000; i++) {
		typedef unsigned char PixelType;
		const unsigned int Dimension = 2;
		typedef itk::Image<PixelType, Dimension> ImageType;
		typedef itk::ImageFileReader<ImageType> ReaderType;
	
		ReaderType::Pointer fileReader = ReaderType::New();
		fileReader->SetFileName(argv[1]);
		fileReader->Update();
	
		std::cout << i << std::endl;
		}
}
//---------------------------------

GDB backtrace of this code run within GDB (crashes after 3411 loops)
------------------------------------
Program received signal EXC_BAD_ACCESS, Could not access memory.
0x9001c878 in fclose ()
(gdb) bt
#0  0x9001c878 in fclose ()
#1  0x010bfb70 in itk::JPEGFileWrapper::~JPEGFileWrapper() ()
#2  0x010bfa28 in itk::JPEGFileWrapper::~JPEGFileWrapper() ()
#3  0x0101bf68 in itk::JPEGImageIO::CanReadFile(char const*) ()
#4  0x01029004 in itk::ImageIOFactory::CreateImageIO(char const*,  
itk::ImageIOFactory::FileModeType) ()
#5  0x000501d4 in itk::ImageFileReader<itk::Image<unsigned char, 2>,  
itk::DefaultConvertPixelTraits<unsigned char>  
 >::GenerateOutputInformation() ()
#6  0x0047c264 in itk::ProcessObject::UpdateOutputInformation() ()
#7  0x00052618 in itk::ImageBase<2>::UpdateOutputInformation() ()
#8  0x0046a17c in itk::DataObject::Update() ()
#9  0x0047be50 in itk::ProcessObject::Update() ()
#10 0x00002a54 in main ()
#11 0x000026d0 in _start (argc=2, argv=0xbffffa60, envp=0xbffffa6c) at  
/SourceCache/Csu/Csu-46/crt.c:267
#12 0x00002544 in start ()


GDB backtrace of a core dump generated by this code run outside GDB  
(crashes after 84 loops)
------------------------------------
#0  0x90042aac in kill ()
#1  0x9009ec5c in abort ()
#2  0x012df9b8 in ?? ()
#3  0x012df9fc in ?? ()
#4  0x9009ec34 in abort ()
#5  0x0127e498 in ?? ()
#6  0x000503e8 in std::vector<std::string, std::allocator<std::string>  
 >::~vector() ()
#7  0x0101e264 in ?? ()
#8  0x00052618 in std::invalid_argument::~invalid_argument() ()
#9  0x0100c17c in ?? ()
#10 0x0101de50 in ?? ()
#11 0x00002a54 in  
itk::InvalidRequestedRegionError::InvalidRequestedRegionError(std:: 
string const&, unsigned) ()
#12 0x000026d0 in itk::DataObjectError::GetDataObject() () at  
/SourceCache/Csu/Csu-46/crt.c:267
#13 0x00002544 in itk::DataObjectError::DataObjectError(std::string  
const&, unsigned) ()