~emersion/public-inbox

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH libscfg] Fix all memory leaks

Details
Message ID
<20230802180545.562127-2-vyivel@eclair.cafe>
DKIM signature
missing
Download raw message
Patch: +93 -49
---
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, &param);
			if (res != 0) {
				return res;
				free(param);
				goto end;
			}
			res = buffer_append(&params_buf, &param, sizeof(param));
			if (res != 0) {
				free(param);
				goto end;
			}
			buffer_append(&params_buf, &param, sizeof(param));
			parser_consume_whitespace(parser);
			break;
		}
	}

end:
	dir->params_len = params_buf.len / sizeof(char *);
	dir->params = buffer_steal(&params_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
Details
Message ID
<mPASggXI11RHIkrE7oYY8jsFC2zHU_3Byefct1Ak5AkiXI6rFlAl6waGieeX269QFuWoRgqskLym_j3o7xnSiMFjdrQzah9cgiWjY6Y3UaI=@emersion.fr>
In-Reply-To
<20230802180545.562127-2-vyivel@eclair.cafe> (view parent)
DKIM signature
missing
Download raw message
Pushed, thanks!
Reply to thread Export thread (mbox)