Move token buffers off the stack (Issue #117)

This commit is contained in:
Michael R Sweet 2025-04-04 21:20:23 -04:00
parent fe755eac3d
commit 0bd9edc845
No known key found for this signature in database
GPG Key ID: BE67C75EC81F3244
4 changed files with 170 additions and 35 deletions

View File

@ -110,6 +110,8 @@ pdfioFileClose(pdfio_file_t *pdf) // I - PDF file
{ {
bool ret = true; // Return value bool ret = true; // Return value
size_t i; // Looping var size_t i; // Looping var
_pdfio_strbuf_t *current, // Current string buffer
*next; // Next string buffer
// Range check input // Range check input
@ -152,6 +154,12 @@ pdfioFileClose(pdfio_file_t *pdf) // I - PDF file
free(pdf->strings[i]); free(pdf->strings[i]);
free(pdf->strings); free(pdf->strings);
for (current = pdf->strbuffers; current; current = next)
{
next = current->next;
free(current);
}
free(pdf); free(pdf);
return (ret); return (ret);

View File

@ -225,6 +225,14 @@ typedef struct _pdfio_objmap_s // PDF object map
size_t src_number; // Source object number size_t src_number; // Source object number
} _pdfio_objmap_t; } _pdfio_objmap_t;
typedef struct _pdfio_strbuf_s // PDF string buffer
{
struct _pdfio_strbuf_s *next; // Next string buffer
bool bufused; // Is this string buffer being used?
char buffer[PDFIO_MAX_STRING + 32];
// String buffer
} _pdfio_strbuf_t;
struct _pdfio_file_s // PDF file structure struct _pdfio_file_s // PDF file structure
{ {
char *filename; // Filename char *filename; // Filename
@ -284,6 +292,7 @@ struct _pdfio_file_s // PDF file structure
size_t num_strings, // Number of strings size_t num_strings, // Number of strings
alloc_strings; // Allocated strings alloc_strings; // Allocated strings
char **strings; // Nul-terminated strings char **strings; // Nul-terminated strings
_pdfio_strbuf_t *strbuffers; // String buffers
}; };
struct _pdfio_obj_s // Object struct _pdfio_obj_s // Object
@ -391,6 +400,8 @@ extern bool _pdfioObjWriteHeader(pdfio_obj_t *obj) _PDFIO_INTERNAL;
extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_obj_t *length_obj, size_t cbsize, pdfio_filter_t compression) _PDFIO_INTERNAL; extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_obj_t *length_obj, size_t cbsize, pdfio_filter_t compression) _PDFIO_INTERNAL;
extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL; extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL;
extern char *_pdfioStringAllocBuffer(pdfio_file_t *pdf);
extern void _pdfioStringFreeBuffer(pdfio_file_t *pdf, char *buffer);
extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL; extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
extern void _pdfioTokenClear(_pdfio_token_t *tb) _PDFIO_INTERNAL; extern void _pdfioTokenClear(_pdfio_token_t *tb) _PDFIO_INTERNAL;

View File

@ -532,6 +532,41 @@ _pdfio_vsnprintf(pdfio_file_t *pdf, // I - PDF file
} }
//
// '_pdfioStringAllocBuffer()' - Allocate a string buffer.
//
char * // O - Buffer or `NULL` on error
_pdfioStringAllocBuffer(
pdfio_file_t *pdf) // I - PDF file
{
_pdfio_strbuf_t *current; // Current string buffer
// See if we have an available string buffer...
for (current = pdf->strbuffers; current; current = current->next)
{
if (!current->bufused)
{
current->bufused = true;
return (current->buffer);
}
}
// Didn't find one, allocate a new one...
if ((current = calloc(1, sizeof(_pdfio_strbuf_t))) == NULL)
return (NULL);
// Add to the linked list of string buffers...
current->next = pdf->strbuffers;
current->bufused = true;
pdf->strbuffers = current;
return (current->buffer);
}
// //
// 'pdfioStringCreate()' - Create a durable literal string. // 'pdfioStringCreate()' - Create a durable literal string.
// //
@ -642,6 +677,29 @@ pdfioStringCreatef(
} }
//
// '_pdfioStringFreeBuffer()' - Free a string buffer.
//
void
_pdfioStringFreeBuffer(
pdfio_file_t *pdf, // I - PDF file
char *buffer) // I - String buffer
{
_pdfio_strbuf_t *current; // Current string buffer
for (current = pdf->strbuffers; current; current = current->next)
{
if (current->buffer == buffer)
{
current->bufused = false;
break;
}
}
}
// //
// '_pdfioStringIsAllocated()' - Check whether a string has been allocated. // '_pdfioStringIsAllocated()' - Check whether a string has been allocated.
// //

