libc

/* $Id$ */
/* Copyright (c) 2014-2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS System libc */
/* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
extern char ** environ;
/* stdlib */
/* private */
/* prototypes */
static int _error(char const * progname, char const * message, int ret);
static int _arc4random(char const * progname);
static int _calloc(char const * progname);
static int _environ(char const * program);
static int _mkstemp(char const * progname);
static int _mktemp(char const * progname);
static int _strtold(char const * progname, char const * str,
long double expected);
static int _strtol(char const * progname);
static int _strtoll(char const * progname);
static int _strtoul(char const * progname);
static int _strtoull(char const * progname);
/* functions */
/* arc4random */
static int _arc4random(char const * progname)
{
uint32_t res[4];
size_t i;
printf("%s: Testing arc4random()\n", progname);
/* XXX not deterministic */
for(i = 0; i < sizeof(res) / sizeof(*res); i++)
res[i] = arc4random();
for(i = 0; i < sizeof(res) / sizeof(*res); i++)
printf("%u. 0x%08x\n", i + 1, res[i]);
/* XXX false negatives are unlikely but possible */
if(res[0] == res[1] && res[0] == res[2] && res[0] == res[3])
return 1;
return 0;
}
/* calloc */
static int _calloc(char const * progname)
{
int * p;
size_t i;
const size_t cnt = 16;
printf("%s: Testing calloc()\n", progname);
if(calloc(SIZE_MAX, 2) != NULL || calloc(2, SIZE_MAX) != NULL)
{
printf("calloc() failed to detect overflow\n");
return 1;
}
if((p = calloc(sizeof(int), cnt)) == NULL)
{
printf("calloc() failed to allocate memory\n");
return 1;
}
for(i = 0; i < cnt; i++)
if(p[i] != 0)
{
printf("calloc() failed to clear memory\n");
return 1;
}
free(p);
return 0;
}
/* environ */
static int _environ(char const * progname)
{
char ** e;
printf("%s: Testing environ\n", progname);
for(e = environ; *e != NULL; e++)
printf("%s: %s\n", progname, *e);
return 0;
}
/* error */
static int _error(char const * progname, char const * message, int ret)
{
fputs(progname, stderr);
fputs(": ", stderr);
perror(message);
return ret;
}
/* mkstemp */
static int _mkstemp(char const * progname)
{
int ret = 0;
char buf[] = "/tmp/stdlib.XXXXXX";
int fd;
printf("%s: Testing mkstemp()\n", progname);
if((fd = mkstemp(buf)) < 0)
return _error(progname, "mkstemp", 1);
if(unlink(buf) != 0)
ret = _error(progname, "unlink", 1);
if(close(fd) != 0)
ret = _error(progname, "close", 1);
return ret;
}
/* mktemp */
static int _mktemp(char const * progname)
{
char buf[] = "/tmp/stdlib.XXXXXX";
printf("%s: Testing mktemp()\n", progname);
return (mktemp(buf) == buf) ? 0 : _error(progname, "mktemp", 1);
}
/* realloc */
static int _realloc(char const * progname)
{
size_t i;
char * p = NULL;
char * q;
printf("%s: Testing realloc()\n", progname);
for(i = 0; i < 65536; i++)
{
if((q = realloc(p, arc4random() % 65536)) == NULL)
{
fprintf(stderr, "%s: %s: %s (%zu)\n", progname,
"realloc", strerror(errno), i);
free(p);
return -1;
}
p = q;
}
free(p);
return 0;
}
/* strtold */
static int _strtold(char const * progname, char const * str,
long double expected)
{
int ret = 0;
long double ld;
double d;
float f;
char * p;
printf("%s: Testing strtold(\"%s\", %Lf)\n", progname, str, expected);
ld = strtold(str, &p);
if(ld != expected || *p != '\0')
{
fprintf(stderr, "%s: %s: Obtained %Lf (expected: %Lf)\n",
progname, "strtold", ld, expected);
ret = 1;
}
printf("%s: Testing strtod(\"%s\", %Lf)\n", progname, str, expected);
d = strtod(str, &p);
if(d != (double)expected || *p != '\0')
{
fprintf(stderr, "%s: %s: Obtained %f (expected: %f)\n",
progname, "strtod", d, expected);
ret = 1;
}
printf("%s: Testing strtof(\"%s\", %Lf)\n", progname, str, expected);
f = strtof(str, &p);
if(f != (float)expected || *p != '\0')
{
fprintf(stderr, "%s: %s: Obtained %f (expected: %f)\n",
progname, "strtof", f, expected);
ret = 1;
}
return ret;
}
/* strtol */
static int _strtol(char const * progname)
{
char * p;
char const spaces[] = " ";
long l;
unsigned long lu;
char buf[32];
/* spaces */
errno = 0;
strtol(spaces, &p, 0);
if(p != spaces || errno != ERANGE)
{
fprintf(stderr, "%s: %s: Conversion error (spaces)\n", progname,
"strtol");
return 1;
}
/* -LONG_MAX - 1 */
lu = (unsigned long)LONG_MAX + 1;
snprintf(buf, sizeof(buf), "-%lu", lu);
errno = 0;
l = strtol(buf, &p, 10);
if(errno != 0)
{
fprintf(stderr, "%s: %s: Conversion error (-LONG_MAX - 1)\n",
progname, "strtol");
return 1;
}
/* -LONG_MAX - 2 */
lu = (unsigned long)LONG_MAX + 2;
snprintf(buf, sizeof(buf), "-%lu", lu);
errno = 0;
strtol(buf, &p, 10);
if(errno != ERANGE)
{
fprintf(stderr, "%s: %s: Conversion error (-LONG_MAX - 2)\n",
progname, "strtol");
return 1;
}
/* invalid input */
l = strtol("invalid", &p, 0);
if(l != 0 || errno != EINVAL)
{
fprintf(stderr, "%s: %s: Conversion error (invalid input)\n",
progname, "strtol");
return 1;
}
return 0;
}
/* strtoll */
static int _strtoll(char const * progname)
{
char * p;
char const spaces[] = " ";
long long ll;
unsigned long long llu;
char buf[32];
/* spaces */
errno = 0;
strtoll(spaces, &p, 0);
if(p != spaces || errno != ERANGE)
{
fprintf(stderr, "%s: %s: Conversion error (spaces)\n", progname,
"strtol");
return 1;
}
/* -LLONG_MAX - 1 */
llu = (unsigned long long)LLONG_MAX + 1;
snprintf(buf, sizeof(buf), "-%llu", llu);
errno = 0;
ll = strtoll(buf, &p, 10);
if(errno != 0)
{
fprintf(stderr, "%s: %s: Conversion error (-LLONG_MAX - 1)\n",
progname, "strtoll");
return 1;
}
/* -LLONG_MAX - 2 */
llu = (unsigned long)LLONG_MAX + 2;
snprintf(buf, sizeof(buf), "-%llu", llu);
errno = 0;
strtoll(buf, &p, 10);
if(errno != ERANGE)
{
fprintf(stderr, "%s: %s: Conversion error (-LLONG_MAX - 2)\n",
progname, "strtoll");
return 1;
}
/* invalid input */
ll = strtoll("invalid", &p, 0);
if(ll != 0 || errno != EINVAL)
{
fprintf(stderr, "%s: %s: Conversion error (invalid input)\n",
progname, "strtoll");
return 1;
}
return 0;
}
/* strtoul */
static int _strtoul(char const * progname)
{
char * p;
char const spaces[] = " ";
char buf[32];
/* spaces */
errno = 0;
strtoul(spaces, &p, 0);
if(p != spaces || errno != ERANGE)
{
fprintf(stderr, "%s: %s: Conversion error (spaces)\n", progname,
"strtoul");
return 1;
}
/* ULONG_MAX */
snprintf(buf, sizeof(buf), "%lu", ULONG_MAX);
errno = 0;
strtoul(buf, &p, 10);
if(errno != 0 || *p != '\0')
{
fprintf(stderr, "%s: %s: Conversion error (ULONG_MAX)\n",
progname, "strtoul");
return 1;
}
return 0;
}
/* strtoull */
static int _strtoull(char const * progname)
{
char * p;
char const spaces[] = " ";
char buf[32];
/* spaces */
errno = 0;
strtoull(spaces, &p, 0);
if(p != spaces || errno != ERANGE)
{
fprintf(stderr, "%s: %s: Conversion error (spaces)\n", progname,
"strtoul");
return 1;
}
/* ULLONG_MAX */
snprintf(buf, sizeof(buf), "%llu", ULLONG_MAX);
errno = 0;
strtoull(buf, &p, 10);
if(errno != 0 || *p != '\0')
{
fprintf(stderr, "%s: %s: Conversion error (ULLONG_MAX)\n",
progname, "strtoul");
return 1;
}
return 0;
}
/* public */
/* functions */
/* main */
int main(int argc, char * argv[])
{
int ret = 0;
(void) argc;
ret += _arc4random(argv[0]);
ret += _calloc(argv[0]);
ret += _environ(argv[0]);
ret += _mkstemp(argv[0]);
ret += _mktemp(argv[0]);
ret += _realloc(argv[0]);
ret += _strtold(argv[0], "0.0", 0.0);
ret += _strtold(argv[0], " 0.1", 0.1);
ret += _strtold(argv[0], " 1.0", 1.0);
ret += _strtold(argv[0], "+1.1", 1.1);
ret += _strtold(argv[0], "+1.01", 1.01);
ret += _strtold(argv[0], "-1.1", -1.1);
ret += _strtold(argv[0], "-1.01", -1.01);
ret += _strtol(argv[0]);
ret += _strtoul(argv[0]);
ret += _strtoll(argv[0]);
ret += _strtoull(argv[0]);
return (ret == 0) ? 0 : 2;
}