munificent / craftinginterpreters

Repository for the book "Crafting Interpreters"
http://www.craftinginterpreters.com/
Other
8.79k stars 1.03k forks source link

SIGSEGV at markCompilerRoot #946

Closed mcfriend99 closed 3 years ago

mcfriend99 commented 3 years ago

Hi,

When running a slightly long operation such as a long for loop and GC kicks in, I encounter a SIGSEGV error pointing to

if (object->isMarked) return; or sometimes if (object == NULL) return;

in method

void markObject(Obj* object)

via

markObject((Obj*)compiler->function); in void markCompilerRoots().

Please help!!!

mcfriend99 commented 3 years ago

I think I managed to stumble on many of the GC corruptions possible in the system. Good new is I fixed them already.

I think it will be good to start looking at implementing a GC lock and unlock mechanism.

mcfriend99 commented 3 years ago

I'm reopening this issue because it's still a very valid bug. From what I noticed, this bug usually occurs during the copyString function and whenever a new object is created inside of a native function and the GC happens to run around that time.

I just added a new native function into Lox and created newClosure inside of it. I put that into a large loop and lo and behold, the bug still exits.

Anyone has any idea how to fix this??

munificent commented 3 years ago

If you create multiple objects inside a native function, then you'll just need to temporarily push them onto the stack in the body of the native function and pop them after you've created all the objects and before the function returns.

So instead of:

static Value makeTwoStrings(int argCount, Value* args) {
  ObjString* stringA = copyString("the first string", 16);
  ObjString* stringB = copyString("the second string", 17);
  //                   ^ a GC will free stringA.
  return stringA;
}

You'll want something like:

static Value makeTwoStrings(int argCount, Value* args) {
  ObjString* stringA = copyString("the first string", 16);
  push(OBJ_VAL(stringA));
  ObjString* stringB = copyString("the second string", 17);
  pop(OBJ_VAL(stringA));
  return stringA;
}
mcfriend99 commented 3 years ago

Thanks for the reply. I already figured that out on my own and fixed it.

For anyone looking at another approach, I created GC trackers for objects created in native functions on the VM which automatically clears after a call, but before the result of the call is push to stack.

It essentially achieves the same. I had to do that as I was already implementing a C module system for my language and It will become tedious to write modules if developers always have to do push and pop in their C codes. One thing I particularly hate about extending Lua.