From ae33e6410273f4e4c1347eef012bfa8c58c0ec53 Mon Sep 17 00:00:00 2001 From: Ian Henderson Date: Wed, 8 Jan 2025 13:14:57 -0800 Subject: [PATCH] Detect and report some allocation errors. See https://github.com/ianh/owl/issues/45. --- doc/generated-parser.md | 1 + src/6a-generate.c | 11 +++++++++++ src/x-tokenize.h | 7 ++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/doc/generated-parser.md b/doc/generated-parser.md index 55ed2c8..ad2fb99 100644 --- a/doc/generated-parser.md +++ b/doc/generated-parser.md @@ -95,6 +95,7 @@ There are a few kinds of errors that can happen while creating a tree (see the t | `ERROR_INVALID_TOKEN` | Part of the text didn't match any valid token. | A range that begins with the first unrecognized character. | | `ERROR_UNEXPECTED_TOKEN` | The parser encountered an out-of-place token that didn't fit the grammar. | The range of the unexpected token. | | `ERROR_MORE_INPUT_NEEDED` | The input is valid so far, but incomplete; more tokens are necessary to complete it. | A range positioned at the end of the input. | +| `ERROR_ALLOCATION_FAILURE` | A call to a system allocator returned NULL. Note that not all allocation failures are currently detected. | None. | To handle the error yourself, you can use `owl_tree_get_error`. The `range` parameter is optional; if you pass a non-null pointer, it will be filled with a byte range as described in the table above. diff --git a/src/6a-generate.c b/src/6a-generate.c index 0836abf..8daca55 100644 --- a/src/6a-generate.c +++ b/src/6a-generate.c @@ -282,6 +282,9 @@ void generate(struct generator *gen) output_line(out, " // The input is valid so far, but incomplete; more tokens could be added to"); output_line(out, " // complete it."); output_line(out, " ERROR_MORE_INPUT_NEEDED,"); + output_line(out, ""); + output_line(out, " // A call to a system allocator returned NULL."); + output_line(out, " ERROR_ALLOCATION_FAILURE,"); output_line(out, "};"); output_line(out, "// Returns an error code, or ERROR_NONE if there wasn't an error."); output_line(out, "// The error_range parameter can be null."); @@ -656,6 +659,9 @@ void generate(struct generator *gen) output_line(out, " case ERROR_MORE_INPUT_NEEDED:"); output_line(out, " fprintf(stderr, \"more input needed\\n\");"); output_line(out, " break;"); + output_line(out, " case ERROR_ALLOCATION_FAILURE:"); + output_line(out, " fprintf(stderr, \"allocation failure\\n\");"); + output_line(out, " break;"); output_line(out, " default:"); output_line(out, " break;"); output_line(out, " }"); @@ -1176,6 +1182,11 @@ void generate(struct generator *gen) output_line(out, " }"); output_line(out, " struct fill_run_state top = c.stack[c.top_index];"); output_line(out, " free(c.stack);"); + output_line(out, " if (tokenizer.allocation_failed) {"); + output_line(out, " tree->error = ERROR_ALLOCATION_FAILURE;"); + output_line(out, " free_token_runs(&token_run);"); + output_line(out, " return;"); + output_line(out, " }"); output_line(out, " if (string[tokenizer.offset] != '\\0') {"); output_line(out, " tree->error = ERROR_INVALID_TOKEN;"); output_line(out, " estimate_next_token_range(&tokenizer, &tree->error_range.start, &tree->error_range.end);"); diff --git a/src/x-tokenize.h b/src/x-tokenize.h index 49e69c8..d5a33e7 100644 --- a/src/x-tokenize.h +++ b/src/x-tokenize.h @@ -137,6 +137,9 @@ struct owl_default_tokenizer { // The `info` pointer is passed to READ_KEYWORD_TOKEN. void *info; + + // Communicate allocation failures to the caller. + bool allocation_failed; }; static bool char_is_whitespace(char c) @@ -241,8 +244,10 @@ owl_default_tokenizer_advance(struct owl_default_tokenizer *tokenizer, if (tokenizer->text[tokenizer->offset] == '\0') return false; struct owl_token_run *run = malloc(sizeof(struct owl_token_run)); - if (!run) + if (!run) { + tokenizer->allocation_failed = true; return false; + } uint16_t number_of_tokens = 0; uint16_t lengths_size = 0; const char *text = tokenizer->text;