summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpeter <peter@pmikkelsen.com>2026-10-04 17:04:28 +0000
committerpeter <peter@pmikkelsen.com>2026-10-04 17:04:28 +0000
commitc5a489d7f82535a70488dd4f9e40e79f32a7fb2f (patch)
tree3f6e214b395d9655e054508128fcf373a6dfd39b /src
parentb66229d60635784ed289dd9bf0058f5c165ca8b5 (diff)
Fix the crashes found by the fuzzer so far.
I really need to think of a better way to store those crash inputs. FossilOrigin-Name: a8b84fbc85ec0b472aca930d2d0af27949b39940317114cc37d37044bf1975d5
Diffstat (limited to 'src')
-rw-r--r--src/lib/aplwc_internal.h1
-rw-r--r--src/lib/memory.c12
-rw-r--r--src/lib/module.c2
-rw-r--r--src/lib/string.c8
-rw-r--r--src/lib/syntax.c86
5 files changed, 50 insertions, 59 deletions
diff --git a/src/lib/aplwc_internal.h b/src/lib/aplwc_internal.h
index ca7e719..148fd58 100644
--- a/src/lib/aplwc_internal.h
+++ b/src/lib/aplwc_internal.h
@@ -163,6 +163,7 @@ int valid_ref(struct aplwc_ref *);
#define MEMPTRS_EXIT(aplwc) memptrs_remove(aplwc, &memptrs_frame)
/* string.c */
+#define INVALID_CHAR UINT32_MAX
struct string *chars_to_string(struct aplwc *, const char *, int len);
uint32_t string_char(struct string *, size_t);
size_t char_length(struct string *, size_t);
diff --git a/src/lib/memory.c b/src/lib/memory.c
index a8317c7..006c409 100644
--- a/src/lib/memory.c
+++ b/src/lib/memory.c
@@ -441,8 +441,7 @@ compact(struct aplwc *aplwc)
static void *
alloc(struct aplwc *aplwc, size_t size, enum chunk_tag tag)
{
- struct chunk *free;
- struct chunk *new;
+ struct chunk *free, *new;
size_t pad;
int attempt;
@@ -454,7 +453,7 @@ alloc(struct aplwc *aplwc, size_t size, enum chunk_tag tag)
attempt = 0;
retry:
DEBUG(check_mem(aplwc));
- free = FAILCASE(find_free(aplwc, size), NULL);
+ new = free = FAILCASE(find_free(aplwc, size), NULL);
if(!free){
switch(attempt++){
case 0:
@@ -469,14 +468,12 @@ retry:
/* fall-through */
default:
aplwc->last_error = APLWC_OUT_OF_MEMORY;
- return NULL;
+ goto end;
}
}
assert(free->tag == CHUNK_TAG_FREE);
- new = free;
-
if(free->size > (size + 2*HEADER_SIZE)){
free = (struct chunk *)(((uint8_t*)free) + HEADER_SIZE + size);
free->tag = CHUNK_TAG_FREE;
@@ -496,8 +493,9 @@ retry:
new->tag = tag;
new->reachable = aplwc->reachable_bit;
+end:
DEBUG(check_mem(aplwc));
- return data(new);
+ return new ? data(new) : NULL;
}
void
diff --git a/src/lib/module.c b/src/lib/module.c
index 9c2cbc2..22b8eac 100644
--- a/src/lib/module.c
+++ b/src/lib/module.c
@@ -28,8 +28,6 @@ add_member(struct aplwc *aplwc, struct aplwc_module *module, symbol_t name, stru
for(m = module->members; m; m = m->link){
if(m->name == name){
- if(real_member)
- assert(m->real_member == NULL || m->real_member == real_member);
m->real_member = real_member;
m->exported |= export;
goto end;
diff --git a/src/lib/string.c b/src/lib/string.c
index 4101b80..0c01fca 100644
--- a/src/lib/string.c
+++ b/src/lib/string.c
@@ -104,6 +104,10 @@ string_char(struct string *string, size_t offset)
uint32_t c;
size_t len, i;
+ assert(offset <= string->bytes);
+ if(offset == string->bytes)
+ return INVALID_CHAR;
+
c = 0;
len = char_length(string, offset);
switch(char_length(string, offset)){
@@ -134,8 +138,8 @@ char_length(struct string *string, size_t offset)
{
uint8_t b;
- if(offset >= string->bytes)
- return 0;
+ assert(offset < string->bytes);
+
b = string->utf8[offset];
assert(!((b & 0xC0) == 0x80));
diff --git a/src/lib/syntax.c b/src/lib/syntax.c
index 3354050..5b60fac 100644
--- a/src/lib/syntax.c
+++ b/src/lib/syntax.c
@@ -56,8 +56,10 @@ peek(struct scan_state *state)
static uint32_t
advance(struct scan_state *state)
{
- state->offset += char_length(*state->text, state->offset);
- state->skip_number_and_identifier = 0;
+ if(peek(state) != INVALID_CHAR){
+ state->offset += char_length(*state->text, state->offset);
+ state->skip_number_and_identifier = 0;
+ }
return peek(state);
}
@@ -81,7 +83,7 @@ skip_space(struct scan_state *state)
#define T tokens->tokens[token_index]
static enum aplwc_rc
-single_sym(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
+single_sym(struct scan_state *state, struct token_list *tokens, size_t token_index)
{
uint32_t c;
size_t start;
@@ -110,11 +112,9 @@ single_sym(struct scan_state *state, struct token_list *tokens, size_t token_ind
goto end;
}
T.tag = TOKEN_TAG_UNKNOWN_SYM;
- if(!check_only){
- if((rc = newsym(state, start, 1, &sym)) != APLWC_OK)
- goto end;
- T.data.symbol = sym;
- }
+ if((rc = newsym(state, start, 1, &sym)) != APLWC_OK)
+ goto end;
+ T.data.symbol = sym;
break;
}
@@ -125,7 +125,7 @@ end:
}
static enum aplwc_rc
-identifier(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
+identifier(struct scan_state *state, struct token_list *tokens, size_t token_index)
{
uint32_t c;
size_t start, len;
@@ -148,11 +148,9 @@ identifier(struct scan_state *state, struct token_list *tokens, size_t token_ind
}while(is_id_continue(c));
T.tag = TOKEN_TAG_IDENTIFIER;
- if(!check_only){
- if((rc = newsym(state, start, len, &sym)) != APLWC_OK)
- goto end;
- T.data.symbol = sym;
- }
+ if((rc = newsym(state, start, len, &sym)) != APLWC_OK)
+ goto end;
+ T.data.symbol = sym;
state->skip_number_and_identifier = 1;
rc = APLWC_OK;
@@ -162,7 +160,7 @@ end:
}
static enum aplwc_rc
-keyword(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
+keyword(struct scan_state *state, struct token_list *tokens, size_t token_index)
{
uint32_t c;
size_t start, len;
@@ -180,35 +178,30 @@ keyword(struct scan_state *state, struct token_list *tokens, size_t token_index,
c = advance(state);
start = state->offset;
- len = 0;
- do{
- c = advance(state);
+ for(len = 0; is_id_continue(c); c = advance(state))
len++;
- }while(is_id_continue(c));
rc = APLWC_OK;
T.tag = TOKEN_TAG_KEYWORD;
- if(!check_only){
- if((rc = newsym(state, start, len, &sym)) != APLWC_OK)
- goto end;
+ if((rc = newsym(state, start, len, &sym)) != APLWC_OK)
+ goto end;
- for(kw = 0; kw < N_KWDS; kw++){
- if(sym == state->aplwc->keyword_symbols[kw]){
- T.data.keyword = kw;
- break;
- }
+ for(kw = 0; kw < N_KWDS; kw++){
+ if(sym == state->aplwc->keyword_symbols[kw]){
+ T.data.keyword = kw;
+ break;
}
- if(kw == N_KWDS)
- rc = APLWC_INVALID_SYNTAX;
-
}
+ if(kw == N_KWDS)
+ rc = APLWC_INVALID_SYNTAX;
+
end:
MEMPTRS_EXIT(state->aplwc);
return rc;
}
static enum aplwc_rc
-number(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
+number(struct scan_state *state, struct token_list *tokens, size_t token_index)
{
uint32_t c;
int has_digits;
@@ -217,8 +210,6 @@ number(struct scan_state *state, struct token_list *tokens, size_t token_index,
MEMPTRS(state->aplwc, 1);
MEMPTR(0, tokens);
- UNUSED_PARAMETER(check_only);
-
rc = APLWC_INVALID_SYNTAX;
c = peek(state);
@@ -260,7 +251,7 @@ end:
}
static enum aplwc_rc
-text(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
+text(struct scan_state *state, struct token_list *tokens, size_t token_index)
{
uint32_t c;
enum aplwc_rc rc;
@@ -268,8 +259,6 @@ text(struct scan_state *state, struct token_list *tokens, size_t token_index, in
MEMPTRS(state->aplwc, 1);
MEMPTR(0, tokens);
- UNUSED_PARAMETER(check_only);
-
rc = APLWC_INVALID_SYNTAX;;
c = peek(state);
if(c != '\'')
@@ -277,7 +266,7 @@ text(struct scan_state *state, struct token_list *tokens, size_t token_index, in
do
c = advance(state);
- while((c != '\n') && (c != 0) && (c != '\''));
+ while((c != '\n') && (c != INVALID_CHAR) && (c != '\''));
if(c == '\'')
advance(state);
@@ -292,7 +281,7 @@ end:
}
static enum aplwc_rc
-comment(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
+comment(struct scan_state *state, struct token_list *tokens, size_t token_index)
{
uint32_t c;
enum aplwc_rc rc;
@@ -300,8 +289,6 @@ comment(struct scan_state *state, struct token_list *tokens, size_t token_index,
MEMPTRS(state->aplwc, 1);
MEMPTR(0, tokens);
- UNUSED_PARAMETER(check_only);
-
rc = APLWC_INVALID_SYNTAX;
c = peek(state);
if(c != 0x235D)
@@ -319,11 +306,11 @@ end:
}
static enum aplwc_rc
-next_token(struct scan_state *state, struct token_list *tokens, size_t token_index, int check_only)
+next_token(struct scan_state *state, struct token_list *tokens, size_t token_index)
{
enum aplwc_rc rc;
size_t i;
- enum aplwc_rc (*scans[])(struct scan_state *, struct token_list *, size_t, int) = {
+ enum aplwc_rc (*scans[])(struct scan_state *, struct token_list *, size_t) = {
identifier,
keyword,
number,
@@ -338,12 +325,12 @@ next_token(struct scan_state *state, struct token_list *tokens, size_t token_ind
T.start = state->offset;
rc = APLWC_INVALID_SYNTAX;
for(i = 0; (rc == APLWC_INVALID_SYNTAX) && (i < NELEM(scans)); i++){
- rc = scans[i](state, tokens, token_index, check_only);
+ rc = scans[i](state, tokens, token_index);
switch(rc){
case APLWC_OK:
break;
case APLWC_INVALID_SYNTAX:
- state->offset = tokens->tokens[token_index].start;
+ state->offset = T.start;
break;
default:
goto end;
@@ -374,11 +361,13 @@ check(struct aplwc *aplwc, struct string *text, size_t *n)
goto end;
}
MEMPTR(1, tokens);
+ tokens->text = text;
+ tokens->length = 1;
init_scan_state(&state, aplwc, &text);
- for(count = 0; peek(&state); count++){
- ret = next_token(&state, tokens, 0, 1);
+ for(count = 0; peek(&state) != INVALID_CHAR; count++){
+ ret = next_token(&state, tokens, 0);
if(ret != APLWC_OK)
goto end;
}
@@ -404,8 +393,9 @@ scan(struct aplwc *aplwc, struct string *text, struct token_list *tokens)
init_scan_state(&state, aplwc, &text);
ret = APLWC_OK;
- for(count = 0; (ret == APLWC_OK) && peek(&state); count++){
- ret = next_token(&state, tokens, count, 0);
+ for(count = 0; (ret == APLWC_OK) && (peek(&state) != INVALID_CHAR); count++){
+ assert(count < tokens->length);
+ ret = next_token(&state, tokens, count);
}
MEMPTRS_EXIT(aplwc);