View File

@ -125,8 +125,7 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
_pdfio_crypto_ctx_t ctx; // Decryption context _pdfio_crypto_ctx_t ctx; // Decryption context
_pdfio_crypto_cb_t cb; // Decryption callback _pdfio_crypto_cb_t cb; // Decryption callback
size_t ivlen; // Number of initialization vector bytes size_t ivlen; // Number of initialization vector bytes
uint8_t temp[PDFIO_MAX_STRING + 32]; uint8_t *temp = NULL; // Temporary buffer for decryption
// Temporary buffer for decryption
size_t templen; // Number of actual data bytes size_t templen; // Number of actual data bytes
time_t timeval; // Date/time value time_t timeval; // Date/time value
@ -153,11 +152,16 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
case PDFIO_VALTYPE_BINARY : case PDFIO_VALTYPE_BINARY :
// Decrypt the binary string... // Decrypt the binary string...
if (v->value.binary.datalen > (sizeof(temp) - 32)) if (v->value.binary.datalen > PDFIO_MAX_STRING)
{ {
_pdfioFileError(pdf, "Unable to read encrypted binary string - too long."); _pdfioFileError(pdf, "Unable to read encrypted binary string - too long.");
return (false); return (false);
} }
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL)
{
_pdfioFileError(pdf, "Unable to read encrypted binary string - out of memory.");
return (false);
}
ivlen = v->value.binary.datalen; ivlen = v->value.binary.datalen;
if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL) if ((cb = _pdfioCryptoMakeReader(pdf, obj, &ctx, v->value.binary.data, &ivlen)) == NULL)
@ -172,6 +176,8 @@ _pdfioValueDecrypt(pdfio_file_t *pdf, // I - PDF file
v->value.binary.datalen = templen - temp[templen - 1]; v->value.binary.datalen = templen - temp[templen - 1];
else else
v->value.binary.datalen = templen; v->value.binary.datalen = templen;
_pdfioStringFreeBuffer(pdf, (char *)temp);
break; break;
case PDFIO_VALTYPE_STRING : case PDFIO_VALTYPE_STRING :
@ -301,7 +307,9 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
_pdfio_value_t *v, // I - Value _pdfio_value_t *v, // I - Value
size_t depth) // I - Depth of value size_t depth) // I - Depth of value
{ {
char token[PDFIO_MAX_STRING];// Token buffer _pdfio_value_t *ret = NULL; // Return value
char *token = _pdfioStringAllocBuffer(pdf);
// Token buffer
time_t timeval; // Date/time value time_t timeval; // Date/time value
#ifdef DEBUG #ifdef DEBUG
static const char * const valtypes[] = static const char * const valtypes[] =
@ -323,8 +331,11 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
PDFIO_DEBUG("_pdfioValueRead(pdf=%p, obj=%p, v=%p)\n", pdf, obj, v); PDFIO_DEBUG("_pdfioValueRead(pdf=%p, obj=%p, v=%p)\n", pdf, obj, v);
if (!_pdfioTokenGet(tb, token, sizeof(token))) if (!token)
return (NULL); goto done;
if (!_pdfioTokenGet(tb, token, PDFIO_MAX_STRING))
goto done;
if (!strcmp(token, "[")) if (!strcmp(token, "["))
{ {
@ -332,12 +343,14 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
if (depth >= PDFIO_MAX_DEPTH) if (depth >= PDFIO_MAX_DEPTH)
{ {
_pdfioFileError(pdf, "Too many nested arrays."); _pdfioFileError(pdf, "Too many nested arrays.");
return (NULL); goto done;
} }
v->type = PDFIO_VALTYPE_ARRAY; v->type = PDFIO_VALTYPE_ARRAY;
if ((v->value.array = _pdfioArrayRead(pdf, obj, tb, depth + 1)) == NULL) if ((v->value.array = _pdfioArrayRead(pdf, obj, tb, depth + 1)) == NULL)
return (NULL); goto done;
ret = v;
} }
else if (!strcmp(token, "<<")) else if (!strcmp(token, "<<"))
{ {
@ -345,29 +358,34 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
if (depth >= PDFIO_MAX_DEPTH) if (depth >= PDFIO_MAX_DEPTH)
{ {
_pdfioFileError(pdf, "Too many nested dictionaries."); _pdfioFileError(pdf, "Too many nested dictionaries.");
return (NULL); goto done;
} }
v->type = PDFIO_VALTYPE_DICT; v->type = PDFIO_VALTYPE_DICT;
if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL) if ((v->value.dict = _pdfioDictRead(pdf, obj, tb, depth + 1)) == NULL)
return (NULL); goto done;
ret = v;
} }
else if ((timeval = get_date_time(token + 1)) != 0) else if ((timeval = get_date_time(token + 1)) != 0)
{ {
v->type = PDFIO_VALTYPE_DATE; v->type = PDFIO_VALTYPE_DATE;
v->value.date = timeval; v->value.date = timeval;
ret = v;
} }
else if (token[0] == '(') else if (token[0] == '(')
{ {
// String // String
v->type = PDFIO_VALTYPE_STRING; v->type = PDFIO_VALTYPE_STRING;
v->value.string = pdfioStringCreate(pdf, token + 1); v->value.string = pdfioStringCreate(pdf, token + 1);
ret = v;
} }
else if (token[0] == '/') else if (token[0] == '/')
{ {
// Name // Name
v->type = PDFIO_VALTYPE_NAME; v->type = PDFIO_VALTYPE_NAME;
v->value.name = pdfioStringCreate(pdf, token + 1); v->value.name = pdfioStringCreate(pdf, token + 1);
ret = v;
} }
else if (token[0] == '<') else if (token[0] == '<')
{ {
@ -380,7 +398,7 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
if ((v->value.binary.data = (unsigned char *)malloc(v->value.binary.datalen)) == NULL) if ((v->value.binary.data = (unsigned char *)malloc(v->value.binary.datalen)) == NULL)
{ {
_pdfioFileError(pdf, "Out of memory for hex string."); _pdfioFileError(pdf, "Out of memory for hex string.");
return (NULL); goto done;
} }
// Convert hex to binary... // Convert hex to binary...
@ -407,6 +425,8 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
*dataptr++ = (unsigned char)d; *dataptr++ = (unsigned char)d;
} }
ret = v;
} }
else if (strchr("0123456789-+.", token[0]) != NULL) else if (strchr("0123456789-+.", token[0]) != NULL)
{ {
@ -494,7 +514,8 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
PDFIO_DEBUG("_pdfioValueRead: Returning indirect value %lu %u R.\n", (unsigned long)v->value.indirect.number, v->value.indirect.generation); PDFIO_DEBUG("_pdfioValueRead: Returning indirect value %lu %u R.\n", (unsigned long)v->value.indirect.number, v->value.indirect.generation);
return (v); ret = v;
goto done;
} }
} }
} }
@ -502,27 +523,41 @@ _pdfioValueRead(pdfio_file_t *pdf, // I - PDF file
// If we get here, we have a number... // If we get here, we have a number...
v->type = PDFIO_VALTYPE_NUMBER; v->type = PDFIO_VALTYPE_NUMBER;
v->value.number = _pdfio_strtod(pdf, token); v->value.number = _pdfio_strtod(pdf, token);
ret = v;
} }
else if (!strcmp(token, "true") || !strcmp(token, "false")) else if (!strcmp(token, "true") || !strcmp(token, "false"))
{ {
// Boolean value // Boolean value
v->type = PDFIO_VALTYPE_BOOLEAN; v->type = PDFIO_VALTYPE_BOOLEAN;
v->value.boolean = !strcmp(token, "true"); v->value.boolean = !strcmp(token, "true");
ret = v;
} }
else if (!strcmp(token, "null")) else if (!strcmp(token, "null"))
{ {
// null value // null value
v->type = PDFIO_VALTYPE_NULL; v->type = PDFIO_VALTYPE_NULL;
ret = v;
} }
else else
{ {
_pdfioFileError(pdf, "Unexpected '%s' token seen.", token); _pdfioFileError(pdf, "Unexpected '%s' token seen.", token);
return (NULL);
} }
PDFIO_DEBUG("_pdfioValueRead: Returning %s value.\n", valtypes[v->type]); done:
return (v); if (token)
_pdfioStringFreeBuffer(pdf, token);
if (ret)
{
PDFIO_DEBUG("_pdfioValueRead: Returning %s value.\n", valtypes[ret->type]);
return (ret);
}
else
{
PDFIO_DEBUG("_pdfioValueRead: Returning NULL.\n");
return (NULL);
}
} }
@ -547,9 +582,10 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
case PDFIO_VALTYPE_BINARY : case PDFIO_VALTYPE_BINARY :
{ {
size_t databytes; // Bytes to write size_t databytes; // Bytes to write
uint8_t temp[PDFIO_MAX_STRING + 32], uint8_t *temp = NULL, // Temporary buffer for encryption
// Temporary buffer for encryption
*dataptr; // Pointer into data *dataptr; // Pointer into data
bool ret = false; // Return value
if (obj && pdf->encryption) if (obj && pdf->encryption)
{ {
@ -558,11 +594,16 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
_pdfio_crypto_cb_t cb; // Encryption callback _pdfio_crypto_cb_t cb; // Encryption callback
size_t ivlen; // Number of initialization vector bytes size_t ivlen; // Number of initialization vector bytes
if (v->value.binary.datalen > (sizeof(temp) - 32)) if (v->value.binary.datalen > PDFIO_MAX_STRING)
{ {
_pdfioFileError(pdf, "Unable to write encrypted binary string - too long."); _pdfioFileError(pdf, "Unable to write encrypted binary string - too long.");
return (false); return (false);
} }
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL)
{
_pdfioFileError(pdf, "Unable to write encrypted binary string - out of memory.");
return (false);
}
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen); cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
databytes = (cb)(&ctx, temp + ivlen, v->value.binary.data, v->value.binary.datalen) + ivlen; databytes = (cb)(&ctx, temp + ivlen, v->value.binary.data, v->value.binary.datalen) + ivlen;
@ -575,18 +616,25 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
} }
if (!_pdfioFilePuts(pdf, "<")) if (!_pdfioFilePuts(pdf, "<"))
return (false); goto bindone;
for (; databytes > 1; databytes -= 2, dataptr += 2) for (; databytes > 1; databytes -= 2, dataptr += 2)
{ {
if (!_pdfioFilePrintf(pdf, "%02X%02X", dataptr[0], dataptr[1])) if (!_pdfioFilePrintf(pdf, "%02X%02X", dataptr[0], dataptr[1]))
return (false); goto bindone;
} }
if (databytes > 0) if (databytes > 0 && !_pdfioFilePrintf(pdf, "%02X", dataptr[0]))
return (_pdfioFilePrintf(pdf, "%02X>", dataptr[0])); goto bindone;
else
return (_pdfioFilePuts(pdf, ">")); ret = _pdfioFilePuts(pdf, ">");
bindone:
if (temp)
_pdfioStringFreeBuffer(pdf, (char *)temp);
return (ret);
} }
case PDFIO_VALTYPE_BOOLEAN : case PDFIO_VALTYPE_BOOLEAN :
@ -611,8 +659,7 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
if (obj && pdf->encryption) if (obj && pdf->encryption)
{ {
// Write encrypted string... // Write encrypted string...
uint8_t temp[PDFIO_MAX_STRING + 32], uint8_t temp[64], // Encrypted bytes
// Encrypted bytes
*tempptr; // Pointer into encrypted bytes *tempptr; // Pointer into encrypted bytes
_pdfio_crypto_ctx_t ctx; // Encryption context _pdfio_crypto_ctx_t ctx; // Encryption context
_pdfio_crypto_cb_t cb; // Encryption callback _pdfio_crypto_cb_t cb; // Encryption callback
@ -663,8 +710,7 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
if (obj && pdf->encryption) if (obj && pdf->encryption)
{ {
// Write encrypted string... // Write encrypted string...
uint8_t temp[PDFIO_MAX_STRING + 32], uint8_t *temp = NULL, // Encrypted bytes
// Encrypted bytes
*tempptr; // Pointer into encrypted bytes *tempptr; // Pointer into encrypted bytes
_pdfio_crypto_ctx_t ctx; // Encryption context _pdfio_crypto_ctx_t ctx; // Encryption context
_pdfio_crypto_cb_t cb; // Encryption callback _pdfio_crypto_cb_t cb; // Encryption callback
@ -672,29 +718,41 @@ _pdfioValueWrite(pdfio_file_t *pdf, // I - PDF file
// Length of value // Length of value
ivlen, // Number of initialization vector bytes ivlen, // Number of initialization vector bytes
tempbytes; // Number of output bytes tempbytes; // Number of output bytes
bool ret = false; // Return value
if (len > (sizeof(temp) - 32)) if (len > PDFIO_MAX_STRING)
{ {
_pdfioFileError(pdf, "Unable to write encrypted string - too long."); _pdfioFileError(pdf, "Unable to write encrypted string - too long.");
return (false); return (false);
} }
else if ((temp = (uint8_t *)_pdfioStringAllocBuffer(pdf)) == NULL)
{
_pdfioFileError(pdf, "Unable to write encrypted string - out of memory.");
return (false);
}
cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen); cb = _pdfioCryptoMakeWriter(pdf, obj, &ctx, temp, &ivlen);
tempbytes = (cb)(&ctx, temp + ivlen, (const uint8_t *)v->value.string, len) + ivlen; tempbytes = (cb)(&ctx, temp + ivlen, (const uint8_t *)v->value.string, len) + ivlen;
if (!_pdfioFilePuts(pdf, "<")) if (!_pdfioFilePuts(pdf, "<"))
return (false); goto strdone;
for (tempptr = temp; tempbytes > 1; tempbytes -= 2, tempptr += 2) for (tempptr = temp; tempbytes > 1; tempbytes -= 2, tempptr += 2)
{ {
if (!_pdfioFilePrintf(pdf, "%02X%02X", tempptr[0], tempptr[1])) if (!_pdfioFilePrintf(pdf, "%02X%02X", tempptr[0], tempptr[1]))
return (false); goto strdone;
} }
if (tempbytes > 0) if (tempbytes > 0 && !_pdfioFilePrintf(pdf, "%02X", *tempptr))
return (_pdfioFilePrintf(pdf, "%02X>", *tempptr)); goto strdone;
else
return (_pdfioFilePuts(pdf, ">")); ret = _pdfioFilePuts(pdf, ">");
strdone :
_pdfioStringFreeBuffer(pdf, (char *)temp);
return (ret);
} }
else else
{ {