From 5d5042fdec2928433ae611c8fe45c75d159af010 Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Fri, 19 May 2017 19:22:44 +0200 Subject: Add allocation error handling to the parser --- ell.c | 96 +++++++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 56 insertions(+), 40 deletions(-) diff --git a/ell.c b/ell.c index ad52af5..043fad5 100755 --- a/ell.c +++ b/ell.c @@ -203,8 +203,10 @@ new_string (const char *s, ssize_t len) { static struct item * new_list (struct item *head) { struct item *item = calloc (1, sizeof *item + 1); - if (!item) + if (!item) { + item_free_list (head); return NULL; + } item->type = ITEM_LIST; item->head = head; @@ -453,6 +455,7 @@ struct parser char *error; ///< Tokenizer error enum token token; ///< Current token in the lexer bool replace_token; ///< Replace the token + bool memory_failure; ///< Memory allocation failed }; static void @@ -478,11 +481,13 @@ parser_peek (struct parser *self, jmp_buf out) { const char *e = NULL; self->token = lexer_next (&self->lexer, &e); if (e) { - // TODO: check memory error - self->error = lexer_errorf (&self->lexer, "%s", e); + self->memory_failure = + !(self->error = lexer_errorf (&self->lexer, "%s", e)); longjmp (out, 1); } - // TODO: with T_STRING check for memory error within + if (self->token == T_STRING + && (self->memory_failure = self->lexer.string.memory_failure)) + longjmp (out, 1); self->replace_token = false; } return self->token; @@ -498,10 +503,9 @@ parser_expect (struct parser *self, enum token token, jmp_buf out) { if (parser_accept (self, token, out)) return; - // TODO: check memory error - self->error = lexer_errorf (&self->lexer, "unexpected `%s', expected `%s'", - token_name (self->token), - token_name (token)); + self->memory_failure = !(self->error = lexer_errorf (&self->lexer, + "unexpected `%s', expected `%s'", + token_name (self->token), token_name (token))); longjmp (out, 1); } @@ -515,24 +519,37 @@ parser_expect (struct parser *self, enum token token, jmp_buf out) { #define EXPECT(token) parser_expect (self, token, err) #define SKIP_NL() do {} while (ACCEPT (T_NEWLINE)) -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +static struct item * +parser_check (struct parser *self, struct item *item, jmp_buf out) { + if (!item) { + self->memory_failure = true; + longjmp (out, 1); + } + return item; +} -static struct item * parse_line (struct parser *self, jmp_buf out); +// Beware that this jumps to the "out" buffer directly +#define CHECK(item) parser_check (self, (item), out) + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static struct item * parse_prefix_list (struct item *list, const char *name) { - // TODO: check memory error - struct item *prefix = new_string (name, strlen (name)); + struct item *prefix; + if (!(prefix = new_string (name, strlen (name)))) { + item_free_list (list); + return NULL; + } prefix->next = list; - // TODO: check memory error return new_list (prefix); } +static struct item * parse_line (struct parser *self, jmp_buf out); + static struct item * parse_item (struct parser *self, jmp_buf out) { - struct item *volatile result = NULL, *volatile *tail = &result; jmp_buf err; - + struct item *volatile result = NULL, *volatile *tail = &result; if (setjmp (err)) { item_free_list (result); longjmp (out, 1); @@ -540,48 +557,43 @@ parse_item (struct parser *self, jmp_buf out) { SKIP_NL (); if (ACCEPT (T_STRING)) - // TODO: check memory error, also in "self->lexer.string" - return new_string (self->lexer.string.s, self->lexer.string.len); + return CHECK (new_string + (self->lexer.string.s, self->lexer.string.len)); if (ACCEPT (T_AT)) { result = parse_item (self, out); - return parse_prefix_list (result, "set"); + return CHECK (parse_prefix_list (result, "set")); } if (ACCEPT (T_LPAREN)) { while (!ACCEPT (T_RPAREN)) { - *tail = parse_item (self, err); - tail = &(*tail)->next; + tail = &(*tail = parse_item (self, err))->next; SKIP_NL (); } - // TODO: check memory error - return new_list (result); + return CHECK (new_list (result)); } if (ACCEPT (T_LBRACKET)) { while (!ACCEPT (T_RBRACKET)) { - *tail = parse_item (self, err); - tail = &(*tail)->next; + tail = &(*tail = parse_item (self, err))->next; SKIP_NL (); } - return parse_prefix_list (result, "list"); + return CHECK (parse_prefix_list (result, "list")); } if (ACCEPT (T_LBRACE)) { while ((*tail = parse_line (self, err))) tail = &(*tail)->next; EXPECT (T_RBRACE); - // TODO: check memory error - return parse_prefix_list (new_list (result), "quote"); + result = CHECK (new_list (result)); + return CHECK (parse_prefix_list (result, "quote")); } - // TODO: check memory error - self->error = lexer_errorf (&self->lexer, - "unexpected `%s', expected a value", token_name (self->token)); + self->memory_failure = !(self->error = lexer_errorf (&self->lexer, + "unexpected `%s', expected a value", token_name (self->token))); longjmp (out, 1); } static struct item * parse_line (struct parser *self, jmp_buf out) { - struct item *volatile result = NULL, *volatile *tail = &result; jmp_buf err; - + struct item *volatile result = NULL, *volatile *tail = &result; if (setjmp (err)) { item_free_list (result); longjmp (out, 1); @@ -589,16 +601,13 @@ parse_line (struct parser *self, jmp_buf out) { while (PEEK () != T_RBRACE && PEEK () != T_ABORT) { if (!ACCEPT (T_NEWLINE)) { - *tail = parse_item (self, err); - tail = &(*tail)->next; + tail = &(*tail = parse_item (self, err))->next; } else if (result) { - // TODO: check memory error - return new_list (result); + return CHECK (new_list (result)); } } if (result) - // TODO: check memory error - return new_list (result); + return CHECK (new_list (result)); return NULL; } @@ -608,19 +617,25 @@ parse_line (struct parser *self, jmp_buf out) { #undef ACCEPT #undef EXPECT #undef SKIP_NL +#undef CHECK static struct item * parse (const char *s, size_t len, char **e) { struct parser parser; parser_init (&parser, s, len); - struct item *volatile result = NULL, *volatile *tail = &result; jmp_buf err; - + struct item *volatile result = NULL, *volatile *tail = &result; if (setjmp (err)) { item_free_list (result); *e = parser.error; lexer_free (&parser.lexer); + + // TODO: figure out how to handle this, since the return value + // may be null and we may not be able to allocate an error message + if (parser.memory_failure) + abort (); + return NULL; } @@ -917,6 +932,7 @@ init_runtime_library_scripts (struct context *ctx) { char *e = NULL; struct item *body = parse (functions[i].definition, strlen (functions[i].definition), &e); + // TODO: also handle memory allocation errors if (e) { printf ("error parsing internal function `%s': %s\n", functions[i].definition, e); -- cgit v1.2.3-70-g09d2