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:
parent
c64282f8bf
commit
37faac1f8a
25
compile.c
25
compile.c
@ -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 */
|
||||||
|
@ -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
170
main.c
@ -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
26
vm.c
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user