From 69175e801a129cde4311cc70b2ffbe2913fbd084 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Tue, 26 May 2026 17:52:07 +1000 Subject: [PATCH] Fixed a hash collision causing null variables to be overwritten Andrew, don't you dare run my code through a clanker again or I'll hunt your Canuck ass down and beat you with a hockey stick. --- repl/bucket_inspector.c | 2 +- repl/main.c | 6 +++--- source/toy_attributes.c | 2 +- source/toy_compiler.c | 5 +++-- source/toy_parser.c | 4 ++-- source/toy_print.c | 4 ++++ source/toy_scope.c | 2 +- source/toy_vm.c | 2 ++ tests/scripts/test_variables.toy | 7 +++++++ 9 files changed, 24 insertions(+), 10 deletions(-) diff --git a/repl/bucket_inspector.c b/repl/bucket_inspector.c index 8bffbf6..d5717ef 100644 --- a/repl/bucket_inspector.c +++ b/repl/bucket_inspector.c @@ -13,7 +13,7 @@ int inspect_bucket(Toy_Bucket** bucketHandle) { unsigned char* ptr = iter->data; - while ((ptr - iter->data < iter->count) && *((int*)ptr) != 0) { //for each partition + while ((ptr >= iter->data) && (ptr < iter->data + iter->count) && *((int*)ptr) != 0) { //for each partition if ( ( *((int*)ptr) & 1) == 0) { //is this partition still in use? occupied++; diff --git a/repl/main.c b/repl/main.c index 241c42d..3fcdc2b 100644 --- a/repl/main.c +++ b/repl/main.c @@ -26,7 +26,7 @@ unsigned char* readFile(char* path, int* size) { //determine the file's length fseek(file, 0L, SEEK_END); - *size = ftell(file); + *size = (int)ftell(file); rewind(file); //make some space @@ -44,7 +44,7 @@ unsigned char* readFile(char* path, int* size) { return NULL; } - buffer[(*size)++] = '\0'; + buffer[(*size)] = '\0'; //clean up and return fclose(file); @@ -334,7 +334,7 @@ int repl(const char* filepath, bool verbose) { inputBuffer[--length] = '\0'; } - if (length == 0 || !inputBuffer[ strspn(inputBuffer, " \r\n\t") ]) { + if (length == 0 || inputBuffer[ strspn(inputBuffer, " \r\n\t") ] == '\0') { printf("%s> ", prompt); //shows the terminal prompt and restart continue; } diff --git a/source/toy_attributes.c b/source/toy_attributes.c index d9acfed..8f30995 100644 --- a/source/toy_attributes.c +++ b/source/toy_attributes.c @@ -172,7 +172,7 @@ static void attr_tableRemove(Toy_VM* vm, Toy_FunctionNative* self) { Toy_Value Toy_private_handleTableAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { if (MATCH_VALUE_AND_CSTRING(attribute, "length")) { - return TOY_VALUE_FROM_INTEGER(TOY_VALUE_AS_ARRAY(compound)->count); + return TOY_VALUE_FROM_INTEGER(TOY_VALUE_AS_TABLE(compound)->count); } else if (MATCH_VALUE_AND_CSTRING(attribute, "insert")) { Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_tableInsert); diff --git a/source/toy_compiler.c b/source/toy_compiler.c index a21c22d..ab939b2 100644 --- a/source/toy_compiler.c +++ b/source/toy_compiler.c @@ -78,6 +78,7 @@ static void emitByte(unsigned char** handle, unsigned int* capacity, unsigned in ((unsigned char*)(*handle))[(*count)++] = byte; } +//BUG: There might be issues here when compiled on big-endian platforms static void emitInt(unsigned char** handle, unsigned int* capacity, unsigned int* count, unsigned int bytes) { char* ptr = (char*)&bytes; emitByte(handle, capacity, count, *(ptr++)); @@ -200,8 +201,8 @@ static unsigned int emitParameters(Toy_Bytecode* mb, Toy_Ast* ast) { } //the address within the data section - char buffer[128]; - snprintf(buffer, 128, "%.*s", ast->varDeclare.name->info.length, ast->varDeclare.name->leaf.data); + char buffer[256]; + snprintf(buffer, 256, "%.*s", ast->varDeclare.name->info.length, ast->varDeclare.name->leaf.data); unsigned int dataAddr = emitCStringToData(&(mb->data), &(mb->dataCapacity), &(mb->dataCount), buffer); //check the param index for that entry i.e. don't reuse parameter names diff --git a/source/toy_parser.c b/source/toy_parser.c index 793aea6..75894fa 100644 --- a/source/toy_parser.c +++ b/source/toy_parser.c @@ -324,7 +324,7 @@ static Toy_AstFlag literal(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_As case TOY_TOKEN_LITERAL_INTEGER: { //filter the '_' character - char buffer[parser->previous.length]; + char buffer[parser->previous.length + 1]; unsigned int i = 0, o = 0; do { @@ -341,7 +341,7 @@ static Toy_AstFlag literal(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_As case TOY_TOKEN_LITERAL_FLOAT: { //filter the '_' character - char buffer[parser->previous.length]; + char buffer[parser->previous.length + 1]; unsigned int i = 0, o = 0; do { diff --git a/source/toy_print.c b/source/toy_print.c index 5db3cd9..6b663fe 100644 --- a/source/toy_print.c +++ b/source/toy_print.c @@ -1,5 +1,6 @@ #include "toy_print.h" +#include #include static Toy_callbackType printCallback = puts; @@ -19,14 +20,17 @@ void Toy_assertFailure(const char* msg) { } void Toy_setPrintCallback(Toy_callbackType cb) { + assert(cb); printCallback = cb; } void Toy_setErrorCallback(Toy_callbackType cb) { + assert(cb); errorCallback = cb; } void Toy_setAssertFailureCallback(Toy_callbackType cb) { + assert(cb); assertCallback = cb; } diff --git a/source/toy_scope.c b/source/toy_scope.c index 29a32be..04716d7 100644 --- a/source/toy_scope.c +++ b/source/toy_scope.c @@ -48,7 +48,7 @@ static void probeAndInsert(Toy_Scope* scope, Toy_String* key, Toy_Value value, T } //if this spot is free, insert and return - if (TOY_VALUE_IS_NULL(scope->data[probe].value)) { + if (scope->data[probe].key == NULL) { //fuck my life scope->data[probe] = entry; scope->count++; scope->maxPsl = entry.psl > scope->maxPsl ? entry.psl : scope->maxPsl; diff --git a/source/toy_vm.c b/source/toy_vm.c index ed395d4..010c0a1 100644 --- a/source/toy_vm.c +++ b/source/toy_vm.c @@ -73,6 +73,8 @@ static void processRead(Toy_VM* vm) { //grab the jump as an integer unsigned int jump = *((int*)(vm->code + vm->jumpsAddr + READ_INT(vm))); + //BUG: the jump parameter could cause an out of bounds read if it's malformed + //jumps are relative to the data address char* cstring = (char*)(vm->code + vm->dataAddr + jump); diff --git a/tests/scripts/test_variables.toy b/tests/scripts/test_variables.toy index 82c15cb..d20f270 100644 --- a/tests/scripts/test_variables.toy +++ b/tests/scripts/test_variables.toy @@ -157,4 +157,11 @@ print !false; //true print a; } +{ + //Yet Another Cosmic Joke + var a = null; + var i = 42; + print a; +} + //TODO: type casting \ No newline at end of file