-
Notifications
You must be signed in to change notification settings - Fork 430
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
Enable strict parsing #105
Labels
Comments
Said patch for easier review: From 3b29914200c76d8b867fbc31a499e6104119d90e Mon Sep 17 00:00:00 2001
From: Mario Malenica <[email protected]>
Date: Sun, 10 Feb 2019 21:32:13 +0100
Subject: [PATCH] Add more thorough number parsing checks. Fix a couple of
potential bugs.
---
Makefile | 6 ++++
src/dictionary.c | 15 ++++++++
src/iniparser.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++----
test/test_dictionary.c | 1 +
4 files changed, 113 insertions(+), 7 deletions(-)
diff --git a/Makefile b/Makefile
index a5a4ab2..db0a8b0 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/src/dictionary.c b/src/dictionary.c
index cb7ccd4..03b334b 100644
--- a/src/dictionary.c
+++ b/src/dictionary.c
@@ -159,8 +159,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 ;
}
diff --git a/src/iniparser.c b/src/iniparser.c
index fffdf9f..8264117 100644
--- a/src/iniparser.c
+++ b/src/iniparser.c
@@ -7,8 +7,14 @@
*/
/*--------------------------------------------------------------------------*/
/*---------------------------- Includes ------------------------------------*/
+#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
+#if defined(INIPARSER_STRICT_PARSER)
+#include <errno.h>
+#include <limits.h>
+#include <math.h>
+#endif /* INIPARSER_STRICT_PARSER */
#include "iniparser.h"
/*---------------------------- Defines -------------------------------------*/
@@ -48,7 +54,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++ ;
}
@@ -444,20 +450,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==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 */
}
@@ -490,7 +530,17 @@ long int iniparser_getlongint(const dictionary * d, const char * key, long int n
/*--------------------------------------------------------------------------*/
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
}
/*-------------------------------------------------------------------------*/
@@ -503,16 +553,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==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 */
+
}
/*-------------------------------------------------------------------------*/
diff --git a/test/test_dictionary.c b/test/test_dictionary.c
index f89f1c1..bbe045d 100644
--- a/test/test_dictionary.c
+++ b/test/test_dictionary.c
@@ -124,6 +124,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;
}
--
2.7.4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Pull request across different sites doesn't work with GitHub.
My cloned repo is on BitBucket.
Here are some changes in patch file format.
0001-Add-more-thorough-number-parsing-checks.-Fix-a-coupl.txt
The text was updated successfully, but these errors were encountered: