ref: 3e2f953a10cafa1b037d0172f81103c9f1a5f433
parent: 0d0365ec59a68767214b357f35379e1dbd3929e9
author: David Turner <[email protected]>
date: Tue May 22 09:10:59 EDT 2007
real fix for bug #19910. the .Z format is really badly designed :-(
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,8 @@
2007-05-22 David Turner <[email protected]>
- * src/lzw/ftzopen.h, src/lzw/ftzopen.c: apply some "band-aid"
- to avoid blowing up the heap in the case of malformed fonts.
- related to bug #19910; *not* a real fix though...
+ * src/lzw/ftzopen.h, src/lzw/ftzopen.c: fix for bug #19910
+ (heap blowup with very large .Z font file). The .Z format is
+ *really* crappy :-(
2007-05-20 Ismail Dönmez <[email protected]>
--- a/src/lzw/ftzopen.c
+++ b/src/lzw/ftzopen.c
@@ -23,59 +23,86 @@
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_DEBUG_H
- /* refill input buffer, return 0 on success, or -1 if eof */
static int
ft_lzwstate_refill( FT_LzwState state )
{
- int result = -1;
+ FT_ULong count;
+ if (state->in_eof)
+ return -1;
- if ( !state->in_eof )
- {
- FT_ULong count = FT_Stream_TryRead( state->source,
- state->in_buff,
- sizeof ( state->in_buff ) );
+ count = FT_Stream_TryRead( state->source,
+ state->buf_tab,
+ state->num_bits ); /* WHY ?? */
- state->in_cursor = state->in_buff;
- state->in_limit = state->in_buff + count;
- state->in_eof = FT_BOOL( count < sizeof ( state->in_buff ) );
+ state->buf_size = (FT_UInt) count;
+ state->buf_total += count;
+ state->in_eof = FT_BOOL( count < state->num_bits );
+ state->buf_offset = 0;
+ state->buf_size = (state->buf_size << 3) - (state->num_bits-1);
- if ( count > 0 )
- result = 0;
- }
- return result;
+ if (count == 0) /* end of file */
+ return -1;
+
+ return 0;
}
- /* return new code of 'num_bits', or -1 if eof */
static FT_Int32
- ft_lzwstate_get_code( FT_LzwState state,
- FT_UInt num_bits )
+ ft_lzwstate_get_code( FT_LzwState state )
{
- FT_Int32 result = -1;
- FT_UInt32 pad = state->pad;
- FT_UInt pad_bits = state->pad_bits;
+ FT_UInt num_bits = state->num_bits;
+ FT_Int offset = state->buf_offset;
+ FT_Byte* p;
+ FT_Int result;
- while ( num_bits > pad_bits )
+ if ( state->buf_clear ||
+ offset >= state->buf_size ||
+ state->free_ent >= state->free_bits )
{
- if ( state->in_cursor >= state->in_limit &&
- ft_lzwstate_refill( state ) < 0 )
- goto Exit;
+ if ( state->free_ent >= state->free_bits )
+ {
+ state->num_bits = ++num_bits;
+ state->free_bits = state->num_bits < state->max_bits
+ ? (FT_UInt)( ( 1UL << num_bits ) - 256 )
+ : state->max_free + 1;
+ }
- pad |= (FT_UInt32)(*state->in_cursor++) << pad_bits;
- pad_bits += 8;
+ if ( state->buf_clear )
+ {
+ state->num_bits = num_bits = LZW_INIT_BITS;
+ state->free_bits = (FT_UInt)( ( 1UL << num_bits ) - 256 );
+ state->buf_clear = 0;
+ }
+
+ if ( ft_lzwstate_refill( state ) < 0 )
+ return -1;
+
+ offset = 0;
}
- result = (FT_Int32)( pad & LZW_MASK( num_bits ) );
- state->pad_bits = pad_bits - num_bits;
- state->pad = pad >> num_bits;
+ state->buf_offset = offset + num_bits;
- Exit:
+ p = &state->buf_tab[offset >> 3];
+ offset &= 7;
+ result = *p++ >> offset;
+ offset = 8-offset;
+ num_bits -= offset;
+ if (num_bits >= 8)
+ {
+ result |= *p++ << offset;
+ offset += 8;
+ num_bits -= 8;
+ }
+ if (num_bits > 0)
+ result |= (*p & LZW_MASK(num_bits)) << offset;
+
return result;
}
+
/* grow the character stack */
static int
ft_lzwstate_stack_grow( FT_LzwState state )
@@ -87,11 +114,6 @@
FT_UInt old_size = state->stack_size;
FT_UInt new_size = old_size;
- /* limit stack size to detect invalid files */
- /* the magic number comes from the origin NetBSD zopen implementation */
- if (state->stack_size >= 69001 )
- return -1;
-
new_size = new_size + ( new_size >> 1 ) + 4;
if ( state->stack == state->stack_0 )
@@ -115,7 +137,6 @@
{
FT_UInt old_size = state->prefix_size;
FT_UInt new_size = old_size;
- FT_UInt max_size = INT_MAX/(sizeof(FT_UShort)+sizeof(FT_Byte));
FT_Memory memory = state->memory;
FT_Error error;
@@ -125,13 +146,6 @@
else
new_size += new_size >> 2; /* don't grow too fast */
- if (new_size < old_size || new_size > max_size)
- {
- new_size = max_size;
- if (new_size == old_size)
- return -1;
- }
-
/*
* Note that the `suffix' array is located in the same memory block
* pointed to by `prefix'.
@@ -159,12 +173,11 @@
FT_LOCAL_DEF( void )
ft_lzwstate_reset( FT_LzwState state )
{
- state->in_cursor = state->in_buff;
- state->in_limit = state->in_buff;
state->in_eof = 0;
- state->pad_bits = 0;
- state->pad = 0;
-
+ state->buf_offset = 0;
+ state->buf_size = 0;
+ state->buf_clear = 0;
+ state->buf_total = 0;
state->stack_top = 0;
state->num_bits = LZW_INIT_BITS;
state->phase = FT_LZW_PHASE_START;
@@ -226,11 +239,9 @@
{
FT_ULong result = 0;
- FT_UInt num_bits = state->num_bits;
- FT_UInt free_ent = state->free_ent;
- FT_UInt last_char = state->last_char;
- FT_UInt old_code = state->old_code;
- FT_UInt in_code = state->in_code;
+ FT_UInt old_char = state->old_char;
+ FT_UInt old_code = state->old_code;
+ FT_UInt in_code = state->in_code;
if ( out_size == 0 )
@@ -256,27 +267,27 @@
if ( state->max_bits > LZW_MAX_BITS )
goto Eof;
- num_bits = LZW_INIT_BITS;
- free_ent = ( state->block_mode ? LZW_FIRST : LZW_CLEAR ) - 256;
+ state->num_bits = LZW_INIT_BITS;
+ state->free_ent = ( state->block_mode ? LZW_FIRST : LZW_CLEAR ) - 256;
in_code = 0;
- state->free_bits = num_bits < state->max_bits
- ? (FT_UInt)( ( 1UL << num_bits ) - 256 )
+ state->free_bits = state->num_bits < state->max_bits
+ ? (FT_UInt)( ( 1UL << state->num_bits ) - 256 )
: state->max_free + 1;
- c = ft_lzwstate_get_code( state, num_bits );
+ c = ft_lzwstate_get_code( state );
if ( c < 0 )
goto Eof;
- old_code = last_char = (FT_UInt)c;
+ old_code = old_char = (FT_UInt)c;
if ( buffer )
- buffer[result] = (FT_Byte)last_char;
+ buffer[result] = (FT_Byte)old_char;
- state->phase = FT_LZW_PHASE_CODE;
-
if ( ++result >= out_size )
goto Exit;
+
+ state->phase = FT_LZW_PHASE_CODE;
}
/* fall-through */
@@ -287,7 +298,7 @@
NextCode:
- c = ft_lzwstate_get_code( state, num_bits );
+ c = ft_lzwstate_get_code( state );
if ( c < 0 )
goto Eof;
@@ -295,14 +306,9 @@
if ( code == LZW_CLEAR && state->block_mode )
{
- free_ent = ( LZW_FIRST - 1 ) - 256; /* why not LZW_FIRST-256 ? */
- num_bits = LZW_INIT_BITS;
-
- state->free_bits = num_bits < state->max_bits
- ? (FT_UInt)( ( 1UL << num_bits ) - 256 )
- : state->max_free + 1;
-
- c = ft_lzwstate_get_code( state, num_bits );
+ state->free_ent = ( LZW_FIRST - 1 ) - 256; /* why not LZW_FIRST-256 ? */
+ state->buf_clear = 1;
+ c = ft_lzwstate_get_code( state );
if ( c < 0 )
goto Eof;
@@ -314,9 +320,9 @@
if ( code >= 256U )
{
/* special case for KwKwKwK */
- if ( code - 256U >= free_ent )
+ if ( code - 256U >= state->free_ent )
{
- FTLZW_STACK_PUSH( last_char );
+ FTLZW_STACK_PUSH( old_char );
code = old_code;
}
@@ -327,8 +333,8 @@
}
}
- last_char = code;
- FTLZW_STACK_PUSH( last_char );
+ old_char = code;
+ FTLZW_STACK_PUSH( old_char );
state->phase = FT_LZW_PHASE_STACK;
}
@@ -348,25 +354,18 @@
}
/* now create new entry */
- if ( free_ent < state->max_free )
+ if ( state->free_ent < state->max_free )
{
- if ( free_ent >= state->prefix_size &&
- ft_lzwstate_prefix_grow( state ) < 0 )
+ if ( state->free_ent >= state->prefix_size &&
+ ft_lzwstate_prefix_grow( state ) < 0 )
goto Eof;
- FT_ASSERT( free_ent < state->prefix_size );
+ FT_ASSERT( state->free_ent < state->prefix_size );
- state->prefix[free_ent] = (FT_UShort)old_code;
- state->suffix[free_ent] = (FT_Byte) last_char;
+ state->prefix[state->free_ent] = (FT_UShort)old_code;
+ state->suffix[state->free_ent] = (FT_Byte) old_char;
- if ( ++free_ent == state->free_bits )
- {
- num_bits++;
-
- state->free_bits = num_bits < state->max_bits
- ? (FT_UInt)( ( 1UL << num_bits ) - 256 )
- : state->max_free + 1;
- }
+ state->free_ent += 1;
}
old_code = in_code;
@@ -380,11 +379,9 @@
}
Exit:
- state->num_bits = num_bits;
- state->free_ent = free_ent;
- state->old_code = old_code;
- state->last_char = last_char;
- state->in_code = in_code;
+ state->old_code = old_code;
+ state->old_char = old_char;
+ state->in_code = in_code;
return result;
--- a/src/lzw/ftzopen.h
+++ b/src/lzw/ftzopen.h
@@ -112,13 +112,13 @@
typedef struct _FT_LzwStateRec
{
FT_LzwPhase phase;
-
FT_Int in_eof;
- FT_Byte* in_cursor; /* current buffer pos */
- FT_Byte* in_limit; /* current buffer limit */
- FT_UInt32 pad; /* a pad value where incoming bits were read */
- FT_Int pad_bits; /* number of meaningful bits in pad value */
+ FT_Byte buf_tab[16];
+ FT_Int buf_offset;
+ FT_Int buf_size;
+ FT_Bool buf_clear;
+ FT_Int buf_total;
FT_UInt max_bits; /* max code bits, from file header */
FT_Int block_mode; /* block mode flag, from file header */
@@ -128,7 +128,7 @@
FT_UInt free_ent; /* index of next free entry */
FT_UInt free_bits; /* if reached by free_ent, increment num_bits */
FT_UInt old_code;
- FT_UInt last_char;
+ FT_UInt old_char;
FT_UInt in_code;
FT_UShort* prefix; /* always dynamically allocated / reallocated */
@@ -138,8 +138,6 @@
FT_Byte* stack; /* character stack */
FT_UInt stack_top;
FT_UInt stack_size;
-
- FT_Byte in_buff[FT_LZW_IN_BUFF_SIZE]; /* small read-buffer */
FT_Byte stack_0[FT_LZW_DEFAULT_STACK_SIZE]; /* minimize heap alloc */
FT_Stream source; /* source stream */