Search code examples
c++javascript-objectsseamonkey

SIGSEGV when calling JS_NewStringCopyN twice


I have been trying to use the Mozilla / SeaMonkey JavaScript library that ships with Ubuntu 16.04.3 LTS, mozjs185-1.0, but am encountering a SIGSEGV when I try to call JS_NewStringCopyN twice to allocate two JSString objects from char * strings.

My sample code is as follows:

#include <js/jsapi.h>
#include <js/jscntxt.h>
#include <js/jscompartment.h>

size_t gStackChunkSize = 8192;

static void
my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
{ }

int main(int argc, char *argv[]) {
    JSRuntime *rt = JS_NewRuntime(256L * 1024L * 1024L);
    if (!rt)
       return -1;

    JSCompartment compartment(rt);
    JSContext *cx = JS_NewContext(rt, gStackChunkSize);
    if (!cx)
        return -2;
    JS_SetErrorReporter(cx, my_ErrorReporter);
    cx->compartment = &compartment;

    const char data[] = "PScript5.dll Version 5.2.2";
    const char data2[] = "Thom Parker";

    JSString *str = JS_NewStringCopyN(cx, data, sizeof(data));
    JSString *str2 = JS_NewStringCopyN(cx, data2, sizeof(data2));

    return 0;
}

Which I compile with:

g++ test.cpp -o mdntest -I/usr/include/nspr -lmozjs185-1.0 -L/usr/lib/x86_64-linux-gnu -lz -lnspr4  -lpthread

When I run ./mdntest it generates a SIGSEGV and crashes. Having debugged the 1.8.5 version of the Mozilla JavaScript library, I know that what is happening during the second call to JS_NewStringCopyN is that the garbage collector is called (JS_gc) and that somewhere it is trying to do a mark and sweep pass but is accessing some invalid memory, 30 levels deep in the back trace with a call to js::gc::ArenaBitmap::markIfUnmarked.

My theory is there is some undocumented thing I'm forgetting do do after calling the first JS_NewStringCopyN. Any advice or assistance would be greatly appreciated.


Solution

  • In the example code above, the issue I've found is that a JSCompartment must be manually initialized before use.

    Thus, by adding:

    compartment.init();
    

    right after the construction of compartment in JSCompartment compartment(rt); the two JS_NewStringCopyN are called without error and the garbage collector JS_gc runs without error. Why the JSCompartment doesn't call JSCompartment::init() in its constructor and why this isn't clearly documented is beyond me.