1
0
mirror of https://github.com/janet-lang/janet synced 2024-12-25 07:50:27 +00:00

Fix read after free bug with GC sweep.

This commit is contained in:
Calvin Rose 2017-02-12 23:45:52 -05:00
parent c64282f8bf
commit 37faac1f8a
4 changed files with 109 additions and 113 deletions

View File

@ -70,8 +70,7 @@ struct Scope {
Dictionary * literals; Dictionary * literals;
Array * literalsArray; Array * literalsArray;
Dictionary * locals; Dictionary * locals;
Scope * nextScope; Scope * parent;
Scope * previousScope;
}; };
/* Provides default FormOptions */ /* Provides default FormOptions */
@ -110,11 +109,9 @@ static Scope * CompilerPushScope(Compiler * c, int sameFunction) {
scope->freeHeap = VMAlloc(c->vm, 10 * sizeof(uint16_t)); scope->freeHeap = VMAlloc(c->vm, 10 * sizeof(uint16_t));
scope->heapSize = 0; scope->heapSize = 0;
scope->heapCapacity = 10; scope->heapCapacity = 10;
scope->nextScope = NULL; scope->parent = c->tail;
scope->previousScope = c->tail;
scope->frameSize = 0; scope->frameSize = 0;
if (c->tail) { if (c->tail) {
c->tail->nextScope = scope;
scope->level = c->tail->level + (sameFunction ? 0 : 1); scope->level = c->tail->level + (sameFunction ? 0 : 1);
} else { } else {
scope->level = 0; scope->level = 0;
@ -132,8 +129,6 @@ static Scope * CompilerPushScope(Compiler * c, int sameFunction) {
scope->literalsArray = ArrayNew(c->vm, 10); scope->literalsArray = ArrayNew(c->vm, 10);
} }
c->tail = scope; c->tail = scope;
if (!c->root)
c->root = scope;
return scope; return scope;
} }
@ -146,15 +141,11 @@ static void CompilerPopScope(Compiler * c) {
if (last->nextLocal > last->frameSize) { if (last->nextLocal > last->frameSize) {
last->frameSize = last->nextLocal; last->frameSize = last->nextLocal;
} }
c->tail = last->previousScope; c->tail = last->parent;
if (c->tail) { if (c->tail) {
if (last->frameSize > c->tail->frameSize) { if (last->frameSize > c->tail->frameSize) {
c->tail->frameSize = last->frameSize; c->tail->frameSize = last->frameSize;
} }
c->tail->nextScope = NULL;
} else {
/* We deleted the last scope */
c->root = NULL;
} }
} }
} }
@ -350,7 +341,7 @@ static int ScopeSymbolResolve(Scope * scope, Value x,
*index = (uint16_t) check.data.number; *index = (uint16_t) check.data.number;
return 1; return 1;
} }
scope = scope->previousScope; scope = scope->parent;
} }
return 0; return 0;
} }
@ -1183,7 +1174,7 @@ void CompilerInit(Compiler * c, VM * vm) {
c->vm = vm; c->vm = vm;
c->buffer = BufferNew(vm, 128); c->buffer = BufferNew(vm, 128);
c->env = ArrayNew(vm, 10); c->env = ArrayNew(vm, 10);
c->tail = c->root = NULL; c->tail = NULL;
c->error = NULL; c->error = NULL;
CompilerPushScope(c, 0); CompilerPushScope(c, 0);
} }
@ -1192,7 +1183,7 @@ void CompilerInit(Compiler * c, VM * vm) {
void CompilerAddGlobal(Compiler * c, const char * name, Value x) { void CompilerAddGlobal(Compiler * c, const char * name, Value x) {
Value sym = ValueLoadCString(c->vm, name); Value sym = ValueLoadCString(c->vm, name);
sym.type = TYPE_SYMBOL; sym.type = TYPE_SYMBOL;
CompilerDeclareSymbol(c, c->root, sym); CompilerDeclareSymbol(c, c->tail, sym);
ArrayPush(c->vm, c->env, x); ArrayPush(c->vm, c->env, x);
} }
@ -1211,8 +1202,8 @@ Func * CompilerCompile(Compiler * c, Value form) {
FuncDef * def; FuncDef * def;
if (setjmp(c->onError)) { if (setjmp(c->onError)) {
/* Clear all but root scope */ /* Clear all but root scope */
c->tail = c->root; if (c->tail)
c->root->nextScope = NULL; c->tail->parent = NULL;
return NULL; return NULL;
} }
/* Create a scope */ /* Create a scope */

View File

@ -167,7 +167,6 @@ struct Compiler {
VM * vm; VM * vm;
const char * error; const char * error;
jmp_buf onError; jmp_buf onError;
Scope * root;
Scope * tail; Scope * tail;
Array * env; Array * env;
Buffer * buffer; Buffer * buffer;

170
main.c
View File

@ -9,104 +9,104 @@
/* Test c function */ /* Test c function */
Value print(VM * vm) { Value print(VM * vm) {
uint32_t i, j, count; uint32_t i, j, count;
Value nil; Value nil;
count = VMCountArgs(vm); count = VMCountArgs(vm);
for (j = 0; j < count; ++j) { for (j = 0; j < count; ++j) {
uint8_t * string = ValueToString(vm, VMGetArg(vm, j)); uint8_t * string = ValueToString(vm, VMGetArg(vm, j));
uint32_t len = VStringSize(string); uint32_t len = VStringSize(string);
for (i = 0; i < len; ++i) for (i = 0; i < len; ++i)
fputc(string[i], stdout); fputc(string[i], stdout);
fputc('\n', stdout); fputc('\n', stdout);
} }
nil.type = TYPE_NIL; nil.type = TYPE_NIL;
return nil; return nil;
} }
/* A simple repl for debugging */ /* A simple repl for debugging */
void debugRepl() { void debugRepl() {
char buffer[128] = {0}; char buffer[128] = {0};
const char * reader = buffer; const char * reader = buffer;
Value func; Value func;
VM vm; VM vm;
Parser p; Parser p;
Compiler c; Compiler c;
VMInit(&vm); VMInit(&vm);
for (;;) { for (;;) {
/* Run garbage collection */ /* Run garbage collection */
/* VMMaybeCollect(&vm);*/ VMMaybeCollect(&vm);
/* Reset state */ /* Reset state */
ParserInit(&p, &vm); ParserInit(&p, &vm);
/* Get and parse input until we have a full form */ /* Get and parse input until we have a full form */
while (p.status == PARSER_PENDING) { while (p.status == PARSER_PENDING) {
/* Get some input if we are done */ /* Get some input if we are done */
if (*reader == '\0') { if (*reader == '\0') {
printf("> "); printf("> ");
if (!fgets(buffer, sizeof(buffer), stdin)) { if (!fgets(buffer, sizeof(buffer), stdin)) {
return; return;
}
p.index = 0;
reader = buffer;
}
reader += ParserParseCString(&p, reader);
}
/* Check for parsing errors */
if (p.error) {
unsigned i;
printf("\n");
printf("%s\n", buffer);
for (i = 0; i < p.index; ++i) {
printf(" ");
}
printf("^\n");
printf("\nParse error: %s\n", p.error);
reader = buffer; /* Flush the input buffer */
buffer[0] = '\0';
continue;
}
/* Try to compile generated AST */
CompilerInit(&c, &vm);
CompilerAddGlobalCFunc(&c, "print", print);
func.type = TYPE_FUNCTION;
func.data.func = CompilerCompile(&c, p.value);
/* Check for compilation errors */
if (c.error) {
printf("Compiler error: %s\n", c.error);
reader = buffer;
buffer[0] = 0;
continue;
}
/* Print asm */
printf("\n");
dasmFunc(stdout, func.data.func);
printf("\n");
/* Execute function */
VMLoad(&vm, func);
if (VMStart(&vm)) {
printf("VM error: %s\n", vm.error);
reader = buffer;
buffer[0] = 0;
continue;
} else {
ValuePrint(vm.ret, 0);
printf("\n");
} }
p.index = 0;
reader = buffer;
}
reader += ParserParseCString(&p, reader);
} }
/* Check for parsing errors */
if (p.error) {
unsigned i;
printf("\n");
printf("%s\n", buffer);
for (i = 0; i < p.index; ++i) {
printf(" ");
}
printf("^\n");
printf("\nParse error: %s\n", p.error);
reader = buffer; /* Flush the input buffer */
buffer[0] = '\0';
continue;
}
/* Try to compile generated AST */
CompilerInit(&c, &vm);
CompilerAddGlobalCFunc(&c, "print", print);
func.type = TYPE_FUNCTION;
func.data.func = CompilerCompile(&c, p.value);
/* Check for compilation errors */
if (c.error) {
printf("Compiler error: %s\n", c.error);
reader = buffer;
buffer[0] = 0;
continue;
}
/* Print asm */
printf("\n");
dasmFunc(stdout, func.data.func);
printf("\n");
/* Execute function */
VMLoad(&vm, func);
if (VMStart(&vm)) {
printf("VM error: %s\n", vm.error);
reader = buffer;
buffer[0] = 0;
continue;
} else {
ValuePrint(vm.ret, 0);
printf("\n");
}
}
} }
int main() { int main() {
printf("Super cool interpreter v0.0\n"); printf("Super cool interpreter v0.0\n");
debugRepl(); debugRepl();
return 0; return 0;
} }

26
vm.c
View File

@ -41,7 +41,8 @@ static void VMMarkFuncEnv(VM * vm, FuncEnv * env) {
temp.type = TYPE_THREAD; temp.type = TYPE_THREAD;
temp.data.array = env->thread; temp.data.array = env->thread;
VMMark(vm, &temp); VMMark(vm, &temp);
} else if (env->values) { }
if (env->values) {
uint32_t count = env->stackOffset; uint32_t count = env->stackOffset;
uint32_t i; uint32_t i;
GCHeader(env->values)->color = vm->black; GCHeader(env->values)->color = vm->black;
@ -126,8 +127,9 @@ static void VMMark(VM * vm, Value * x) {
if (GCHeader(x->data.func)->color != vm->black) { if (GCHeader(x->data.func)->color != vm->black) {
Func * f = x->data.func; Func * f = x->data.func;
GCHeader(f)->color = vm->black; GCHeader(f)->color = vm->black;
VMMarkFuncEnv(vm, f->env);
VMMarkFuncDef(vm, f->def); VMMarkFuncDef(vm, f->def);
if (f->env)
VMMarkFuncEnv(vm, f->env);
if (f->parent) { if (f->parent) {
Value temp; Value temp;
temp.type = TYPE_FUNCTION; temp.type = TYPE_FUNCTION;
@ -169,18 +171,20 @@ static void VMMark(VM * vm, Value * x) {
static void VMSweep(VM * vm) { static void VMSweep(VM * vm) {
GCMemoryHeader * previous = NULL; GCMemoryHeader * previous = NULL;
GCMemoryHeader * current = vm->blocks; GCMemoryHeader * current = vm->blocks;
GCMemoryHeader * next;
while (current) { while (current) {
next = current->next;
if (current->color != vm->black) { if (current->color != vm->black) {
if (previous) { if (previous) {
previous->next = current->next; previous->next = next;
} else { } else {
vm->blocks = current->next; vm->blocks = next;
} }
free(current); free(current);
} else { } else {
previous = current; previous = current;
} }
current = current->next; current = next;
} }
/* Rotate flag */ /* Rotate flag */
vm->black = !vm->black; vm->black = !vm->black;
@ -216,10 +220,12 @@ void * VMZalloc(VM * vm, uint32_t size) {
void VMCollect(VM * vm) { void VMCollect(VM * vm) {
if (vm->lock > 0) return; if (vm->lock > 0) return;
/* Thread can be null */ /* Thread can be null */
Value thread; if (vm->thread) {
thread.type = TYPE_THREAD; Value thread;
thread.data.array = vm->thread; thread.type = TYPE_THREAD;
VMMark(vm, &thread); thread.data.array = vm->thread;
VMMark(vm, &thread);
}
VMMark(vm, &vm->ret); VMMark(vm, &vm->ret);
VMSweep(vm); VMSweep(vm);
vm->nextCollection = 0; vm->nextCollection = 0;
@ -271,7 +277,7 @@ static void VMThreadSplitStack(VM * vm) {
env->stackOffset = size; env->stackOffset = size;
env->values = VMAlloc(vm, sizeof(Value) * size); env->values = VMAlloc(vm, sizeof(Value) * size);
memcpy(env->values, thread->data + thread->count, size * sizeof(Value)); memcpy(env->values, thread->data + thread->count, size * sizeof(Value));
} }
} }
/* Pop the top-most stack frame from stack */ /* Pop the top-most stack frame from stack */