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