Malfunction of gcry_sexp_car
Benjamin Pousse
benjamin.pousse at member.fsf.org
Thu Feb 16 22:09:38 CET 2012
Hello,
(This is my first contribution. So I apologize if this is not the right
way to contribute.)
The function gcry_sexp_car seems buggy to me (tested on libgcrypt
version 1.4.6, 1.5.0, 1.6.0-git6078b05): it doesn't return any result on
S-expression starting with a data element.
For example, applied to the S-expression (hello "123"), it returns an
empty S-expression (I expect the S-expression (hello)).
In fact, after some "investigation", the function gcry_sexp_nth appears
unable to return the n-th element of a S-expression when this element is
not a list.
More precisely, in the function gcry_sexp_nth, the code in the first
"if" after the first loop "while" does not construct a valid gcry_sexp.
Please find at the end of this mail my patch to solve this problem (the
patch is large because I apply a regular indentation on the full
function).
Regards,
Benjamin.
diff --git a/src/sexp.c b/src/sexp.c
index 0877773..12b57ba 100644
--- a/src/sexp.c
+++ b/src/sexp.c
@@ -549,73 +549,96 @@ gcry_sexp_nth( const gcry_sexp_t list, int number
)
int level = 0;
if ( !list || list->d[0] != ST_OPEN )
- return NULL;
+ return NULL;
p = list->d;
- while ( number > 0 ) {
- p++;
- if ( *p == ST_DATA ) {
- memcpy ( &n, ++p, sizeof n );
- p += sizeof n + n;
- p--;
- if ( !level )
- number--;
- }
- else if ( *p == ST_OPEN ) {
- level++;
- }
- else if ( *p == ST_CLOSE ) {
- level--;
- if ( !level )
- number--;
- }
- else if ( *p == ST_STOP ) {
- return NULL;
- }
- }
+ while ( number > 0 )
+ {
+ p++;
+ if ( *p == ST_DATA )
+ {
+ memcpy ( &n, ++p, sizeof n );
+ p += sizeof n + n;
+ p--;
+ if ( !level )
+ number--;
+ }
+ else if ( *p == ST_OPEN )
+ {
+ level++;
+ }
+ else if ( *p == ST_CLOSE )
+ {
+ level--;
+ if ( !level )
+ number--;
+ }
+ else if ( *p == ST_STOP )
+ {
+ return NULL;
+ }
+ }
p++;
- if ( *p == ST_DATA ) {
- memcpy ( &n, p, sizeof n ); p += sizeof n;
- newlist = gcry_malloc ( sizeof *newlist + n + 1 );
+ if ( *p == ST_DATA )
+ {
+ memcpy ( &n, p + 1, sizeof n );
+ /* Allocate 1 (= sizeof *newlist) byte for ST_OPEN
+ 1 byte for ST_DATA
+ sizeof n byte for n
+ n byte for the data
+ 1 byte for ST_CLOSE
+ 1 byte for ST_STOP*/
+ newlist = gcry_malloc ( sizeof *newlist + 1 + sizeof n + n + 2
);
if (!newlist)
return NULL;
- d = newlist->d;
- memcpy ( d, p, n ); d += n;
- *d++ = ST_STOP;
- }
- else if ( *p == ST_OPEN ) {
- const byte *head = p;
-
- level = 1;
- do {
- p++;
- if ( *p == ST_DATA ) {
- memcpy ( &n, ++p, sizeof n );
- p += sizeof n + n;
- p--;
- }
- else if ( *p == ST_OPEN ) {
- level++;
- }
- else if ( *p == ST_CLOSE ) {
- level--;
- }
- else if ( *p == ST_STOP ) {
- BUG ();
- }
- } while ( level );
- n = p + 1 - head;
+ d = newlist->d;
+ *d = ST_OPEN;
+ d++;
+ memcpy ( d, p, 1 + sizeof n + n ); /* Copy ST_DATA, n and the
data from p to d*/
+ d += 1 + sizeof n + n;
+ *d = ST_CLOSE;
+ d++;
+ *d = ST_STOP;
+ }
+ else if ( *p == ST_OPEN )
+ {
+ const byte *head = p;
+
+ level = 1;
+ do
+ {
+ p++;
+ if ( *p == ST_DATA )
+ {
+ memcpy ( &n, ++p, sizeof n );
+ p += sizeof n + n;
+ p--;
+ }
+ else if ( *p == ST_OPEN )
+ {
+ level++;
+ }
+ else if ( *p == ST_CLOSE )
+ {
+ level--;
+ }
+ else if ( *p == ST_STOP )
+ {
+ BUG ();
+ }
+ } while ( level );
+ n = p + 1 - head;
- newlist = gcry_malloc ( sizeof *newlist + n );
+ newlist = gcry_malloc ( sizeof *newlist + n );
if (!newlist)
return NULL;
- d = newlist->d;
- memcpy ( d, head, n ); d += n;
- *d++ = ST_STOP;
- }
+ d = newlist->d;
+ memcpy ( d, head, n ); d += n;
+ *d++ = ST_STOP;
+ }
else
- newlist = NULL;
+ newlist = NULL;
return normalize (newlist);
}
More information about the Gcrypt-devel
mailing list