Skip to content

Commit

Permalink
check for write behind file end in TinyTIFFWriter: fixes issue #23
Browse files Browse the repository at this point in the history
  • Loading branch information
jkriege2 committed May 8, 2024
1 parent 77a86c0 commit 0350bea
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 21 deletions.
49 changes: 29 additions & 20 deletions src/tinytiffwriter.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
#ifdef TINYTIFF_USE_WINAPI_FOR_FILEIO
# include <windows.h>
# warning COMPILING TinyTIFFWriter with WinAPI
# define TinyTIFFWriter_POSTYPE DWORD
#else
# define TinyTIFFWriter_POSTYPE fpos_t
#endif // TINYTIFF_USE_WINAPI_FOR_FILEIO


Expand All @@ -61,6 +64,7 @@ int TinyTIFFWriter_getMaxDescriptionTextSize() {
return TINYTIFFWRITER_DESCRIPTION_SIZE;
}


/** \defgroup tinytiffwriter_internal TinyTIFFWriter: Internal functions
* \ingroup tinytiffwriter */

Expand Down Expand Up @@ -212,7 +216,7 @@ static size_t TinyTIFFWriter_fwrite(const void * ptr, size_t size, size_t count,
\ingroup tinytiffwriter_internal
\internal
*/
static long int TinyTIFFWriter_ftell ( TinyTIFFWriterFile * tiff ) {
static long long TinyTIFFWriter_ftell ( TinyTIFFWriterFile * tiff ) {
#ifdef TINYTIFF_USE_WINAPI_FOR_FILEIO
DWORD dwPtr = SetFilePointer( tiff->hFile,
0,
Expand All @@ -224,6 +228,18 @@ DWORD dwPtr = SetFilePointer( tiff->hFile,
#endif
}

int TinyTIFFWriter_fgetpos(TinyTIFFWriterFile* tiff, TinyTIFFWriter_POSTYPE* pos) {
#ifdef TINYTIFF_USE_WINAPI_FOR_FILEIO
*pos= SetFilePointer( tiff->hFile,
0,
NULL,
FILE_CURRENT );
return 0;
#else
return fgetpos(tiff->file, pos);
#endif // TINYTIFF_USE_WINAPI_FOR_FILEIO
}


/*! \brief wrapper around fseek
\ingroup tinytiffwriter_internal
Expand All @@ -243,25 +259,6 @@ static int TinyTIFFWriter_fseek_set(TinyTIFFWriterFile* tiff, size_t offset) {
#endif // TINYTIFF_USE_WINAPI_FOR_FILEIO
}

#ifdef TinyTIFFWriter_fseek_cur // Silence "unused" warning
/*! \brief wrapper around fseek(..., FILE_CURRENT)
\ingroup tinytiffwriter_internal
\internal
*/
static int TinyTIFFWriter_fseek_cur(TinyTIFFWriterFile* tiff, size_t offset) {
#ifdef TINYTIFF_USE_WINAPI_FOR_FILEIO
DWORD res = SetFilePointer (tiff->hFile,
offset,
NULL,
FILE_CURRENT);


return res;
#else
return fseek(tiff->file, (long)offset, SEEK_CUR);
#endif // TINYTIFF_USE_WINAPI_FOR_FILEIO
}
#endif

/*! \brief calculates the number of channels, covered by the photometric interpretation. If samples is larger than this, the difference are extraSamples!
\ingroup tinytiffwriter_internal
Expand Down Expand Up @@ -901,6 +898,7 @@ int TinyTIFFWriter_writeImageMultiSample(TinyTIFFWriterFile *tiff, const void *d
return TINYTIFF_FALSE;
}
const long pos=TinyTIFFWriter_ftell(tiff);

int hsize=TIFF_HEADER_SIZE;
#ifdef TINYTIFF_WRITE_COMMENTS
if (tiff->frames<=0) {
Expand Down Expand Up @@ -973,6 +971,17 @@ int TinyTIFFWriter_writeImageMultiSample(TinyTIFFWriterFile *tiff, const void *d
}
TinyTIFFWriter_writeIFDEntrySHORT(tiff, TIFF_FIELD_SAMPLEFORMAT, tiff->sampleformat);
TinyTIFFWriter_endIFD(tiff, hsize);

TinyTIFFWriter_POSTYPE datapos=0; TinyTIFFWriter_fgetpos(tiff, &datapos);
const TinyTIFFWriter_POSTYPE data_size_expected=tiff->width*tiff->height*tiff->samples*(tiff->bitspersample/8);
const TinyTIFFWriter_POSTYPE expected_endpos=datapos+data_size_expected;
const TinyTIFFWriter_POSTYPE max_endpos=(((TinyTIFFWriter_POSTYPE)0xFFFFFFFF)-(TinyTIFFWriter_POSTYPE)1024);
if (expected_endpos>=max_endpos) {
tiff->wasError=TINYTIFF_TRUE;
TINYTIFF_SET_LAST_ERROR(tiff, "trying to write behind end of file in TinyTIFFWriter_writeImage() (i.e. too many of a too big frame)\0");
return TINYTIFF_FALSE;
}

if (inputOrganisation==outputOrganization) {
TinyTIFFWriter_fwrite(data, tiff->width*tiff->height*tiff->samples*(tiff->bitspersample/8), 1, tiff);
} else if (inputOrganisation==TinyTIFF_Interleaved && outputOrganization==TinyTIFF_Separate) {
Expand Down
2 changes: 1 addition & 1 deletion tests/tinytiffreader_test/tinytiffreader_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <string>
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
Expand Down
95 changes: 95 additions & 0 deletions tests/tinytiffwriter_test/tinytiffwriter_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,94 @@ void performWriteTest(const std::string& name, const char* filename, const T* im
}
}

template <class T>
void performWriteTest_ExpectedToFail(const std::string& name, const char* filename, const T* imagedata, size_t WIDTH, size_t HEIGHT, size_t SAMPLES, TinyTIFFWriterSampleInterpretation interpret, std::vector<TestResult>& test_results, TinyTIFFSampleLayout inputOrg=TinyTIFF_Chunky, TinyTIFFSampleLayout outputOrg=TinyTIFF_Chunky) {
const size_t bits=sizeof(T)*8;
std::string desc=std::to_string(WIDTH)+"x"+std::to_string(HEIGHT)+"pix/"+std::to_string(bits)+"bit/"+std::to_string(SAMPLES)+"ch/1frame";
if (inputOrg==TinyTIFF_Chunky && outputOrg==TinyTIFF_Chunky) desc+="/CHUNKY_FROM_CHUNKY";
if (inputOrg==TinyTIFF_Chunky && outputOrg==TinyTIFF_Planar) desc+="/PLANAR_FROM_CHUNKY";
if (inputOrg==TinyTIFF_Planar && outputOrg==TinyTIFF_Chunky) desc+="/CHUNKY_FROM_PLANAR";
if (inputOrg==TinyTIFF_Planar && outputOrg==TinyTIFF_Planar) desc+="/PLANAR_FROM_PLANAR";
test_results.emplace_back();
test_results.back().name=name+" ["+desc+", "+std::string(filename)+"]";
test_results.back().success=true;
std::cout<<"\n\n*****************************************************************************\n";
std::cout<<"* "<<test_results.back().name<<"\n";
HighResTimer timer;
timer.start();
TinyTIFFWriterFile* tiff = TinyTIFFWriter_open(filename, bits, TinyTIFF_SampleFormatFromType<T>().format, SAMPLES, WIDTH,HEIGHT, interpret);
if (tiff) {
int res;
res=TinyTIFFWriter_writeImageMultiSample(tiff, imagedata, inputOrg, outputOrg);
if (res!=TINYTIFF_FALSE) {
test_results.back().success=false;
TESTFAIL("could not prevent writing image data into '"<<filename<<"'!", test_results.back())
} else {
std::cout<<" --> WRITING GENERATED ERROR MESSAGE:"<<TinyTIFFWriter_getLastError(tiff)<<"\n";
}
TinyTIFFWriter_close(tiff);
test_results.back().duration_ms=timer.get_time()/1e3;
test_results.back().numImages=1;
std::string description_out;
} else {
TESTFAIL("could not open '"<<filename<<"' for writing!", test_results.back())
test_results.back().success=false;
}
if (test_results.back().success) {
std::cout<<"* ==> SUCCESSFUL, duration="<<test_results.back().duration_ms<<"ms\n";
} else {
std::cout<<"* ==> FAILED\n";
}
}


template <class T>
void performMultiFrameWriteTest_ExpectedToFail(const std::string& name, const char* filename, const T* imagedata, const T* imagedatai, size_t WIDTH, size_t HEIGHT, size_t SAMPLES, size_t FRAMES, TinyTIFFWriterSampleInterpretation interpret, std::vector<TestResult>& test_results, TinyTIFFSampleLayout inputOrg=TinyTIFF_Chunky, TinyTIFFSampleLayout outputOrg=TinyTIFF_Chunky) {
const size_t bits=sizeof(T)*8;
std::string desc=std::to_string(WIDTH)+"x"+std::to_string(HEIGHT)+"pix/"+std::to_string(bits)+"bit/"+std::to_string(SAMPLES)+"ch/1frame";
if (inputOrg==TinyTIFF_Chunky && outputOrg==TinyTIFF_Chunky) desc+="/CHUNKY_FROM_CHUNKY";
if (inputOrg==TinyTIFF_Chunky && outputOrg==TinyTIFF_Planar) desc+="/PLANAR_FROM_CHUNKY";
if (inputOrg==TinyTIFF_Planar && outputOrg==TinyTIFF_Chunky) desc+="/CHUNKY_FROM_PLANAR";
if (inputOrg==TinyTIFF_Planar && outputOrg==TinyTIFF_Planar) desc+="/PLANAR_FROM_PLANAR";
test_results.emplace_back();
test_results.back().name=name+" ["+desc+", "+std::string(filename)+"]";
test_results.back().success=true;
std::cout<<"\n\n*****************************************************************************\n";
std::cout<<"* "<<test_results.back().name<<"\n";
HighResTimer timer;
timer.start();
TinyTIFFWriterFile* tiff = TinyTIFFWriter_open(filename, bits, TinyTIFF_SampleFormatFromType<T>().format, SAMPLES, WIDTH,HEIGHT, interpret);
if (tiff) {
int res;
size_t f=0;
for (; f<FRAMES; f++) {
if (f%2==0) res=TinyTIFFWriter_writeImageMultiSample(tiff, imagedata, inputOrg, outputOrg);
else res=TinyTIFFWriter_writeImageMultiSample(tiff, imagedatai, inputOrg, outputOrg);
if (res!=TINYTIFF_TRUE) {
break;
}
}
if (res!=TINYTIFF_FALSE) {
test_results.back().success=false;
TESTFAIL("could not prevent writing image data into '"<<filename<<"'!", test_results.back())
} else {
std::cout<<" --> WRITING GENERATED ERROR MESSAGE for frame "<<(f+1)<<"/"<<FRAMES<<":"<<TinyTIFFWriter_getLastError(tiff)<<"\n";
}
TinyTIFFWriter_close(tiff);
test_results.back().duration_ms=timer.get_time()/1e3;
test_results.back().numImages=1;
std::string description_out;
} else {
TESTFAIL("could not open '"<<filename<<"' for writing!", test_results.back())
test_results.back().success=false;
}
if (test_results.back().success) {
std::cout<<"* ==> SUCCESSFUL, duration="<<test_results.back().duration_ms<<"ms\n";
} else {
std::cout<<"* ==> FAILED\n";
}
}

template <class T>
void performMultiFrameWriteTest(const std::string& name, const char* filename, const T* imagedata, const T* imagedatai, size_t WIDTH, size_t HEIGHT, size_t SAMPLES, size_t FRAMES, TinyTIFFWriterSampleInterpretation interpret, std::vector<TestResult>& test_results, TinyTIFFSampleLayout inputOrg=TinyTIFF_Chunky, TinyTIFFSampleLayout outputOrg=TinyTIFF_Chunky) {
const size_t bits=sizeof(T)*8;
Expand Down Expand Up @@ -324,6 +412,13 @@ int main(int argc, char *argv[]) {

performWriteTest("WRITING 64-Bit UINT GREY TIFF", "test64.tif", image64.data(), WIDTH, HEIGHT, 1, TinyTIFFWriter_Greyscale, test_results);
if (quicktest==TINYTIFF_FALSE) performMultiFrameWriteTest("WRITING 64-Bit UINT GREY TIFF", "test64m.tif", image64.data(), image64i.data(), WIDTH, HEIGHT, 1, NUMFRAMES, TinyTIFFWriter_Greyscale, test_results);
if (quicktest==TINYTIFF_FALSE) {
const size_t WIDTH_too_many=8000;
const size_t HEIGHT_too_many=4000;
const std::vector<uint64_t> image64_too_many(WIDTH_too_many*HEIGHT_too_many, 0);
const size_t too_many_frames=((size_t)0xFFFFFFFF)/((size_t)(WIDTH_too_many*HEIGHT_too_many*sizeof(uint64_t)))*8;
performMultiFrameWriteTest_ExpectedToFail("WRITING TOO MANY 64-Bit UINT GREY TIFF", "test64m_toomany.tif", image64_too_many.data(), image64_too_many.data(), WIDTH_too_many, HEIGHT_too_many, 1, too_many_frames, TinyTIFFWriter_Greyscale, test_results);
}

performWriteTest("WRITING 32-Bit FLOAT GREY TIFF", "testf.tif", imagef.data(), WIDTH, HEIGHT, 1, TinyTIFFWriter_Greyscale, test_results);
if (quicktest==TINYTIFF_FALSE) performMultiFrameWriteTest("WRITING 32-Bit FLOAT GREY TIFF", "testfm.tif", imagef.data(), imagefi.data(), WIDTH, HEIGHT, 1, NUMFRAMES, TinyTIFFWriter_Greyscale, test_results);
Expand Down

0 comments on commit 0350bea

Please sign in to comment.