Merge branch 'out-of-memory' into 'master'

tiffcp/tiff2pdf/tiff2ps: enforce maximum malloc size

Closes #153, #84, #116 et #115

See merge request libtiff/libtiff!130
This commit is contained in:
Even Rouault 2020-03-23 18:11:02 +00:00
commit 6c63f17749
6 changed files with 102 additions and 28 deletions

View File

@ -212,6 +212,9 @@ Set document information subject, overrides image image description default.
.BI \-k " keywords"
Set document information keywords.
.TP
.BI \-m " size"
Set memory allocation limit (in MiB). Default is 256MiB. Set to 0 to disable the limit.
.TP
.B \-h
List usage reminder to stderr and exit.
.SH EXAMPLES

View File

@ -160,6 +160,10 @@ options.
Specify the left margin for the output (in inches). This does not affect
the width of the printed image.
.TP
.BI \-M " size"
Set maximum memory allocation size (in MiB). The default is 256MiB.
Set to 0 to disable the limit.
.TP
.B \-m
Where possible render using the
.I imagemask

View File

@ -247,6 +247,10 @@ Note that
.B \-,=
with whitespace immediately following will disable
the special meaning of the `,' entirely. See examples.
.TP
.BI \-m " size"
Set maximum memory allocation size (in MiB). The default is 256MiB.
Set to 0 to disable the limit.
.SH EXAMPLES
The following concatenates two files and writes the result using
.SM LZW

View File

@ -70,6 +70,8 @@ extern int getopt(int argc, char * const argv[], const char *optstring);
#define TIFF_DIR_MAX 65534
#define DEFAULT_MAX_MALLOC (256 * 1024 * 1024)
/* This type is of PDF color spaces. */
typedef enum {
T2P_CS_BILEVEL = 0x01, /* Bilevel, black and white */
@ -176,6 +178,7 @@ typedef struct {
uint16 tiff_orientation;
toff_t tiff_dataoffset;
tsize_t tiff_datasize;
tsize_t tiff_maxdatasize;
uint16 tiff_resunit;
uint16 pdf_centimeters;
uint16 pdf_overrideres;
@ -622,8 +625,11 @@ int main(int argc, char** argv){
while (argv &&
(c = getopt(argc, argv,
"o:q:u:x:y:w:l:r:p:e:c:a:t:s:k:jzndifbhF")) != -1){
"m:o:q:u:x:y:w:l:r:p:e:c:a:t:s:k:jzndifbhF")) != -1){
switch (c) {
case 'm':
t2p->tiff_maxdatasize = (tsize_t)strtoul(optarg, NULL, 0) << 20;
break;
case 'o':
outfilename = optarg;
break;
@ -869,6 +875,7 @@ void tiff2pdf_usage(){
" -s: sets document subject, overrides image image description default",
" -k: sets document keywords",
" -b: set PDF \"Interpolate\" user preference",
" -m: set memory allocation limit (in MiB). set to 0 to disable limit",
" -h: usage",
NULL
};
@ -964,6 +971,7 @@ T2P* t2p_init()
t2p->pdf_defaultpagewidth=612.0;
t2p->pdf_defaultpagelength=792.0;
t2p->pdf_xrefcount=3; /* Catalog, Info, Pages */
t2p->tiff_maxdatasize = DEFAULT_MAX_MALLOC;
return(t2p);
}
@ -5626,6 +5634,13 @@ tsize_t t2p_write_pdf(T2P* t2p, TIFF* input, TIFF* output){
written += t2p_write_pdf_stream_start(output);
streamlen=written;
t2p_read_tiff_size(t2p, input);
if (t2p->tiff_maxdatasize && (t2p->tiff_datasize > t2p->tiff_maxdatasize)) {
TIFFError(TIFF2PDF_MODULE,
"Allocation of " TIFF_UINT64_FORMAT " bytes is forbidden. Limit is " TIFF_UINT64_FORMAT ". Use -m option to change limit",
(uint64)t2p->tiff_datasize, (uint64)t2p->tiff_maxdatasize);
t2p->t2p_error = T2P_ERR_ERROR;
return (0);
}
written += t2p_readwrite_pdf_image(t2p, input, output);
t2p_write_advance_directory(t2p, output);
if(t2p->t2p_error!=T2P_ERR_OK){return(0);}

View File

@ -174,6 +174,12 @@
#define FALSE 0
#endif
#define DEFAULT_MAX_MALLOC (256 * 1024 * 1024)
/* malloc size limit (in bytes)
* disabled when set to 0 */
static tmsize_t maxMalloc = DEFAULT_MAX_MALLOC;
int ascii85 = FALSE; /* use ASCII85 encoding */
int interpolate = TRUE; /* interpolate level2 image */
int level2 = FALSE; /* generate PostScript level 2 */
@ -234,6 +240,20 @@ tsize_t Ascii85EncodeBlock( uint8 * ascii85_p, unsigned f_eod, const uint8 * raw
static void usage(int);
/**
* This custom malloc function enforce a maximum allocation size
*/
static void* limitMalloc(tmsize_t s)
{
if (maxMalloc && (s > maxMalloc)) {
fprintf(stderr, "MemoryLimitError: allocation of " TIFF_UINT64_FORMAT " bytes is forbidden. Limit is " TIFF_UINT64_FORMAT ".\n",
(uint64)s, (uint64)maxMalloc);
fprintf(stderr, " use -M option to change limit.\n");
return NULL;
}
return _TIFFmalloc(s);
}
int
main(int argc, char* argv[])
{
@ -252,8 +272,11 @@ main(int argc, char* argv[])
pageOrientation[0] = '\0';
while ((c = getopt(argc, argv, "b:d:h:H:W:L:i:w:l:o:O:P:C:r:t:acemxyzps1238DT")) != -1)
while ((c = getopt(argc, argv, "b:d:h:H:W:L:M:i:w:l:o:O:P:C:r:t:acemxyzps1238DT")) != -1)
switch (c) {
case 'M':
maxMalloc = (tmsize_t)strtoul(optarg, NULL, 0) << 20;
break;
case 'b':
bottommargin = atof(optarg);
break;
@ -2187,7 +2210,7 @@ PS_Lvl2page(FILE* fd, TIFF* tif, uint32 w, uint32 h)
else
chunk_size = TIFFStripSize(tif);
}
buf_data = (unsigned char *)_TIFFmalloc(chunk_size);
buf_data = (unsigned char *)limitMalloc(chunk_size);
if (!buf_data) {
TIFFError(filename, "Can't alloc %lu bytes for %s.",
(unsigned long) chunk_size, tiled_image ? "tiles" : "strips");
@ -2205,7 +2228,7 @@ PS_Lvl2page(FILE* fd, TIFF* tif, uint32 w, uint32 h)
* 5*chunk_size/4.
*/
ascii85_p = _TIFFmalloc( (chunk_size+(chunk_size/2)) + 8 );
ascii85_p = limitMalloc( (chunk_size+(chunk_size/2)) + 8 );
if ( !ascii85_p ) {
_TIFFfree( buf_data );
@ -2449,7 +2472,7 @@ PSDataColorContig(FILE* fd, TIFF* tif, uint32 w, uint32 h, int nc)
TIFFError(filename, "Inconsistent value of es: %d (samplesperpixel=%u, nc=%d)", es, samplesperpixel, nc);
return;
}
tf_buf = (unsigned char *) _TIFFmalloc(tf_bytesperrow);
tf_buf = (unsigned char *) limitMalloc(tf_bytesperrow);
if (tf_buf == NULL) {
TIFFError(filename, "No space for scanline buffer");
return;
@ -2517,7 +2540,7 @@ PSDataColorSeparate(FILE* fd, TIFF* tif, uint32 w, uint32 h, int nc)
unsigned char *cp, c;
(void) w;
tf_buf = (unsigned char *) _TIFFmalloc(tf_bytesperrow);
tf_buf = (unsigned char *) limitMalloc(tf_bytesperrow);
if (tf_buf == NULL) {
TIFFError(filename, "No space for scanline buffer");
return;
@ -2563,7 +2586,7 @@ PSDataPalette(FILE* fd, TIFF* tif, uint32 w, uint32 h)
return;
}
nc = 3 * (8 / bitspersample);
tf_buf = (unsigned char *) _TIFFmalloc(tf_bytesperrow);
tf_buf = (unsigned char *) limitMalloc(tf_bytesperrow);
if (tf_buf == NULL) {
TIFFError(filename, "No space for scanline buffer");
return;
@ -2628,7 +2651,7 @@ PSDataBW(FILE* fd, TIFF* tif, uint32 w, uint32 h)
#endif
(void) w; (void) h;
tf_buf = (unsigned char *) _TIFFmalloc(stripsize);
tf_buf = (unsigned char *) limitMalloc(stripsize);
if (tf_buf == NULL) {
TIFFError(filename, "No space for scanline buffer");
return;
@ -2648,7 +2671,7 @@ PSDataBW(FILE* fd, TIFF* tif, uint32 w, uint32 h)
* 5*stripsize/4.
*/
ascii85_p = _TIFFmalloc( (stripsize+(stripsize/2)) + 8 );
ascii85_p = limitMalloc( (stripsize+(stripsize/2)) + 8 );
if ( !ascii85_p ) {
_TIFFfree( tf_buf );
@ -2775,7 +2798,7 @@ PSRawDataBW(FILE* fd, TIFF* tif, uint32 w, uint32 h)
bufsize = (uint32) bc[s];
}
tf_buf = (unsigned char*) _TIFFmalloc(bufsize);
tf_buf = (unsigned char*) limitMalloc(bufsize);
if (tf_buf == NULL) {
TIFFError(filename, "No space for strip buffer");
return;
@ -2792,7 +2815,7 @@ PSRawDataBW(FILE* fd, TIFF* tif, uint32 w, uint32 h)
* 5*bufsize/4.
*/
ascii85_p = _TIFFmalloc( (bufsize+(bufsize/2)) + 8 );
ascii85_p = limitMalloc( (bufsize+(bufsize/2)) + 8 );
if ( !ascii85_p ) {
_TIFFfree( tf_buf );
@ -3079,6 +3102,7 @@ char* stuff[] = {
" -i # enable/disable (Nz/0) pixel interpolation (default: enable)",
" -l # set the left margin to # inches",
" -m use \"imagemask\" operator instead of \"image\"",
" -M size set the memory allocation limit in MiB. 0 to disable limit",
" -o # convert directory at file offset # bytes",
" -O file write PostScript to file instead of standard output",
" -p generate regular (non-encapsulated) PostScript",

View File

@ -65,6 +65,12 @@ extern int getopt(int argc, char * const argv[], const char *optstring);
#define TRUE 1
#define FALSE 0
#define DEFAULT_MAX_MALLOC (256 * 1024 * 1024)
/* malloc size limit (in bytes)
* disabled when set to 0 */
static tmsize_t maxMalloc = DEFAULT_MAX_MALLOC;
static int outtiled = -1;
static uint32 tilewidth;
static uint32 tilelength;
@ -94,6 +100,20 @@ static TIFF* bias = NULL;
static int pageNum = 0;
static int pageInSeq = 0;
/**
* This custom malloc function enforce a maximum allocation size
*/
static void* limitMalloc(tmsize_t s)
{
if (maxMalloc && (s > maxMalloc)) {
fprintf(stderr, "MemoryLimitError: allocation of " TIFF_UINT64_FORMAT " bytes is forbidden. Limit is " TIFF_UINT64_FORMAT ".\n",
(uint64)s, (uint64)maxMalloc);
fprintf(stderr, " use -m option to change limit.\n");
return NULL;
}
return _TIFFmalloc(s);
}
static int nextSrcImage (TIFF *tif, char **imageSpec)
/*
seek to the next image specified in *imageSpec
@ -173,8 +193,11 @@ main(int argc, char* argv[])
*mp++ = 'w';
*mp = '\0';
while ((c = getopt(argc, argv, ",:b:c:f:l:o:p:r:w:aistBLMC8x")) != -1)
while ((c = getopt(argc, argv, "m:,:b:c:f:l:o:p:r:w:aistBLMC8x")) != -1)
switch (c) {
case 'm':
maxMalloc = (tmsize_t)strtoul(optarg, NULL, 0) << 20;
break;
case ',':
if (optarg[0] != '=') usage();
comma = optarg[1];
@ -423,6 +446,7 @@ char* stuff[] = {
" -i ignore read errors",
" -b file[,#] bias (dark) monochrome image to be subtracted from all others",
" -,=% use % rather than , to separate image #'s (per Note below)",
" -m size set maximum memory allocation size (MiB). 0 to disable limit.",
"",
" -r # make each strip have no more than # rows",
" -w # set output tile width (pixels)",
@ -859,7 +883,7 @@ DECLAREcpFunc(cpContig2ContigByRow)
tdata_t buf;
uint32 row;
buf = _TIFFmalloc(scanlinesize);
buf = limitMalloc(scanlinesize);
if (!buf)
return 0;
_TIFFmemset(buf, 0, scanlinesize);
@ -933,8 +957,8 @@ DECLAREcpFunc(cpBiasedContig2Contig)
subtractLine = lineSubtractFn (sampleBits);
if (subtractLine) {
uint32 row;
buf = _TIFFmalloc(bufSize);
biasBuf = _TIFFmalloc(bufSize);
buf = limitMalloc(bufSize);
biasBuf = limitMalloc(bufSize);
for (row = 0; row < imagelength; row++) {
if (TIFFReadScanline(in, buf, row, 0) < 0
&& !ignore) {
@ -996,7 +1020,7 @@ bad:
DECLAREcpFunc(cpDecodedStrips)
{
tsize_t stripsize = TIFFStripSize(in);
tdata_t buf = _TIFFmalloc(stripsize);
tdata_t buf = limitMalloc(stripsize);
(void) imagewidth; (void) spp;
if (buf) {
@ -1046,7 +1070,7 @@ DECLAREcpFunc(cpSeparate2SeparateByRow)
tsample_t s;
(void) imagewidth;
buf = _TIFFmalloc(scanlinesize);
buf = limitMalloc(scanlinesize);
if (!buf)
return 0;
_TIFFmemset(buf, 0, scanlinesize);
@ -1097,8 +1121,8 @@ DECLAREcpFunc(cpContig2SeparateByRow)
return 0;
}
inbuf = _TIFFmalloc(scanlinesizein);
outbuf = _TIFFmalloc(scanlinesizeout);
inbuf = limitMalloc(scanlinesizein);
outbuf = limitMalloc(scanlinesizeout);
if (!inbuf || !outbuf)
goto bad;
_TIFFmemset(inbuf, 0, scanlinesizein);
@ -1160,8 +1184,8 @@ DECLAREcpFunc(cpSeparate2ContigByRow)
return 0;
}
inbuf = _TIFFmalloc(scanlinesizein);
outbuf = _TIFFmalloc(scanlinesizeout);
inbuf = limitMalloc(scanlinesizein);
outbuf = limitMalloc(scanlinesizeout);
if (!inbuf || !outbuf)
goto bad;
_TIFFmemset(inbuf, 0, scanlinesizein);
@ -1267,7 +1291,7 @@ cpImage(TIFF* in, TIFF* out, readFunc fin, writeFunc fout,
if (scanlinesize
&& imagelength
&& bytes / (tsize_t)imagelength == scanlinesize) {
buf = _TIFFmalloc(bytes);
buf = limitMalloc(bytes);
if (buf) {
if ((*fin)(in, (uint8*)buf, imagelength,
imagewidth, spp)) {
@ -1315,7 +1339,7 @@ DECLAREreadFunc(readSeparateStripsIntoBuffer)
if (!scanlinesize)
return 0;
scanline = _TIFFmalloc(scanlinesize);
scanline = limitMalloc(scanlinesize);
if (!scanline)
return 0;
_TIFFmemset(scanline, 0, scanlinesize);
@ -1364,7 +1388,7 @@ DECLAREreadFunc(readContigTilesIntoBuffer)
uint32 row;
(void) spp;
tilebuf = _TIFFmalloc(tilesize);
tilebuf = limitMalloc(tilesize);
if (tilebuf == 0)
return 0;
_TIFFmemset(tilebuf, 0, tilesize);
@ -1424,7 +1448,7 @@ DECLAREreadFunc(readSeparateTilesIntoBuffer)
return 0;
}
iskew = imagew - tilew*spp;
tilebuf = _TIFFmalloc(tilesize);
tilebuf = limitMalloc(tilesize);
if (tilebuf == 0)
return 0;
_TIFFmemset(tilebuf, 0, tilesize);
@ -1525,7 +1549,7 @@ DECLAREwriteFunc(writeBufferToSeparateStrips)
tstrip_t strip = 0;
tsample_t s;
obuf = _TIFFmalloc(stripsize);
obuf = limitMalloc(stripsize);
if (obuf == NULL)
return (0);
_TIFFmemset(obuf, 0, stripsize);
@ -1567,7 +1591,7 @@ DECLAREwriteFunc(writeBufferToContigTiles)
(void) spp;
obuf = _TIFFmalloc(TIFFTileSize(out));
obuf = limitMalloc(TIFFTileSize(out));
if (obuf == NULL)
return 0;
_TIFFmemset(obuf, 0, tilesize);
@ -1620,7 +1644,7 @@ DECLAREwriteFunc(writeBufferToSeparateTiles)
uint32 row;
uint16 bps = 0, bytes_per_sample;
obuf = _TIFFmalloc(TIFFTileSize(out));
obuf = limitMalloc(TIFFTileSize(out));
if (obuf == NULL)
return 0;
_TIFFmemset(obuf, 0, tilesize);