[truetype] Fix handling of packed deltas in Variation Fonts. * src/truetype/ttgxvar (ft_var_readpackeddeltas): Don't expect the number of bytes used to encode the deltas to be higher than the number of encoded values. The specification allows a very compact encoding; for example, a list of 200 zeros can be encoded with just a couple of bytes. We now count the consumed bytes to make sure to not read more than expected.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c
index e4da810..48b79ef 100644
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -264,55 +264,80 @@
FT_Fixed *deltas = NULL;
FT_UInt runcnt, cnt;
FT_UInt i, j;
+ FT_UInt bytes_used;
FT_Memory memory = stream->memory;
FT_Error error = FT_Err_Ok;
FT_UNUSED( error );
- if ( delta_cnt > size )
- {
- FT_TRACE1(( "ft_var_readpackeddeltas: number of points too large\n" ));
- return NULL;
- }
-
if ( FT_NEW_ARRAY( deltas, delta_cnt ) )
return NULL;
- i = 0;
- while ( i < delta_cnt )
+ i = 0;
+ bytes_used = 0;
+
+ while ( i < delta_cnt && bytes_used < size )
{
runcnt = FT_GET_BYTE();
cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK;
+ bytes_used++;
+
if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
{
- /* `runcnt' zeroes get added */
+ /* `cnt` + 1 zeroes get added */
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
deltas[i++] = 0;
}
else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
{
- /* `runcnt' shorts from the stack */
+ /* `cnt` + 1 shorts from the stack */
+ bytes_used += 2 * ( cnt + 1 );
+ if ( bytes_used > size )
+ {
+ FT_TRACE1(( "ft_var_readpackeddeltas:"
+ " number of short deltas too large\n" ));
+ goto Fail;
+ }
+
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
deltas[i++] = FT_intToFixed( FT_GET_SHORT() );
}
else
{
- /* `runcnt' signed bytes from the stack */
+ /* `cnt` + 1 signed bytes from the stack */
+ bytes_used += cnt + 1;
+ if ( bytes_used > size )
+ {
+ FT_TRACE1(( "ft_var_readpackeddeltas:"
+ " number of byte deltas too large\n" ));
+ goto Fail;
+ }
+
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
deltas[i++] = FT_intToFixed( FT_GET_CHAR() );
}
if ( j <= cnt )
{
- /* bad format */
- FT_FREE( deltas );
- return NULL;
+ FT_TRACE1(( "ft_var_readpackeddeltas:"
+ " number of deltas too large\n" ));
+ goto Fail;
}
}
+ if ( i < delta_cnt )
+ {
+ FT_TRACE1(( "ft_var_readpackeddeltas: not enough deltas\n" ));
+ goto Fail;
+ }
+
return deltas;
+
+ Fail:
+ FT_FREE( deltas );
+ return NULL;
}