Skip to content

Commit

Permalink
fix segfault bug, add interning
Browse files Browse the repository at this point in the history
  • Loading branch information
dragoncoder047 authored Mar 13, 2024
1 parent e4a48f3 commit a8e5909
Show file tree
Hide file tree
Showing 7 changed files with 982 additions and 242 deletions.
438 changes: 438 additions & 0 deletions test/out32.txt

Large diffs are not rendered by default.

607 changes: 432 additions & 175 deletions test/out64.txt

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions test/valgrind32.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
==11957== Memcheck, a memory error detector
==11957== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11957== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==11957== Command: ./ttest32
==11957==
0 tests failed
==11957==
==11957== HEAP SUMMARY:
==11957== in use at exit: 0 bytes in 0 blocks
==11957== total heap usage: 15 allocs, 15 frees, 28,832 bytes allocated
==11957==
==11957== All heap blocks were freed -- no leaks are possible
==11957==
==11957== For lists of detected and suppressed errors, rerun with: -s
==11957== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
56 changes: 15 additions & 41 deletions test/valgrind64.txt
Original file line number Diff line number Diff line change
@@ -1,41 +1,15 @@
==20147== Memcheck, a memory error detector
==20147== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==20147== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==20147== Command: ./ttest64
==20147==
==20147== Jump to the invalid address stated on the next line
==20147== at 0x0: ???
==20147== by 0x109A85: tinobsy::markcons(tinobsy::vm*, tinobsy::object*) (tinobsy.cpp:119)
==20147== by 0x109641: tinobsy::vm::markobject(tinobsy::object*) (tinobsy.cpp:58)
==20147== by 0x10A69A: MyVM::mark_globals() (tinobsy_test.cpp:15)
==20147== by 0x1096CA: tinobsy::vm::gc() (tinobsy.cpp:65)
==20147== by 0x109D63: test_mark_no_sweep() (tinobsy_test.cpp:61)
==20147== by 0x10A444: main (tinobsy_test.cpp:128)
==20147== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==20147==
==20147==
==20147== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==20147== Bad permissions for mapped region at address 0x0
==20147== at 0x0: ???
==20147== by 0x109A85: tinobsy::markcons(tinobsy::vm*, tinobsy::object*) (tinobsy.cpp:119)
==20147== by 0x109641: tinobsy::vm::markobject(tinobsy::object*) (tinobsy.cpp:58)
==20147== by 0x10A69A: MyVM::mark_globals() (tinobsy_test.cpp:15)
==20147== by 0x1096CA: tinobsy::vm::gc() (tinobsy.cpp:65)
==20147== by 0x109D63: test_mark_no_sweep() (tinobsy_test.cpp:61)
==20147== by 0x10A444: main (tinobsy_test.cpp:128)
==20147==
==20147== HEAP SUMMARY:
==20147== in use at exit: 4,152 bytes in 2 blocks
==20147== total heap usage: 5 allocs, 3 frees, 85,056 bytes allocated
==20147==
==20147== LEAK SUMMARY:
==20147== definitely lost: 0 bytes in 0 blocks
==20147== indirectly lost: 0 bytes in 0 blocks
==20147== possibly lost: 0 bytes in 0 blocks
==20147== still reachable: 4,152 bytes in 2 blocks
==20147== suppressed: 0 bytes in 0 blocks
==20147== Rerun with --leak-check=full to see details of leaked memory
==20147==
==20147== For lists of detected and suppressed errors, rerun with: -s
==20147== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
==11930== Memcheck, a memory error detector
==11930== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11930== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==11930== Command: ./ttest64
==11930==
0 tests failed
==11930==
==11930== HEAP SUMMARY:
==11930== in use at exit: 0 bytes in 0 blocks
==11930== total heap usage: 15 allocs, 15 frees, 85,696 bytes allocated
==11930==
==11930== All heap blocks were freed -- no leaks are possible
==11930==
==11930== For lists of detected and suppressed errors, rerun with: -s
==11930== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
35 changes: 29 additions & 6 deletions tinobsy.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "tinobsy.hpp"
#include <functional>

