Various mostly safety fixes

This commit is contained in:
Přemysl Eric Janouch 2017-05-18 20:45:46 +02:00
parent 5963b99c3e
commit 365d6e69e1
Signed by: p
GPG Key ID: B715679E3A361BE6
2 changed files with 35 additions and 25 deletions

View File

@ -47,7 +47,7 @@ Runtime
------- -------
All variables are put in a single global namespace with no further scoping. All variables are put in a single global namespace with no further scoping.
When calling a command (which is a list of lists), all arguments are When calling a command (which is a list of lists), all arguments are
automatically stored in variables named 1, 2, 3, ... n. They are however automatically stored in variables named 0, 1, 2, 3, ... n. They are however
effectively inaccessible and you must rename them first using the `arg` special effectively inaccessible and you must rename them first using the `arg` special
form. form.

58
ell.c
View File

@ -270,8 +270,10 @@ lexer_free (struct lexer *self) {
free (self->string.s); free (self->string.s);
} }
// FIXME: other isspace() stuff is missing static bool lexer_is_ignored (int c) { return c == ' ' || c == '\t'; }
static bool lexer_is_word_char (int c) { return !strchr ("()[]{}\n@#' ", c); } static bool lexer_is_word_char (int c) {
return !lexer_is_ignored (c) && !strchr ("()[]{}\n@#' ", c);
}
static int static int
lexer_advance (struct lexer *self) { lexer_advance (struct lexer *self) {
@ -286,11 +288,10 @@ lexer_advance (struct lexer *self) {
return c; return c;
} }
static void lexer_error (struct lexer *self, char **e, const char *fmt, ...) static bool lexer_error (struct lexer *self, char **e, const char *fmt, ...)
ATTRIBUTE_PRINTF (3, 4); ATTRIBUTE_PRINTF (3, 4);
// TODO: see "script", we can just use error constants to avoid allocation static bool
static void
lexer_error (struct lexer *self, char **e, const char *fmt, ...) { lexer_error (struct lexer *self, char **e, const char *fmt, ...) {
va_list ap; va_list ap;
va_start (ap, fmt); va_start (ap, fmt);
@ -300,11 +301,12 @@ lexer_error (struct lexer *self, char **e, const char *fmt, ...) {
*e = format ("near line %u, column %u: %s", *e = format ("near line %u, column %u: %s",
self->line + 1, self->column + 1, description); self->line + 1, self->column + 1, description);
// TODO: see above, we should be able to indicate error without allocation // TODO: see "script", we can just use error constants to avoid allocation
if (!*e) if (!*e)
abort (); abort ();
free (description); free (description);
return false;
} }
static bool static bool
@ -333,10 +335,8 @@ lexer_hexa_escape (struct lexer *self, struct buffer *output) {
static bool static bool
lexer_escape_sequence (struct lexer *self, struct buffer *output, char **e) { lexer_escape_sequence (struct lexer *self, struct buffer *output, char **e) {
if (!self->len) { if (!self->len)
lexer_error (self, e, "premature end of escape sequence"); return lexer_error (self, e, "premature end of escape sequence");
return false;
}
unsigned char c = *self->p; unsigned char c = *self->p;
switch (c) { switch (c) {
@ -356,12 +356,10 @@ lexer_escape_sequence (struct lexer *self, struct buffer *output, char **e) {
if (lexer_hexa_escape (self, output)) if (lexer_hexa_escape (self, output))
return true; return true;
lexer_error (self, e, "invalid hexadecimal escape"); return lexer_error (self, e, "invalid hexadecimal escape");
return false;
default: default:
lexer_error (self, e, "unknown escape sequence"); return lexer_error (self, e, "unknown escape sequence");
return false;
} }
buffer_append_c (output, c); buffer_append_c (output, c);
@ -380,14 +378,13 @@ lexer_string (struct lexer *self, struct buffer *output, char **e) {
else if (!lexer_escape_sequence (self, output, e)) else if (!lexer_escape_sequence (self, output, e))
return false; return false;
} }
lexer_error (self, e, "premature end of string"); return lexer_error (self, e, "premature end of string");
return false;
} }
static enum token static enum token
lexer_next (struct lexer *self, char **e) { lexer_next (struct lexer *self, char **e) {
// Skip over any whitespace between tokens // Skip over any whitespace between tokens
while (self->len && isspace (*self->p) && *self->p != '\n') while (self->len && lexer_is_ignored (*self->p))
lexer_advance (self); lexer_advance (self);
if (!self->len) if (!self->len)
return T_ABORT; return T_ABORT;
@ -428,6 +425,8 @@ lexer_next (struct lexer *self, char **e) {
// --- Parsing ----------------------------------------------------------------- // --- Parsing -----------------------------------------------------------------
// FIXME: the parser generally ignores memory allocation errors
static void static void
print_string (const char *s) { print_string (const char *s) {
putc ('\'', stdout); putc ('\'', stdout);
@ -675,6 +674,9 @@ register_native (const char *name, handler_fn handler) {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// TODO: fill in "error_is_fatal"
// TODO: probably add new_*() methods that set "memory_failure"
struct context { struct context {
struct item *variables; ///< List of variables struct item *variables; ///< List of variables
@ -704,7 +706,6 @@ get (struct context *ctx, const char *name) {
return NULL; return NULL;
} }
// FIXME: cloning and removing
static bool static bool
set (struct context *ctx, const char *name, struct item *value) { set (struct context *ctx, const char *name, struct item *value) {
struct item *iter, *key = NULL, *pair = NULL; struct item *iter, *key = NULL, *pair = NULL;
@ -713,12 +714,19 @@ set (struct context *ctx, const char *name, struct item *value) {
break; break;
if (iter) { if (iter) {
item_free (iter->head->next); item_free (iter->head->next);
iter->head->next = value; if (!(iter->head->next = new_clone (value))) {
ctx->memory_failure = true;
return false;
}
return true; return true;
} }
if ((key = new_string (name, strlen (name))) if ((key = new_string (name, strlen (name)))
&& (pair = new_list (NULL))) { && (pair = new_list (NULL))) {
(pair->head = key)->next = value; if (!((pair->head = key)->next = new_clone (value))) {
item_free (pair);
ctx->memory_failure = true;
return false;
}
pair->next = ctx->variables; pair->next = ctx->variables;
ctx->variables = pair; ctx->variables = pair;
return true; return true;
@ -756,10 +764,12 @@ rename_arguments (struct context *ctx, struct item *names) {
if (names->type != ITEM_STRING) if (names->type != ITEM_STRING)
continue; continue;
if (value) if (value && !(value = new_clone (value))) {
set (ctx, names->value, new_clone (value)); ctx->memory_failure = true;
else return false;
set (ctx, names->value, NULL); }
if (!set (ctx, names->value, value))
return false;
} }
return true; return true;
} }