@@ -233,6 +233,8 @@ static const uint8_t *ttf_find_table(const uint8_t *data, size_t data_len,
233233 if (data_len < 12 )
234234 return NULL ;
235235 uint16_t numTables = ttf_be16 (data + 4 );
236+ if (numTables > (data_len - 12 ) / 16 )
237+ numTables = (uint16_t )((data_len - 12 ) / 16 );
236238 for (uint16_t i = 0 ; i < numTables ; i ++ ) {
237239 if ((size_t )(12 + ((size_t )i + 1 ) * 16 ) > data_len )
238240 break ;
@@ -312,6 +314,8 @@ static const uint8_t *ttf_find_cmap_subtable(const uint8_t *cmap,
312314 if (!cmap || cmap_len < 4 )
313315 return NULL ;
314316 uint16_t numTables = ttf_be16 (cmap + 2 );
317+ if (numTables > (cmap_len - 4 ) / 8 )
318+ numTables = (uint16_t )((cmap_len - 4 ) / 8 );
315319 const uint8_t * best_subtable = NULL ;
316320 int best_priority = -1 ;
317321
@@ -323,7 +327,7 @@ static const uint8_t *ttf_find_cmap_subtable(const uint8_t *cmap,
323327 uint16_t platformID = ttf_be16 (rec );
324328 uint16_t platEncID = ttf_be16 (rec + 2 );
325329 uint32_t subtable_offset = ttf_be32 (rec + 4 );
326- if (subtable_offset + 4 > cmap_len )
330+ if (( size_t ) subtable_offset + 4 > cmap_len )
327331 continue ;
328332 const uint8_t * sub = cmap + subtable_offset ;
329333 uint16_t fmt = ttf_be16 (sub );
@@ -383,6 +387,8 @@ static void ttf_extract_name(const uint8_t *name_table, size_t table_len,
383387 if (!name_table || table_len < 6 )
384388 return ;
385389 uint16_t count = ttf_be16 (name_table + 2 );
390+ if (count > (table_len - 6 ) / 12 )
391+ count = (uint16_t )((table_len - 6 ) / 12 );
386392 uint16_t stringOffset = ttf_be16 (name_table + 4 );
387393
388394 for (uint16_t i = 0 ; i < count ; i ++ ) {
@@ -403,7 +409,10 @@ static void ttf_extract_name(const uint8_t *name_table, size_t table_len,
403409 if (platformID == 3 ) {
404410 // Windows UTF-16 BE: extract only ASCII characters
405411 size_t ascii_len = 0 ;
406- for (uint16_t j = 0 ; j + 1 < length && ascii_len < out_len - 1 ;
412+ size_t safe_length = length ;
413+ if (safe_length > table_len - str_off )
414+ safe_length = table_len - str_off ;
415+ for (size_t j = 0 ; j + 1 < safe_length && ascii_len < out_len - 1 ;
407416 j += 2 ) {
408417 uint16_t cp = ttf_be16 (str + j );
409418 if (cp < 128 )
@@ -414,7 +423,11 @@ static void ttf_extract_name(const uint8_t *name_table, size_t table_len,
414423 return ;
415424 } else if (platformID == 1 ) {
416425 // Mac Roman: ASCII-compatible
417- size_t copy_len = length < out_len - 1 ? length : out_len - 1 ;
426+ size_t safe_length = length ;
427+ if (safe_length > table_len - str_off )
428+ safe_length = table_len - str_off ;
429+ size_t copy_len =
430+ safe_length < out_len - 1 ? safe_length : out_len - 1 ;
418431 memcpy (out , str , copy_len );
419432 out [copy_len ] = '\0' ;
420433 return ;
@@ -1285,8 +1298,8 @@ int pdf_set_font_ttf(struct pdf_doc *pdf, const char *path)
12851298 sizeof (font_name ));
12861299 if (font_name [0 ] == '\0' ) {
12871300 const char * base = strrchr (path , '/' );
1288- base = base ? base + 1 : path ;
1289- strncpy (font_name , base , sizeof (font_name ) - 1 );
1301+ const char * name_src = base ? base + 1 : path ;
1302+ strncpy (font_name , name_src , sizeof (font_name ) - 1 );
12901303 font_name [sizeof (font_name ) - 1 ] = '\0' ;
12911304 char * dot = strrchr (font_name , '.' );
12921305 if (dot )
@@ -1309,7 +1322,8 @@ int pdf_set_font_ttf(struct pdf_doc *pdf, const char *path)
13091322 uint16_t cmap_subtable_len = 0 ;
13101323 const uint8_t * cmap_subtable =
13111324 ttf_find_cmap_subtable (cmap , (size_t )cmap_len , & cmap_subtable_len );
1312- if (!cmap_subtable ) {
1325+ if (!cmap_subtable || cmap_subtable_len == 0 ||
1326+ cmap_subtable_len > font_data_len ) {
13131327 free (font_data );
13141328 return pdf_set_err (pdf , - EINVAL ,
13151329 "Font '%s' has no usable cmap subtable" , path );
@@ -1321,8 +1335,22 @@ int pdf_set_font_ttf(struct pdf_doc *pdf, const char *path)
13211335 "Unable to allocate cmap subtable for font '%s'" ,
13221336 path );
13231337 }
1338+ // ensure subtable fits in cmap bounds safely before blind copy
1339+ if (cmap_subtable_len > (cmap + cmap_len ) - cmap_subtable ) {
1340+ free (cmap_copy );
1341+ free (font_data );
1342+ return pdf_set_err (pdf , - EINVAL ,
1343+ "Font '%s' cmap subtable length invalid" , path );
1344+ }
13241345 memcpy (cmap_copy , cmap_subtable , cmap_subtable_len );
13251346
1347+ if (hmtx_len == 0 || hmtx_len > font_data_len ) {
1348+ free (cmap_copy );
1349+ free (font_data );
1350+ return pdf_set_err (pdf , - EINVAL , "Font '%s' has invalid hmtx_len" ,
1351+ path );
1352+ }
1353+
13261354 // Make a copy of the hmtx table for runtime advance-width lookups
13271355 uint8_t * hmtx_copy = (uint8_t * )malloc (hmtx_len );
13281356 if (!hmtx_copy ) {
@@ -1338,12 +1366,12 @@ int pdf_set_font_ttf(struct pdf_doc *pdf, const char *path)
13381366 // Widths are in PDF thousandths-of-em units. We store one entry per
13391367 // glyph ID in 0..numberOfHMetrics-1; glyphs beyond that share the last
13401368 // advance width (/DW).
1341- if (numberOfHMetrics == 0 ) {
1369+ if (numberOfHMetrics == 0 || numberOfHMetrics > font_data_len / 2 ) {
13421370 free (hmtx_copy );
13431371 free (cmap_copy );
13441372 free (font_data );
13451373 return pdf_set_err (pdf , - EINVAL ,
1346- "Font '%s' has numberOfHMetrics == 0 " , path );
1374+ "Font '%s' has invalid numberOfHMetrics " , path );
13471375 }
13481376 uint16_t * glyph_widths =
13491377 (uint16_t * )calloc (numberOfHMetrics , sizeof (uint16_t ));
0 commit comments