namespace tinobsy {

Expand Down Expand Up @@ -55,6 +56,10 @@ void vm::markobject(object* o) {
goto MARK;
}
DBG("Marking a %s", t->name);
if (!t->mark) {
DBG("No MARK pointer, returning...");
return;
}
o = t->mark(this, o);
goto MARK;
}
Expand All @@ -68,12 +73,10 @@ size_t vm::gc() {
this->freelist = NULL;
this->freespace = 0;
size_t freed_chunks = 0;
for (chunk** c = &this->chunks; c; c = &(*c)->next) {
DBG("Chunk %zu {", ci);
for (chunk** c = &this->chunks; c && *c; c = &(*c)->next) {
bool is_empty = true;
object* freelist_here = this->freelist;
for (size_t i = 0; i < TINOBSY_CHUNK_SIZE; i++) {
DBG("Checking object %zu of chunk %zu", i, ci);
object* o = &(*c)->d[i];
if (!o->tst_flag(GC_MARKED)) this->release(o);
else {
Expand All @@ -94,7 +97,7 @@ size_t vm::gc() {
DBG("}");
ci++;
}
size_t freed = this->freespace - start;
size_t freed = this->freespace + TINOBSY_CHUNK_SIZE * freed_chunks - start;
DBG("vm::gc() after sweeping objects, %zu objects freed, %zu chunks freed", freed, freed_chunks);
return freed;
}
Expand All @@ -103,17 +106,37 @@ void vm::release(object* o) {
if (!o) return;
if (o->type && o->type->free) o->type->free(o);
memset(o, 0, sizeof(object));
o->as_obj = this->freelist;
cdr(o) = this->freelist;
this->freelist = o;
this->freespace++;
}

vm::~vm() {
DBG("vm::~vm() {");
TODO(sweep all);
while (this->chunks) {
chunk* c = this->chunks;
for (size_t i = 0; i < TINOBSY_CHUNK_SIZE; i++) {
this->release(&c->d[i]);
}
this->chunks = c->next;
delete c;
}
DBG("}");
}

void vm::iter_objects(bool (*func)(object*, void*), void* arg, bool all) {
chunk* c = this->chunks;
while (c) {
for (size_t i = 0; i < TINOBSY_CHUNK_SIZE; i++) {
if (!all && c->d[i].type == NULL) continue;
bool done = func(&c->d[i], arg);
if (done) return;
}
c = c->next;
}
}


object* markcons(vm* vm, object* self) {
// Error on this line WTF??
vm->markobject(car(self));
Expand Down
6 changes: 4 additions & 2 deletions tinobsy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
#endif

#ifdef TINOBSY_DEBUG
#include <sysexits.h>
#define DBG(s, ...) printf("[%s:%i-%s] " s "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
#define ASSERT(cond, ...) do { \
if (!(cond)) { \
DBG("Assertion failed: %s", #cond); \
DBG(__VA_ARGS__); \
fprintf(stderr, "Assert failed, causing a deliberate segfault now.\n"); \
*((int*)0) = 1; \
fprintf(stderr, "Assertion failed %s\n", #cond); \
exit(EX_SOFTWARE); \
} else { \
DBG("Assertion succeeded: %s", #cond); \
} \
Expand Down Expand Up @@ -136,6 +137,7 @@ class vm {
virtual void mark_globals() {};

void markobject(object*);
void iter_objects(bool (*)(object*, void*), void*, bool = true);

private:
void release(object*);
Expand Down
67 changes: 49 additions & 18 deletions tinobsy_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,51 @@

using namespace tinobsy;


object_type cons_type("cons", markcons, NULL, NULL);
class MyVM : public vm {
public:
object* stack;
void mark_globals() {
this->markobject(this->stack);
}
void push(object* thing, object*& stack) {
object* cell = this->alloc(&cons_type);
cell->car = thing;
cell->cdr = stack;
stack = cell;
}
void push(object* thing) {
push(thing, this->stack);
}
};

MyVM* VM;
const int times = 10;
size_t fails = 0;
#define TEST(cond, ...) do { \
if (!(cond)) { \
DBG("Test failed: %s", #cond); \
DBG(__VA_ARGS__); \
fprintf(stderr, "Test failed %s\n", #cond); \
fails++; \
} else { \
DBG("Test succeeded: %s", #cond); \
} \
} while(0)

void divider();

inline void divider() {
printf("\n-------------------------------------------------------------\n\n");
}

void free_string(object* self) {
free(self->as_chars);
}

object_type nothing_type("nil", NULL, NULL, NULL);
object_type atom_type("atom", NULL, NULL, NULL);
object_type atom_type("atom", NULL, free_string, NULL);

void test_sweep() {
DBG("test mark-sweep collector: objects are swept when not put into a thread");
Expand All @@ -39,27 +66,18 @@ void test_sweep() {
VM->alloc(&nothing_type);
DBG("Begin sweep of everything");
VM->gc();
ASSERT(VM->freespace == oldobj, "did not sweep right objects %zu %zu", VM->freespace, oldobj);
}

object_type cons_type("cons", markcons, NULL, NULL);

void push(vm* v, object* thing, object*& stack) {
object* cell = v->alloc(&cons_type);
cell->car = thing;
cell->cdr = stack;
stack = cell;
TEST(VM->freespace == oldobj, "did not sweep right objects %zu %zu", VM->freespace, oldobj);
}

void test_mark_no_sweep() {
DBG("test mark-sweep collector: objects aren't swept when marked on globals");
for (int i = 0; i < times; i++) {
object* foo = VM->alloc(&nothing_type);
push(VM, foo, VM->stack);
VM->push(foo);
}
size_t oldobj = VM->freespace;
VM->gc();
ASSERT(VM->freespace == oldobj, "swept some by mistake");
TEST(VM->freespace == oldobj, "swept some by mistake");
}

char randchar() {
Expand All @@ -73,7 +91,7 @@ void test_freeing_things() {
for (int j = 0; j < 63; j++) buffer[j] = randchar();
DBG("Random atom is %s", buffer);
object* foo = VM->alloc(&atom_type);
TODO(allocate string (void)buffer;);
foo->as_chars = strdup(buffer);
}
VM->gc();
DBG("Check Valgrind output to make sure stuff was freed");
Expand All @@ -86,12 +104,24 @@ void test_reference_cycle() {
a->car = a;
a->cdr = a;
VM->gc();
ASSERT(VM->freespace == oldobj, "a was not collected");
TEST(VM->freespace == oldobj, "a was not collected");
}

const object_type Integer("int", NULL, NULL, NULL);

object* makeint(vm* vm, int64_t z) {
typedef struct { object* found; int64_t num; } f;
f foo = {.num = z};
vm->iter_objects([](object* obj, void* arg) -> bool {
f* foo = (f*)arg;
DBG("Interning, searching a %s", obj->type->name);
if (obj->type == &Integer && foo->num == obj->as_big_int) {
foo->found = obj;
return true;
}
return false;
}, &foo, false);
if (foo.found) return foo.found;
object* x = vm->alloc(&Integer);
x->as_big_int = z;
return x;
Expand All @@ -104,7 +134,7 @@ void test_interning() {
ASSERT(a->as_big_int == 47, "did not copy right");
for (int i = 0; i < times; i++) {
object* b = makeint(VM, foo);
ASSERT(a == b, "not interned");
TEST(a == b, "not interned");
}
}

Expand All @@ -121,14 +151,15 @@ const int num_tests = sizeof(tests) / sizeof(tests[0]);
int main() {
srand(time(NULL));
DBG("Begin Tinobsy test suite");
DBG("sizeof(object) = %zu, sizeof(vm) = %zu", sizeof(object), sizeof(vm));
DBG("sizeof(object) = %zu, sizeof(vm) = %zu, sizeof(chunk) = %zu", sizeof(object), sizeof(vm), sizeof(chunk));
VM = new MyVM();
for (int i = 0; i < num_tests; i++) {
divider();
tests[i]();
}
divider();
DBG("end of tests");
DBG("end of tests. Total %zu fails", fails);
fprintf(stderr, "%zu tests failed\n", fails);
delete VM;
return 0;
}

0 comments on commit a8e5909

Please sign in to comment.