stdlib: add a test strtol, strtoul, strtoll (DONE)

The presumed bug where the value computed without the sign overflows
even though the negative result can be represented is not actually a
problem, because this only happens with signed results and the temporary
value is computed as unsigned (thus with extra range).
This commit is contained in:
Lephenixnoir 2021-05-20 11:01:15 +02:00
parent 5042236392
commit 06f975f75c
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
7 changed files with 51 additions and 10 deletions

View file

@ -107,6 +107,9 @@ set(SOURCES
src/libc/stdlib/lldiv.c
src/libc/stdlib/reallocarray.c
src/libc/stdlib/strto_int.c
src/libc/stdlib/strtol.c
src/libc/stdlib/strtoll.c
src/libc/stdlib/strtoul.c
src/libc/stdlib/strtoull.c
# string
src/libc/string/strchr.c

3
STATUS
View file

@ -100,8 +100,7 @@ DONE: Function/symbol/macro is defined, builds, links, and is tested
7.20.1.1 atof: TODO
7.20.1.2 atoi, atol, atoll: TODO
7.20.1.3 strtod, strtof, strtold: TODO
7.20.1.4 strtol, strtoul, strtoll: TODO
strtoull: DONE
7.20.1.4 strtol, strtoul, strtoll, strtoull: DONE
7.20.2 Pseudo-random sequence generation functions: TODO
7.20.3 Memory management functions: TODO (check existing code first)
7.20.4 Communication with the environment: TODO

View file

@ -1,7 +1,7 @@
#ifndef __STDLIB_P_H__
# define __STDLIB_P_H__
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
/* Parse an integer from a string. This is the base function for strtol,

View file

@ -2,6 +2,7 @@
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
/* Parse an integer from a string. Base function for strtol, strtoul, strtoll,
and strtoull. This function:
@ -55,12 +56,6 @@ int strto_int(char const * restrict ptr, char ** restrict endptr, int base,
valid = true;
/* (x = base*x + v) but with overflow checks */
/*
** TODO FIXME: There is a bug with overflows if the unsigned
** value cannot be represented but the signed value can (which
** is the case only for LONG_MIN and LLONG_MIN)
*/
if(outl) {
if(__builtin_umull_overflow(xl, base, &xl))
errno_value = ERANGE;
@ -77,7 +72,7 @@ int strto_int(char const * restrict ptr, char ** restrict endptr, int base,
ptr++;
}
/* Handle the sign */
/* Handle sign and range */
if(negative) {
/* Only -0 can be represented as unsigned */
if(outl && use_unsigned && xl != 0)
@ -85,9 +80,21 @@ int strto_int(char const * restrict ptr, char ** restrict endptr, int base,
if(outll && use_unsigned && xll != 0)
errno_value = ERANGE;
/* Handle signed range. Don't use -[L]LONG_MIN, it overflows */
if(outl && !use_unsigned && xl > LONG_MAX * 1ul + 1)
errno_value = ERANGE;
if(outll && !use_unsigned && xll > LLONG_MAX * 1ull + 1)
errno_value = ERANGE;
xl = -xl;
xll = -xll;
}
else {
if(outl && !use_unsigned && xl > LONG_MAX * 1ul)
errno_value = ERANGE;
if(outll && !use_unsigned && xll > LLONG_MAX * 1ull)
errno_value = ERANGE;
}
if(outl) *outl = xl;
if(outll) *outll = xll;

10
src/libc/stdlib/strtol.c Normal file
View file

@ -0,0 +1,10 @@
#include "stdlib_p.h"
#include <errno.h>
long int strtol(char const * restrict ptr, char ** restrict endptr, int base)
{
long n = 0;
int err = strto_int(ptr, endptr, base, &n, NULL, false);
if(err != 0) errno = err;
return n;
}

11
src/libc/stdlib/strtoll.c Normal file
View file

@ -0,0 +1,11 @@
#include "stdlib_p.h"
#include <errno.h>
long long int strtoll(char const * restrict ptr, char ** restrict endptr,
int base)
{
long long n = 0;
int err = strto_int(ptr, endptr, base, NULL, &n, false);
if(err != 0) errno = err;
return n;
}

11
src/libc/stdlib/strtoul.c Normal file
View file

@ -0,0 +1,11 @@
#include "stdlib_p.h"
#include <errno.h>
unsigned long int strtoul(char const * restrict ptr, char ** restrict endptr,
int base)
{
unsigned long n = 0;
int err = strto_int(ptr, endptr, base, (long *)&n, NULL, true);
if(err != 0) errno = err;
return n;
}