Subj : GC-related bug in SpiderMonkey To : netscape.public.mozilla.jseng From : pavel.cenek Date : Fri May 13 2005 02:28 pm Hello, we believe we have found a bug in the SpiderMonkey engine. I am not sure whether this is something known, but I have not a clue how to verify that. I hope that our comment will be helpful. All what follows refers to the 1.5-rc6a version. Our application depends heavily on execution of a lot of ECMAScript scripts. We tested the application's behavior in extreme situations. One of the tests generated JS exceptions in a loop (the JS function causing the exception was not called recursively, just in a loop). By coincidence, all JS_MaybeGC() and JS_GC() calls in our code were disabled that time. After a while, the application crashed somewhere deep in the JS engine. A closer look showed that this happened after there was no more memory for allocation of new GC-things (the exception objects in our case) and the last-ditch GC was called by the GC-thing allocator. We further investigated the problem and I will try to describe what exactly happened and why te engine crashed. We do not have a detailed knowledge of the SpiderMonkey insides, so I apologize for possible inaccuracies. The engine crashed in the InitExceptionObject() function (jsexn.c) on line 473. There is the following code: 472 if (fp->script && fp->script->filename) { 473 for (cp = fp->script->filename; *cp; cp++) 474 APPEND_CHAR_TO_STACK(*cp); 476 } This is the stack dump in the time of the crash: InitExceptionObject js_ErrorToException ReportError js_ReportErrorNumberVA JS_ReportErrorNumber js_ReportIsNotDefined js_Interpret js_Execute JS_ExecuteScript The engine crashed because the fp->script->filename was not NULL, but some garbage (even if it was set to NULL by us and should be NULL). We investigated why and found the problem. In the js_ErrorToException() function (jsexn.c), before the InitExceptionObject() function is called (on line 998), some other operations are performed. One of them is the preparation of the filenameStr parameter: 987 if (reportp) { 988 filenameStr = JS_NewStringCopyZ(cx, reportp->filename); Before the call to the JS_NewStringCopyZ() function, the reportp->filename pointer was correctly NULL. The JS_NewStringCopyZ() function calls js_NewString() internally which calls js_AllocGCThing() to allocate the string. In our case, the allocation failed and therefore the last-ditch GC was called. The situation is summarized by the following stack dump: js_GC js_AllocGCThing js_NewString JS_NewStringCopyZ js_ErrorToException ReportError js_ReportErrorNumberVA JS_ReportErrorNumber js_ReportIsNotDefined js_Interpret js_Execute JS_ExecuteScript After the garbage collection, the allocation is tried once more and it was successful this time. So, the execution returned up to the js_ErrorToException() function. At this point, the reportp->filename pointer contained a non-NULL value, which subsequently causes the crash in the InitExceptionObject() function. There is apparently something wrong with the garbage collection. Some value is not rooted or somehow locked properly or whatever, I do not have such a detailed knowledge of the engine. One more thing that we found - the reportp->filename points to the same string as cx->fp->script->filename. It is set in the js_ReportErrorNumberVA() function (jscntxt.c) on line 619: 617 for (fp = cx->fp; fp; fp = fp->down) { 618 if (fp->script && fp->pc) { 619 report.filename = fp->script->filename; I would be grateful for any comments. We would be also interested in an answer to the following question: What is the size limit of the pool for GC-things. Is it not limited only by available physical memory (apparently not). Can be the size set up from outside of the engine (to preclude the situation when there is no free space and there is nothing to be garbage collected) Thank you Pavel Cenek .