Kirill Primak: 1 Fix all memory leaks 1 files changed, 93 insertions(+), 49 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~emersion/public-inbox/patches/43219/mbox | git am -3Learn more about email & git
--- Note: this assumes that the library user always calls scfg_block_finish() regardless of whether parsing a file has succeeded or not. scfg.c | 142 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 93 insertions(+), 49 deletions(-) diff --git a/scfg.c b/scfg.c index a5a9419..41d39a0 100644 --- a/scfg.c +++ b/scfg.c @@ -37,17 +37,21 @@ static int buffer_append_char(struct scfg_buffer *buf, char ch) { return buffer_append(buf, &ch, 1); } -static void buffer_finish(struct scfg_buffer *buf) { - free(buf->data); - memset(buf, 0, sizeof(*buf)); -} - static void *buffer_steal(struct scfg_buffer *buf) { void *data = buf->data; memset(buf, 0, sizeof(*buf)); return data; } +static void directive_finish(struct scfg_directive *dir) { + free(dir->name); + for (size_t i = 0; i < dir->params_len; i++) { + free(dir->params[i]); + } + free(dir->params); + scfg_block_finish(&dir->children); +} + struct scfg_parser { FILE *f; int prev_ch; @@ -106,11 +110,14 @@ static void parser_consume_line(struct scfg_parser *parser) { } static int parser_read_atom(struct scfg_parser *parser, char **str_ptr) { + int res = 0; + struct scfg_buffer buf = {0}; while (1) { int ch = parser_read_char(parser); if (ch < 0) { - return ch; + res = ch; + goto end; } switch (ch) { @@ -119,80 +126,106 @@ static int parser_read_atom(struct scfg_parser *parser, char **str_ptr) { case '\t': case '\n': parser_unread_char(parser); - buffer_append_char(&buf, '\0'); - *str_ptr = buffer_steal(&buf); - return 0; + res = buffer_append_char(&buf, '\0'); + goto end; case '"': case '\'': case '{': case '}': - buffer_finish(&buf); fprintf(stderr, "scfg: unexpected '%c' in atom\n", ch); - return -EINVAL; + res = -EINVAL; + goto end; default: - buffer_append_char(&buf, ch); + res = buffer_append_char(&buf, ch); + if (res != 0) { + goto end; + } break; } } + +end: + *str_ptr = buffer_steal(&buf); + return res; } static int parser_read_dquote_word(struct scfg_parser *parser, char **str_ptr) { + int res = 0; + struct scfg_buffer buf = {0}; while (1) { int ch = parser_read_char(parser); if (ch < 0) { - return ch; + res = ch; + goto end; } switch (ch) { case '\0': case '\n': - buffer_finish(&buf); fprintf(stderr, "scfg: unterminated double-quoted string\n"); - return -EINVAL; + res = -EINVAL; + goto end; case '"': - buffer_append_char(&buf, '\0'); - *str_ptr = buffer_steal(&buf); - return 0; + res = buffer_append_char(&buf, '\0'); + goto end; case '\\': ch = parser_read_char(parser); if (ch < 0) { - return ch; + res = ch; + goto end; } else if (ch == '\n') { fprintf(stderr, "scfg: can't escape '\\n' in double-quoted string\n"); - return -EINVAL; + res = -EINVAL; + goto end; } /* fallthrough */ default: - buffer_append_char(&buf, ch); + res = buffer_append_char(&buf, ch); + if (res != 0) { + goto end; + } break; } } + +end: + *str_ptr = buffer_steal(&buf); + return res; } static int parser_read_squote_word(struct scfg_parser *parser, char **str_ptr) { + int res = 0; + struct scfg_buffer buf = {0}; while (1) { int ch = parser_read_char(parser); if (ch < 0) { - return ch; + res = ch; + goto end; } switch (ch) { case '\0': case '\n': - buffer_finish(&buf); fprintf(stderr, "scfg: unterminated single-quoted string\n"); - return -EINVAL; + res = -EINVAL; + goto end; case '\'': - buffer_append_char(&buf, '\0'); - *str_ptr = buffer_steal(&buf); - return 0; + res = buffer_append_char(&buf, '\0'); + goto end; default: - buffer_append_char(&buf, ch); + res = buffer_append_char(&buf, ch); + if (res != 0) { + goto end; + } break; } } + +end: + *str_ptr = buffer_steal(&buf); + return res; } static int parser_read_word(struct scfg_parser *parser, char **str_ptr) { @@ -229,17 +262,19 @@ static int parser_read_directive(struct scfg_parser *parser, struct scfg_directi while (1) { int ch = parser_read_char(parser); if (ch < 0) { - return ch; + res = ch; + goto end; } else if (ch == '\0' || ch == '\n') { break; } else if (ch == '{') { bool closing_brace = false; res = parser_read_block(parser, &dir->children, &closing_brace); if (res != 0) { - return res; + goto end; } else if (!closing_brace) { fprintf(stderr, "scfg: expected '}'\n"); - return -EINVAL; + res = -EINVAL; + goto end; } break; } @@ -247,36 +282,47 @@ static int parser_read_directive(struct scfg_parser *parser, struct scfg_directi switch (ch) { case '}': fprintf(stderr, "scfg: unexpected '}'\n"); - return -EINVAL; + res = -EINVAL; + goto end; default: parser_unread_char(parser); char *param = NULL; res = parser_read_word(parser, ¶m); if (res != 0) { - return res; + free(param); + goto end; + } + res = buffer_append(¶ms_buf, ¶m, sizeof(param)); + if (res != 0) { + free(param); + goto end; } - buffer_append(¶ms_buf, ¶m, sizeof(param)); parser_consume_whitespace(parser); break; } } + +end: dir->params_len = params_buf.len / sizeof(char *); dir->params = buffer_steal(¶ms_buf); - return 0; + return res; } static int parser_read_block(struct scfg_parser *parser, struct scfg_block *block, bool *closing_brace) { memset(block, 0, sizeof(*block)); *closing_brace = false; + int res = 0; + struct scfg_buffer dirs_buf = {0}; while (1) { parser_consume_whitespace(parser); int ch = parser_read_char(parser); if (ch < 0) { - return ch; + res = ch; + goto end; } else if (ch == '\n') { continue; } else if (ch == '#') { @@ -289,16 +335,23 @@ static int parser_read_block(struct scfg_parser *parser, struct scfg_block *bloc parser_unread_char(parser); struct scfg_directive dir = {0}; - int res = parser_read_directive(parser, &dir); + res = parser_read_directive(parser, &dir); if (res != 0) { - return res; + directive_finish(&dir); + goto end; + } + res = buffer_append(&dirs_buf, &dir, sizeof(dir)); + if (res != 0) { + directive_finish(&dir); + goto end; } - buffer_append(&dirs_buf, &dir, sizeof(dir)); } + +end: block->directives_len = dirs_buf.len / sizeof(struct scfg_directive); block->directives = buffer_steal(&dirs_buf); - return 0; + return res; } int scfg_load_file(struct scfg_block *block, const char *path) { @@ -325,15 +378,6 @@ int scfg_parse_file(struct scfg_block *block, FILE *f) { return 0; } -static void directive_finish(struct scfg_directive *dir) { - free(dir->name); - for (size_t i = 0; i < dir->params_len; i++) { - free(dir->params[i]); - } - free(dir->params); - scfg_block_finish(&dir->children); -} - void scfg_block_finish(struct scfg_block *block) { for (size_t i = 0; i < block->directives_len; i++) { directive_finish(&block->directives[i]); -- 2.41.0
Pushed, thanks!