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.
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
form.

58
ell.c
View File

@ -270,8 +270,10 @@ lexer_free (struct lexer *self) {
free (self->string.s);
}
// FIXME: other isspace() stuff is missing
static bool lexer_is_word_char (int c) { return !strchr ("()[]{}\n@#' ", c); }
static bool lexer_is_ignored (int c) { return c == ' ' || c == '\t'; }
static bool lexer_is_word_char (int c) {
return !lexer_is_ignored (c) && !strchr ("()[]{}\n@#' ", c);
}
static int
lexer_advance (struct lexer *self) {
@ -286,11 +288,10 @@ lexer_advance (struct lexer *self) {
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);
// TODO: see "script", we can just use error constants to avoid allocation
static void
static bool
lexer_error (struct lexer *self, char **e, const char *fmt, ...) {
va_list ap;
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",
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)
abort ();
free (description);
return false;
}
static bool
@ -333,10 +335,8 @@ lexer_hexa_escape (struct lexer *self, struct buffer *output) {
static bool
lexer_escape_sequence (struct lexer *self, struct buffer *output, char **e) {
if (!self->len) {
lexer_error (self, e, "premature end of escape sequence");
return false;
}
if (!self->len)
return lexer_error (self, e, "premature end of escape sequence");
unsigned char c = *self->p;
switch (c) {
@ -356,12 +356,10 @@ lexer_escape_sequence (struct lexer *self, struct buffer *output, char **e) {
if (lexer_hexa_escape (self, output))
return true;
lexer_error (self, e, "invalid hexadecimal escape");
return false;
return lexer_error (self, e, "invalid hexadecimal escape");
default:
lexer_error (self, e, "unknown escape sequence");
return false;
return lexer_error (self, e, "unknown escape sequence");
}
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))
return false;
}
lexer_error (self, e, "premature end of string");
return false;
return lexer_error (self, e, "premature end of string");
}
static enum token
lexer_next (struct lexer *self, char **e) {
// 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);
if (!self->len)
return T_ABORT;
@ -428,6 +425,8 @@ lexer_next (struct lexer *self, char **e) {
// --- Parsing -----------------------------------------------------------------
// FIXME: the parser generally ignores memory allocation errors
static void
print_string (const char *s) {
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 item *variables; ///< List of variables
@ -704,7 +706,6 @@ get (struct context *ctx, const char *name) {
return NULL;
}
// FIXME: cloning and removing
static bool
set (struct context *ctx, const char *name, struct item *value) {
struct item *iter, *key = NULL, *pair = NULL;
@ -713,12 +714,19 @@ set (struct context *ctx, const char *name, struct item *value) {
break;
if (iter) {
item_free (iter->head->next);
iter->head->next = value;
if (!(iter->head->next = new_clone (value))) {
ctx->memory_failure = true;
return false;
}
return true;
}
if ((key = new_string (name, strlen (name)))
&& (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;
ctx->variables = pair;
return true;
@ -756,10 +764,12 @@ rename_arguments (struct context *ctx, struct item *names) {
if (names->type != ITEM_STRING)
continue;
if (value)
set (ctx, names->value, new_clone (value));
else
set (ctx, names->value, NULL);
if (value && !(value = new_clone (value))) {
ctx->memory_failure = true;
return false;
}
if (!set (ctx, names->value, value))
return false;
}
return true;
}