digidotcom/DCRabbit_10

Errors in strtoul() implementation

Closed this issue · 3 comments

Compare output of this test program in gcc to Dynamic C. Pay particular attention to the value of *tailptr, and how it relates to sptr.

#include <stdlib.h>
#include <stdio.h>

void test( char *str, int base)
{
    char *tail;
    unsigned long result;

    result = strtoul( str, &tail, base);
    printf( "strtoul( \"%s\", &tail, %u) = %lu (tail = \"%s\")\n",
            str, base, result, tail);
}
int main (int argc, char *argv[])
{
    test( "   123", 0);
    test( "   123", 1);
    test( "   999", 8);

    return 0;
}

results with gcc:

strtoul( "   123", &tail, 0) = 123 (tail = "")
strtoul( "   123", &tail, 1) = 0 (tail = "   123")
strtoul( "   999", &tail, 8) = 0 (tail = "   999")
DrASK commented

What is the output from Dynamic C? Also, it would be helpful to see the value of errno as the value of tail is unspecified when base is invalid (the second call).

Updated test program:

#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>

void test_unsigned(char *str, int base)
{
    char *tail;
    unsigned long result;

    errno = 0;
    result = strtoul( str, &tail, base);
    printf("strtoul(\"%s\", &tail, %u) = %lu (tail=\"%s\", errno=%d)\n",
        str, base, result, tail, errno);
}

void test_signed(char *str, int base)
{
    char *tail;
    long result;

    errno = 0;
    result = strtol( str, &tail, base);
    printf("strtol(\"%s\", &tail, %u) = %ld (tail=\"%s\", errno=%d)\n",
        str, base, result, tail, errno);
}

void test(char *str, int base)
{
    test_unsigned(str, base);
    test_signed(str, base);
}

int main()
{
    printf("EINVAL=%d, ERANGE=%d, LONG_MAX=%ld ULONG_MAX=%lu\n",
        EINVAL, ERANGE, LONG_MAX, ULONG_MAX);
    test("   123", 0);
    test("   123", 1);
    test("   999", 8);
    test("9999999999999999999", 0);

    return 0;
}

gcc results:

EINVAL=22, ERANGE=34, LONG_MAX=2147483647 ULONG_MAX=4294967295
strtoul("   123", &tail, 0) = 123 (tail="", errno=0)
strtol("   123", &tail, 0) = 123 (tail="", errno=0)
strtoul("   123", &tail, 1) = 0 (tail="   123", errno=22)
strtol("   123", &tail, 1) = 0 (tail="   123", errno=22)
strtoul("   999", &tail, 8) = 0 (tail="   999", errno=0)
strtol("   999", &tail, 8) = 0 (tail="   999", errno=0)
strtoul("9999999999999999999", &tail, 0) = 4294967295 (tail="", errno=34)
strtol("9999999999999999999", &tail, 0) = 2147483647 (tail="", errno=34)

Original Dynamic C results:

EINVAL=22, ERANGE=711, LONG_MAX=2147483647 ULONG_MAX=4294967295                 
strtoul("   123", &tail, 0) = 123 (tail="", errno=0)                            
strtol("   123", &tail, 0) = 123 (tail="", errno=0)                             
strtoul("   123", &tail, 1) = 0 (tail="123", errno=0)                           
strtol("   123", &tail, 1) = 0 (tail="   123", errno=0)                         
strtoul("   999", &tail, 8) = 0 (tail="999", errno=0)                           
strtol("   999", &tail, 8) = 0 (tail="999", errno=0)                            
strtoul("9999999999999999999", &tail, 0) = 4294967295 (tail="", errno=711)      
strtol("9999999999999999999", &tail, 0) = 2147483647 (tail="", errno=711)

With Dynamic C changes (not yet committed):

EINVAL=22, ERANGE=711, LONG_MAX=2147483647 ULONG_MAX=4294967295                 
strtoul("   123", &tail, 0) = 123 (tail="", errno=0)                            
strtol("   123", &tail, 0) = 123 (tail="", errno=0)                             
strtoul("   123", &tail, 1) = 0 (tail="   123", errno=22)                       
strtol("   123", &tail, 1) = 0 (tail="   123", errno=22)                        
strtoul("   999", &tail, 8) = 0 (tail="   999", errno=0)                        
strtol("   999", &tail, 8) = 0 (tail="   999", errno=0)                         
strtoul("9999999999999999999", &tail, 0) = 4294967295 (tail="", errno=711)      
strtol("9999999999999999999", &tail, 0) = 2147483647 (tail="", errno=711) 
DrASK commented

Looks like a good fix.