Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more thorough number parsing checks. Fix a couple of potential bugs. #157

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
CC ?= gcc

CFLAGS += -fPIC -Wall -Wextra -ansi -pedantic
#Enable more thorough check of parsing overflows and errors.
#It will check for trailing junk characters in number strings.
#Whitespace characters are allowed (isspace()), anything else will result
#in a parsing error.
CFLAGS += -DINIPARSER_STRICT_PARSER

ifndef DEBUG
ADDITIONAL_CFLAGS ?= -O2
else
Expand Down
15 changes: 15 additions & 0 deletions src/dictionary.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,23 @@ dictionary * dictionary_new(size_t size)
if (d) {
d->size = size ;
d->val = (char**) calloc(size, sizeof *d->val);
if(d->val == NULL) {
free(d);
return NULL;
}
d->key = (char**) calloc(size, sizeof *d->key);
if(d->key == NULL) {
free(d->val);
free(d);
return NULL;
}
d->hash = (unsigned*) calloc(size, sizeof *d->hash);
if(d->hash == NULL) {
free(d->key);
free(d->val);
free(d);
return NULL;
}
}
return d ;
}
Expand Down
98 changes: 91 additions & 7 deletions src/iniparser.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@
*/
/*--------------------------------------------------------------------------*/
/*---------------------------- Includes ------------------------------------*/
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#if defined(INIPARSER_STRICT_PARSER)
#include <errno.h>
#include <limits.h>
#include <math.h>
#endif /* INIPARSER_STRICT_PARSER */
#include "iniparser.h"

/*---------------------------- Defines -------------------------------------*/
Expand Down Expand Up @@ -51,7 +57,7 @@ static const char * strlwc(const char * in, char *out, unsigned len)

if (in==NULL || out == NULL || len==0) return NULL ;
i=0 ;
while (in[i] != '\0' && i < len-1) {
while ((i < len-1) && (in[i] != '\0')) {
out[i] = (char)tolower((int)in[i]);
i++ ;
}
Expand Down Expand Up @@ -447,20 +453,54 @@ const char * iniparser_getstring(const dictionary * d, const char * key, const c
"042" -> 34 (octal -> decimal)
"0x42" -> 66 (hexa -> decimal)

Warning: the conversion may overflow in various ways. Conversion is
totally outsourced to strtol(), see the associated man page for overflow
handling.

Credits: Thanks to A. Becker for suggesting strtol()
*/
/*--------------------------------------------------------------------------*/
long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound)
{
const char * str ;
#if defined(INIPARSER_STRICT_PARSER)
long int tmp_num;
int tmp_errno;
char *endptr = NULL;
#endif /* INIPARSER_STRICT_PARSER */

str = iniparser_getstring(d, key, INI_INVALID_KEY);
if (str==NULL || str==INI_INVALID_KEY) return notfound ;

#if defined(INIPARSER_STRICT_PARSER)
/* In case of an error strtol() can return 0,
* LONG_MIN or LONG_MAX and errno will be set:
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html
*/
tmp_errno = errno;
tmp_num = strtol(str, &endptr, 0);
/* No valid string supplied */
if(endptr == NULL || endptr == str)
return notfound;

/* In case if there are any whitespace character after the
* number, endptr will point to the first one.
* Ignore whitespace at the end of the string,
* but check if there are any junk characters,
* and return notfound in case if there are any.*/
while(*endptr) {
if(isspace(*endptr)) {
endptr++;
} else {
errno = EINVAL;
return notfound;
}
}

if((tmp_num == 0 || tmp_num == LONG_MIN ||
tmp_num == LONG_MAX) && tmp_errno != errno) {
tmp_num = notfound;
}
return tmp_num;
#else
return strtol(str, NULL, 0);
#endif /* INIPARSER_STRICT_PARSER */
}

int64_t iniparser_getint64(const dictionary * d, const char * key, int64_t notfound)
Expand Down Expand Up @@ -512,7 +552,17 @@ uint64_t iniparser_getuint64(const dictionary * d, const char * key, uint64_t no
/*--------------------------------------------------------------------------*/
int iniparser_getint(const dictionary * d, const char * key, int notfound)
{
#if defined(INIPARSER_STRICT_PARSER)
long int res = iniparser_getlongint(d, key, notfound);
/* Check if the result is within valid range for an integer */
if(res != notfound && (res < INT_MIN || res > INT_MAX)) {
res = notfound;
errno = ERANGE;
}
return (int)res;
#else
return (int)iniparser_getlongint(d, key, notfound);
#endif
}

/*-------------------------------------------------------------------------*/
Expand All @@ -525,16 +575,50 @@ int iniparser_getint(const dictionary * d, const char * key, int notfound)

This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
or if there is an error while parsing then notfound value will be returned.
*/
/*--------------------------------------------------------------------------*/
double iniparser_getdouble(const dictionary * d, const char * key, double notfound)
{
const char * str ;

#if defined(INIPARSER_STRICT_PARSER)
char *endptr = NULL;
double tmp_num;
int tmp_errno;
#endif /* INIPARSER_STRICT_PARSER */
str = iniparser_getstring(d, key, INI_INVALID_KEY);
if (str==NULL || str==INI_INVALID_KEY) return notfound ;

#if defined(INIPARSER_STRICT_PARSER)
tmp_errno = errno;
tmp_num = strtod(str, &endptr);
/* No valid string supplied */
if(endptr == NULL || endptr == str)
return notfound;

/* In case if there are any whitespace character after the
* number, endptr will point to the first one.
* Ignore whitespace at the end of the string,
* but check if there are any junk characters,
* and return notfound in case if there are any.*/
while(*endptr) {
if(isspace(*endptr)) {
endptr++;
} else {
errno = EINVAL;
return notfound;
}
}

if((tmp_num == 0 || tmp_num == HUGE_VAL ||
tmp_num == -(HUGE_VAL)) && tmp_errno != errno) {
tmp_num = notfound;
}
return tmp_num;
#else
return atof(str);
#endif /* INIPARSER_STRICT_PARSER */

}

/*-------------------------------------------------------------------------*/
Expand Down
1 change: 1 addition & 0 deletions test/test_dictionary.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ static char *get_dump(dictionary *d)
}
if (fread(dump_buff, 1, dump_size, fd) != (size_t)dump_size) {
fclose(fd);
free(dump_buff);
return NULL;
}

Expand Down