[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
libgmp v4.1.4: mpz_set_str() fails heavily
From: |
ThMO |
Subject: |
libgmp v4.1.4: mpz_set_str() fails heavily |
Date: |
Mon, 10 Oct 2005 23:54:04 +0200 |
Hello folks,
the conversion routine mpz_set_str() fails several times:
· an optional `+' sign is *not* an error
e.g.: mpz_set_str( n, "+13", 10);
· trailing white-space *is* an error
e.g.: mpz_set_str( n, "13 ", 10);
· white-space after a possible `-' sign *is* an error
e.g.: mpz_set_str( n, " -000 13", 10);
· if the given base is 0, which means the base shall be set upon scanning,
and the base-signifier isn't followed by at least one valid digit, this
*must* be an error
e.g.: mpz_set_str( n, "0x", 0); mpz_set_str( n, "0B", 0);
cross check this with strtol()
alternatively use my attached quick hack and try to give the base as
follows:
./bug 0x abc
-> this will correctly state an error, since 0x signifies base 16, but
there are valid digits missing
· if base is 2 or 16 *and* the respective base-signifier is given at the
front of the number, this *is* correct
e.g.: mpz_set_str( n, "0xabc1262", 16); mpz_set_str( n, "0b1101", 2);
· etc.pp.
I've attached a small C file, which contains the following:
· my_mpz_set_str():
· this routine correctly handles not only the above examples
· furthermore will this routine behave like strtol() and returns a pointer
to the offensive character, which fails the conversion, in case the given
input was faulty
· there is an entry point at which the neccessary setup for mpn_set_str()
could be coded, in order to replace the faulty library routine - just
grep for FIXME
· it's coded to *quickly* perform it's task
· main():
this is a simple test-bed in order to cross check various input parameters
Usage: ./bug base number
THX for listening.
CU Tom.
(Thomas M.Ott)
Germany
/* bug.c: compare buggy mpz_set_str() with my correct wrapper routine
* ©2005-10-10 by (ThMO)
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <gmp.h>
#ifndef NULL
#define NULL ( (void *) 0 )
#endif
#ifndef TRUE
#define FALSE 0
#define TRUE ( !FALSE)
#endif
#if __GNUC__ >= 2
#define INLINE inline
#define NORETURN /* ((noreturn)) */
#define NORETURN2 __attribute__ ( (noreturn) )
#define PFL( fmt, par) \
__attribute__ ( (format( printf, (fmt), (par))) )
#else
#define INLINE /* no inlining */
#define NORETURN /* no pre-attributes */
#define NORETURN2 /* no post-attributes */
#define PFL( fmt, par) /* no format checking */
#endif
static char
*progname;
static int
my_mpz_set_str( mpz_t, char *, char **, int);
static NORETURN void
error( const char *, ...) NORETURN2 PFL( 1, 2);
static int
my_mpz_set_str( mpz_t n, char *ptr, char **endptr, int base)
{
int realbase, ch, errcode;
unsigned char is_neg;
char *str, *hold;
is_neg= 0;
str= ptr;
rescan:
switch ( ch= *str++)
{
case ' ': case '\t': case '\n':
case '\f': case '\r': case '\v':
goto rescan;
case '-':
++is_neg;
case '+':
ch= *str++;
default:
break;
}
switch ( realbase= base)
{
case 0:
realbase= 10;
if ( ch == '0')
switch ( ch= *str++)
{
case 'x': case 'X':
realbase= 16;
ch= *str++;
break;
case 'b': case 'B':
realbase= 2;
ch= *str++;
break;
default:
ch= '0';
--str;
realbase= 8;
break;
}
break;
case 2:
if ( ch == '0')
switch ( ch= *str++)
{
case 'b': case 'B':
ch= *str++;
default:
break;
}
break;
case 16:
if ( ch == '0')
switch ( ch= *str++)
{
case 'x': case 'X':
ch= *str++;
default:
break;
}
default:
break;
}
for ( hold= str; ch == '0'; ch= *str++)
;
for ( errcode= 0; ; ch= *str++)
{
switch ( ch)
{
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z':
ch -= 'a'- 'A';
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y':
case 'Z':
ch -= 'A'- ( '9'+ 1);
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if ( ( ch -= '0') >= 0 && ch < realbase)
continue; /* FIXME: prepare for mpn_set_str() directly */
goto flag_error;
case '\0':
if ( hold != str)
{
errcode= mpz_set_str( n, hold- 1, realbase);
if ( errcode == 0 && is_neg)
mpz_neg( n, n);
goto all_done;
}
default:
flag_error:
if ( hold == str)
str= ptr+ 1;
break;
}
--errcode;
all_done:
if ( endptr != NULL)
*endptr= str- 1;
return( errcode);
}
}
int
main( int argc, char **argv)
{
mpz_t n;
int res, base;
char *p, *endp;
p= strrchr( *argv, '/');
progname= p == NULL ? *argv : p+ 1;
mpz_init( n);
if ( argc != 3)
NORETURN error( "missing parameters\nUsage: %s base number", progname);
p= argv[ 1];
base= strtol( p, &endp, 0);
if ( p == endp || *endp != '\0' || base < 0 || base > 36)
NORETURN error( "invalid base `%s'", p);
p= argv[ 2];
res= mpz_set_str( n, p, base);
gmp_printf( "%s: str= \"%s\", n= %Zd, base= %d, res= %d\n",
"lgmp", p, n, base, res);
res= my_mpz_set_str( n, p, &endp, base);
gmp_printf( "%s: str= \"%s\", n= %Zd, base= %d, res= %d\n",
"mine", p, n, base, res);
if ( res != 0)
printf( "failed at: %*s\n", ( endp- p)+ 2, "^");
mpz_clear( n);
NORETURN exit( EXIT_SUCCESS);
}
static NORETURN void
error( const char *fmt, ...)
{
va_list par;
fprintf( stderr, "%s: error: ", progname);
va_start( par, fmt);
vfprintf( stderr, fmt, par);
va_end( par);
fprintf( stderr, "\n");
NORETURN exit( EXIT_FAILURE);
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- libgmp v4.1.4: mpz_set_str() fails heavily,
ThMO <=