Hello! This bug duplicates upstream issue #142: https://github.com/a2o/snoopy/issues/142
It is fixed by PR https://github.com/a2o/snoopy/pull/143 The fix commit (PR merge) is https://github.com/a2o/snoopy/commit/360bb18e16ceaca16a22b94be9e17fd5f2184c01 I've tried to extract the patch from commit (patch attached), but compilation started to fail with another warning: cmdline.c: In function ‘snoopy_datasource_cmdline’: cmdline.c:71:79: error: comparison between pointer and zero character constant [-Werror=pointer-compare] 71 | for (cmdLineArgCount=0 ; *(snoopy_inputdatastorage->argv+cmdLineArgCount) != '\0' ; cmdLineArgCount++); | ^~ cmdline.c:71:30: note: did you mean to dereference the pointer? 71 | for (cmdLineArgCount=0 ; *(snoopy_inputdatastorage->argv+cmdLineArgCount) != '\0' ; cmdLineArgCount++); | ^ cc1: all warnings being treated as errors
diff -Nur a/lib/inih/dev-update.sh b/lib/inih/dev-update.sh --- a/lib/inih/dev-update.sh +++ b/lib/inih/dev-update.sh @@ -7,17 +7,27 @@ set -e set -u GITORIGINURL="https://github.com/benhoyt/inih.git" -GITORIGINREF="master" +GITREF="master" TMPGITDIR="./_tmp-inih-git" DESTDIR="." DESTDIRSRC="./src" +### Parse arguments +# +if [ "${1:-}" != "" ]; then + GITREF="$1" +fi +echo "Using gitref: $GITREF" + + + ### Clone the repo # rm -rf $TMPGITDIR git clone $GITORIGINURL $TMPGITDIR +(cd $TMPGITDIR && git checkout $GITREF) @@ -30,7 +40,7 @@ ### Apply patches # -patch -p3 < ./patches/0001-strip-value-quotes.diff +patch -p0 < ./patches/0001-strip-value-quotes.diff diff -Nur a/lib/inih/patches/0001-strip-value-quotes.diff b/lib/inih/patches/0001-strip-value-quotes.diff --- a/lib/inih/patches/0001-strip-value-quotes.diff +++ b/lib/inih/patches/0001-strip-value-quotes.diff @@ -1,9 +1,7 @@ -diff --git a/lib/inih/src/ini.c b/lib/inih/src/ini.c -index 27ca85b..2c015c8 100644 ---- a/lib/inih/src/ini.c -+++ b/lib/inih/src/ini.c -@@ -149,6 +149,17 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, - #endif +--- src/ini.c.orig 2018-12-26 21:08:15.289767000 +0000 ++++ src/ini.c 2018-12-26 21:07:25.707778000 +0000 +@@ -187,6 +187,17 @@ + value = lskip(value); rstrip(value); + /* Strip surrounding double and single quotes */ @@ -19,4 +17,4 @@ + /* Valid name[=:]value pair found, call handler */ strncpy0(prev_name, name, sizeof(prev_name)); - if (!handler(user, section, name, value) && !error) + if (!HANDLER(user, section, name, value) && !error) diff -Nur a/lib/inih/SOURCE.txt b/lib/inih/SOURCE.txt --- a/lib/inih/SOURCE.txt +++ b/lib/inih/SOURCE.txt @@ -1,3 +1,3 @@ git-origin-url = 'https://github.com/benhoyt/inih.git' -git-origin-ref = 'tags/r36-0-g5dbf5cb' +git-origin-ref = 'tags/r42-0-g9d1af9d' patches-dir = 'patches/' diff -Nur a/lib/inih/src/ini.c b/lib/inih/src/ini.c --- a/lib/inih/src/ini.c +++ b/lib/inih/src/ini.c @@ -24,6 +24,12 @@ #define MAX_SECTION 50 #define MAX_NAME 50 +/* Used by ini_parse_string() to keep track of string parsing state. */ +typedef struct { + const char* ptr; + size_t num_left; +} ini_parse_string_ctx; + /* Strip whitespace chars off end of given string, in place. Return s. */ static char* rstrip(char* s) { @@ -64,7 +70,7 @@ /* Version of strncpy that ensures dest (size bytes) is null-terminated. */ static char* strncpy0(char* dest, const char* src, size_t size) { - strncpy(dest, src, size); + strncpy(dest, src, size - 1); dest[size - 1] = '\0'; return dest; } @@ -76,8 +82,14 @@ /* Uses a fair bit of stack (use heap instead if you need to) */ #if INI_USE_STACK char line[INI_MAX_LINE]; + int max_line = INI_MAX_LINE; #else char* line; + int max_line = INI_INITIAL_ALLOC; +#endif +#if INI_ALLOW_REALLOC + char* new_line; + int offset; #endif char section[MAX_SECTION] = ""; char prev_name[MAX_NAME] = ""; @@ -90,14 +102,40 @@ int error = 0; #if !INI_USE_STACK - line = (char*)malloc(INI_MAX_LINE); + line = (char*)malloc(INI_INITIAL_ALLOC); if (!line) { return -2; } #endif +#if INI_HANDLER_LINENO +#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno) +#else +#define HANDLER(u, s, n, v) handler(u, s, n, v) +#endif + /* Scan through stream line by line */ - while (reader(line, INI_MAX_LINE, stream) != NULL) { + while (reader(line, max_line, stream) != NULL) { +#if INI_ALLOW_REALLOC + offset = strlen(line); + while (offset == max_line - 1 && line[offset - 1] != '\n') { + max_line *= 2; + if (max_line > INI_MAX_LINE) + max_line = INI_MAX_LINE; + new_line = realloc(line, max_line); + if (!new_line) { + free(line); + return -2; + } + line = new_line; + if (reader(line + offset, max_line - offset, stream) == NULL) + break; + if (max_line >= INI_MAX_LINE) + break; + offset += strlen(line + offset); + } +#endif + lineno++; start = line; @@ -110,15 +148,14 @@ #endif start = lskip(rstrip(start)); - if (*start == ';' || *start == '#') { - /* Per Python configparser, allow both ; and # comments at the - start of a line */ + if (strchr(INI_START_COMMENT_PREFIXES, *start)) { + /* Start-of-line comment */ } #if INI_ALLOW_MULTILINE else if (*prev_name && *start && start > line) { /* Non-blank line with leading whitespace, treat as continuation of previous name's value (as per Python configparser). */ - if (!handler(user, section, prev_name, start) && !error) + if (!HANDLER(user, section, prev_name, start) && !error) error = lineno; } #endif @@ -141,12 +178,13 @@ if (*end == '=' || *end == ':') { *end = '\0'; name = rstrip(start); - value = lskip(end + 1); + value = end + 1; #if INI_ALLOW_INLINE_COMMENTS end = find_chars_or_comment(value, NULL); if (*end) *end = '\0'; #endif + value = lskip(value); rstrip(value); /* Strip surrounding double and single quotes */ @@ -154,7 +192,7 @@ value[strlen(value) - 1] = '\0'; value += 1; } else { - if ((*value == '\'') && (value[strlen(value) - 1] == '\'')) { + if ((*value == '"') && (value[strlen(value) - 1] == '"')) { value[strlen(value) - 1] = '\0'; value += 1; } @@ -162,7 +200,7 @@ /* Valid name[=:]value pair found, call handler */ strncpy0(prev_name, name, sizeof(prev_name)); - if (!handler(user, section, name, value) && !error) + if (!HANDLER(user, section, name, value) && !error) error = lineno; } else if (!error) { @@ -203,3 +241,40 @@ fclose(file); return error; } + +/* An ini_reader function to read the next line from a string buffer. This + is the fgets() equivalent used by ini_parse_string(). */ +static char* ini_reader_string(char* str, int num, void* stream) { + ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream; + const char* ctx_ptr = ctx->ptr; + size_t ctx_num_left = ctx->num_left; + char* strp = str; + char c; + + if (ctx_num_left == 0 || num < 2) + return NULL; + + while (num > 1 && ctx_num_left != 0) { + c = *ctx_ptr++; + ctx_num_left--; + *strp++ = c; + if (c == '\n') + break; + num--; + } + + *strp = '\0'; + ctx->ptr = ctx_ptr; + ctx->num_left = ctx_num_left; + return str; +} + +/* See documentation in header file. */ +int ini_parse_string(const char* string, ini_handler handler, void* user) { + ini_parse_string_ctx ctx; + + ctx.ptr = string; + ctx.num_left = strlen(string); + return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler, + user); +} diff -Nur a/lib/inih/src/ini.h b/lib/inih/src/ini.h --- a/lib/inih/src/ini.h +++ b/lib/inih/src/ini.h @@ -17,9 +17,20 @@ #include <stdio.h> +/* Nonzero if ini_handler callback should accept lineno parameter. */ +#ifndef INI_HANDLER_LINENO +#define INI_HANDLER_LINENO 0 +#endif + /* Typedef for prototype of handler function. */ +#if INI_HANDLER_LINENO +typedef int (*ini_handler)(void* user, const char* section, + const char* name, const char* value, + int lineno); +#else typedef int (*ini_handler)(void* user, const char* section, const char* name, const char* value); +#endif /* Typedef for prototype of fgets-style reader function. */ typedef char* (*ini_reader)(char* str, int num, void* stream); @@ -44,10 +55,16 @@ int ini_parse_file(FILE* file, ini_handler handler, void* user); /* Same as ini_parse(), but takes an ini_reader function pointer instead of - filename. Used for implementing custom or string-based I/O. */ + filename. Used for implementing custom or string-based I/O (see also + ini_parse_string). */ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, void* user); +/* Same as ini_parse(), but takes a zero-terminated string with the INI data +instead of a file. Useful for parsing INI data from a network socket or +already in memory. */ +int ini_parse_string(const char* string, ini_handler handler, void* user); + /* Nonzero to allow multi-line value parsing, in the style of Python's configparser. If allowed, ini_parse() will call the handler with the same name for each subsequent line parsed. */ @@ -61,6 +78,12 @@ #define INI_ALLOW_BOM 1 #endif +/* Chars that begin a start-of-line comment. Per Python configparser, allow + both ; and # comments at the start of a line by default. */ +#ifndef INI_START_COMMENT_PREFIXES +#define INI_START_COMMENT_PREFIXES ";#" +#endif + /* Nonzero to allow inline comments (with valid inline comment characters specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match Python 3.2+ configparser behaviour. */ @@ -71,21 +94,35 @@ #define INI_INLINE_COMMENT_PREFIXES ";" #endif -/* Nonzero to use stack, zero to use heap (malloc/free). */ +/* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */ #ifndef INI_USE_STACK #define INI_USE_STACK 1 #endif +/* Maximum line length for any line in INI file (stack or heap). Note that + this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */ +#ifndef INI_MAX_LINE +#define INI_MAX_LINE 200 +#endif + +/* Nonzero to allow heap line buffer to grow via realloc(), zero for a + fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is + zero. */ +#ifndef INI_ALLOW_REALLOC +#define INI_ALLOW_REALLOC 0 +#endif + +/* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK + is zero. */ +#ifndef INI_INITIAL_ALLOC +#define INI_INITIAL_ALLOC 200 +#endif + /* Stop parsing on first error (default is to keep parsing). */ #ifndef INI_STOP_ON_FIRST_ERROR #define INI_STOP_ON_FIRST_ERROR 0 #endif -/* Maximum line length for any line in INI file. */ -#ifndef INI_MAX_LINE -#define INI_MAX_LINE 200 -#endif - #ifdef __cplusplus } #endif diff -Nur a/src/datasource/rpname.c b/src/datasource/rpname.c --- a/src/datasource/rpname.c +++ b/src/datasource/rpname.c @@ -154,7 +154,7 @@ strncpy(returnValue, v, PROC_PID_STATUS_VAL_MAX_LENGTH); returnValue[PROC_PID_STATUS_VAL_MAX_LENGTH_STR-1] = 0; // Change newline into null character } else { - strncpy(returnValue, v, PROC_PID_STATUS_VAL_MAX_LENGTH_STR); + strncpy(returnValue, v, PROC_PID_STATUS_VAL_MAX_LENGTH_STR-1); } // Do a cleanup and return a string duplicate, which should be freed by the caller diff -Nur a/src/filtering.c b/src/filtering.c --- a/src/filtering.c +++ b/src/filtering.c @@ -59,7 +59,6 @@ char *filterChain ) { char filterChainCopy[SNOOPY_FILTER_CHAIN_MAX_SIZE]; // Must be here, or strtok_r segfaults - int filterChainCopySize; int j; char *str; char *rest; @@ -67,12 +66,8 @@ char *fcPos_filterSpecArg; // Pointer to argument part of single filter specification in a filter chain // Copy the filter chain specification to separate string, to be used in strtok_r - filterChainCopySize = strlen(filterChain); - if (filterChainCopySize > SNOOPY_FILTER_CHAIN_MAX_SIZE - 1) { - filterChainCopySize = SNOOPY_FILTER_CHAIN_MAX_SIZE - 1; - } - strncpy(filterChainCopy, filterChain, filterChainCopySize); - filterChainCopy[filterChainCopySize] = '\0'; + strncpy(filterChainCopy, filterChain, SNOOPY_FILTER_CHAIN_MAX_SIZE - 1); + filterChainCopy[SNOOPY_FILTER_CHAIN_MAX_SIZE-1] = '\0'; // Loop through all filters for (j=1, str=filterChainCopy; ; j++, str=NULL) {