From 3334ea840101b99165d1d03ff88349afb54ff00b Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 1 Feb 2008 15:50:17 +0000 Subject: [PATCH] fix the 1.04 bencode errors reported in the forums this morning. add regression tests. --- libtransmission/bencode-test.c | 55 ++++++++++++++++++++++++---------- libtransmission/bencode.c | 49 +++++++++++++++++------------- 2 files changed, 67 insertions(+), 37 deletions(-) diff --git a/libtransmission/bencode-test.c b/libtransmission/bencode-test.c index bee274e1f..ad9ef3f89 100644 --- a/libtransmission/bencode-test.c +++ b/libtransmission/bencode-test.c @@ -136,6 +136,29 @@ testStr( void ) return 0; } +static int +testString( const char * str, int isGood ) +{ + benc_val_t val; + const uint8_t * end = NULL; + char * saved; + const size_t len = strlen( str ); + int savedLen; + int err = tr_bencParse( str, str+len, &val , &end ); + if( !isGood ) { + check( err ); + } else { + check( !err ); + check( end == (const uint8_t*)str + len ); + saved = tr_bencSave( &val, &savedLen ); + check( !strcmp( saved, str ) ); + check( len == (size_t)savedLen ); + tr_free( saved ); + tr_bencFree( &val ); + } + return 0; +} + static int testParse( void ) { @@ -184,15 +207,22 @@ testParse( void ) tr_free( saved ); tr_bencFree( &val ); - end = NULL; - snprintf( (char*)buf, sizeof( buf ), "llleee" ); - err = tr_bencParse( buf, buf + sizeof( buf ), &val , &end ); - check( !err ); - check( end == buf + 6 ); - saved = tr_bencSave( &val, &len ); - check( !strcmp( saved, "llleee" ) ); - tr_free( saved ); - tr_bencFree( &val ); + if(( err = testString( "llleee", TRUE ))) + return err; + if(( err = testString( "d3:cow3:moo4:spam4:eggse", TRUE ))) + return err; + if(( err = testString( "d4:spaml1:a1:bee", TRUE ))) + return err; +#if 0 + if(( err = testString( "d9:publisher3:bob18:publisher.location4:home17:publisher-webpage15:www.example.come", TRUE ))) + return err; +#endif + if(( err = testString( "d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e", TRUE ))) + return err; + if(( err = testString( "d1:ai0e1:be", FALSE ))) /* odd number of children */ + return err; + if(( err = testString( "", FALSE ))) + return err; /* nested containers * parse an unsorted dict @@ -209,13 +239,6 @@ testParse( void ) tr_free( saved ); tr_bencFree( &val ); - end = NULL; - snprintf( (char*)buf, sizeof( buf ), "d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e" ); - err = tr_bencParse( buf, buf+sizeof( buf ), &val, &end ); - check( !err ); - check( end == buf + strlen( (const char*)buf ) ); - tr_bencFree( &val ); - return 0; } diff --git a/libtransmission/bencode.c b/libtransmission/bencode.c index 586265aa5..c2869ee3a 100644 --- a/libtransmission/bencode.c +++ b/libtransmission/bencode.c @@ -41,27 +41,25 @@ **/ static int -isInt( const benc_val_t * val ) +isType( const benc_val_t * val, int type ) { - return val!=NULL && val->type==TYPE_INT; + return ( ( val != NULL ) && ( val->type == type ) ); } -static int -isList( const benc_val_t * val ) -{ - return val!=NULL && val->type==TYPE_LIST; -} - -static int -isDict( const benc_val_t * val ) -{ - return val!=NULL && val->type==TYPE_DICT; -} +#define isInt(v) ( isType( ( v ), TYPE_INT ) ) +#define isString(v) ( isType( ( v ), TYPE_STR ) ) +#define isList(v) ( isType( ( v ), TYPE_LIST ) ) +#define isDict(v) ( isType( ( v ), TYPE_DICT ) ) static int isContainer( const benc_val_t * val ) { - return val!=NULL && ( val->type & ( TYPE_DICT | TYPE_LIST ) ); + return isList(val) || isDict(val); +} +static int +isSomething( const benc_val_t * val ) +{ + return isContainer(val) || isInt(val) || isString(val); } benc_val_t* @@ -229,6 +227,8 @@ tr_bencParse( const void * buf_in, const uint8_t * bufend = bufend_in; tr_ptrArray * parentStack = tr_ptrArrayNew( ); + tr_bencInit( top, 0 ); + while( buf != bufend ) { if( buf > bufend ) /* no more text to parse... */ @@ -274,9 +274,15 @@ tr_bencParse( const void * buf_in, } else if( *buf=='e' ) /* end of list or dict */ { + benc_val_t * node; ++buf; if( tr_ptrArrayEmpty( parentStack ) ) return TR_ERROR; + + node = tr_ptrArrayBack( parentStack ); + if( isDict( node ) && ( node->val.l.count % 2 ) ) + return TR_ERROR; /* odd # of children in dict */ + tr_ptrArrayPop( parentStack ); if( tr_ptrArrayEmpty( parentStack ) ) break; @@ -308,7 +314,7 @@ tr_bencParse( const void * buf_in, } } - err = tr_ptrArrayEmpty( parentStack ) ? 0 : 1; + err = !isSomething( top ) || !tr_ptrArrayEmpty( parentStack ); if( !err && ( setme_end != NULL ) ) *setme_end = buf; @@ -511,20 +517,21 @@ struct SaveNode static struct SaveNode* nodeNewDict( const benc_val_t * val ) { - int i, j, n; + int i, j; + int nKeys; struct SaveNode * node; struct KeyIndex * indices; assert( isDict( val ) ); - n = val->val.l.count; + nKeys = val->val.l.count / 2; node = tr_new0( struct SaveNode, 1 ); node->val = val; - node->children = tr_new0( int, n ); + node->children = tr_new0( int, nKeys * 2 ); /* ugh, a dictionary's children have to be sorted by key... */ - indices = tr_new( struct KeyIndex, n ); - for( i=j=0; ival.l.vals[i].val.s.s; indices[j].index = i; } @@ -535,7 +542,7 @@ nodeNewDict( const benc_val_t * val ) node->children[ node->childCount++ ] = index + 1; } - assert( node->childCount == n ); + assert( node->childCount == nKeys * 2 ); tr_free( indices ); return node; }