Subj : SpiderMonkey GC problem? To : netscape.public.mozilla.jseng From : Lyndon Griffin Date : Mon Jan 17 2005 02:13 pm My application keeps dumping core. Below are relevant snips, followed by a backtrace: /********************* first, I load *.js from a directory as a number of "scripts" in a context; each "script" is a single function, with the filename of the script being something like: myfunction.js and the contents being: function myfunction() { //... } *********************/ boolean my_js_init() { /* initialize the JS run time, and return result in rt */ if ( NULL == ( jsrt = JS_NewRuntime(8L * 1024L * 1024L) ) ) return( FALSE ); /* create a context and associate it with the JS run time */ if ( NULL == ( jscx = JS_NewContext(jsrt, 8192) ) ) { JS_DestroyRuntime( jsrt ); return( FALSE ); } /* create the global object here */ if ( NULL == ( jsglob = JS_NewObject(jscx, NULL, NULL, NULL) ) ) { JS_DestroyContext( jscx ); JS_DestroyRuntime( jsrt ); return( FALSE ); } /* initialize the built-in JS objects and the global object */ if ( JS_FALSE == JS_InitStandardClasses(jscx, jsglob) ) { JS_DestroyContext( jscx ); JS_DestroyRuntime( jsrt ); return( FALSE ); } load_js_files(); return( TRUE ); } void load_js_files() { extern char *sz_jsdir; jsval rval; char tfnam[MAX_STR_LEN]; DIR *d; FILE *f; char *b; struct dirent *de; struct stat sb; if ( NULL != ( d = opendir( sz_jsdir ) ) ) { while( NULL != ( de = readdir( d ) ) ) { if ( 0 == strcmp( &de->d_name[de->d_namlen-3], ".js" ) ) { sprintf( (char *)&tfnam, "%s/%s%c", sz_jsdir, de->d_name, 0 ); stat( tfnam, &sb ); if ( NULL != ( f = fopen( tfnam, "r" ) ) ) { if ( NULL != ( b = (char *)malloc( sb.st_size + 1 ) ) ) { memset( b, 0, sb.st_size + 1 ); fread( b, sb.st_size, 1, f ); if (!JS_EvaluateScript(jscx,jsglob,b,sb.st_size,de->d_name,0,&rval)) { exit( 99 ); } else free( b ); b = NULL; } fclose( f ); } } } closedir( d ); } } /********* As will be evident from the backtrace, I'm using expat. As the parser travels through a file, the contents of each XML element are made available to the context. For example: This is my value would result in a property on the global object, conceptually: global.MyTag = "This is my value"; The first major question I have is here. After I've added this property, in my head I want to free( tstr ); - is that necessary, or is that what the GC is there for. I'm making a leap that JS_SetProperty alloc's and copies the contents of tval, which again has copied the contents of tstr via STRING_TO_JSVAL() macro. *********/ void handle_end_tag( void *v, const XML_Char *tag ) { JSString *tstr; jsval tval; tstr = JS_NewStringCopyZ(jscx,tbuf); tval = STRING_TO_JSVAL( tstr ); JS_SetProperty(jscx,jsglob,tag,&tval); /*** other code ***/ } /********* once a "block" of XML has finished parsing, it's time to spit out some new stuff (purpose of the program). Here is where the meat of my JS usage is. Basically, I call the functions that I loaded from the files above. The calls are embedded in the "left side" XML file, which works like an XSL stylesheet. The data for the transform comes from the "right side" XML file, which results in the property setting, above. Below, the contents of segments[seg_i].data look like: "myfunction( MyTag );" **********/ void finalize_data_block() { jsval rval; JSString *rstr; /*** other code ***/ if ( JS_TRUE == JS_EvaluateScript( jscx, jsglob, segments[seg_i].data, segments[seg_i].size, segments[seg_i].data, 0, &rval ) ) { JS_ConvertValue( jscx, rval, JSTYPE_STRING, &rval ); rstr = JS_ValueToString(jscx, rval); strncat( mbuf, JS_GetStringBytes( rstr ), JS_GetStringLength( rstr ) ); } else { exit( 99 ); } /*** other code ***/ } /*********** That covers everything but the cleanup before the application exits. My problem is occurring, it appears, when I pass in a particularly large value, like This is a really really really long string that will crash Most values of MyTag look more like this: This is a string Crashes only happen in my application when I have a long string, although they don't ALWAYS occur when I have a long string. Also, at crash, I've ALWAYS gone past the big MyTag value with respect to the XML parser (that record has been done), but it varies as to how far past (could be one record, could be 1000 records). Here's the backtrace ************/ #0 0x280d5e28 in js_DropObjectMap (cx=0x80d1200, map=0x80fe000, obj=0x94fed78) at jsobj.c:1802 1802 if (MAP_IS_NATIVE(map) && ((JSScope *)map)->object == obj) (gdb) backtrace #0 0x280d5e28 in js_DropObjectMap (cx=0x80d1200, map=0x80fe000, obj=0x94fed78) at jsobj.c:1802 #1 0x280d6670 in js_FinalizeObject (cx=0x80d1200, obj=0x94fed78) at jsobj.c:2020 #2 0x280bd05b in js_GC (cx=0x80d1200, gcflags=5) at jsgc.c:1324 #3 0x280bc0b9 in js_AllocGCThing (cx=0x80d1200, flags=3) at jsgc.c:529 #4 0x28101008 in js_NewString (cx=0x80d1200, chars=0x9523790, length=2, gcflag=2) at jsstr.c:2438 #5 0x280fb1f5 in js_ConcatStrings (cx=0x80d1200, left=0x95209c0, right=0x80ef4d8) at jsstr.c:182 #6 0x280c6101 in js_Interpret (cx=0x80d1200, result=0xbfbff4d8) at jsinterp.c:2416 #7 0x280bfd4d in js_Execute (cx=0x80d1200, chain=0x80ee748, script=0x9525080, down=0x0, special=0, result=0xbfbff4d8) at jsinterp.c:1155 #8 0x280941d0 in JS_EvaluateUCScriptForPrincipals (cx=0x80d1200, obj=0x80ee748, principals=0x0, chars=0x951d3c0, length=16, filename=0x806a5f0 "myfunction( e );", lineno=0, rval=0xbfbff4d8) at jsapi.c:3530 #9 0x2809417a in JS_EvaluateUCScript (cx=0x80d1200, obj=0x80ee748, chars=0x951d3c0, length=16, filename=0x806a5f0 "myfunction( e );", lineno=0, rval=0xbfbff4d8) at jsapi.c:3511 #10 0x280940c9 in JS_EvaluateScript (cx=0x80d1200, obj=0x80ee748, bytes=0x806a5f0 "myfunction( e );", length=16, filename=0x806a5f0 "myfunction( e );", lineno=0, rval=0xbfbff4d8) at jsapi.c:3479 #11 0x0804a329 in finalize_data_block () #12 0x0804a09b in handle_end_tag () #13 0x281322f7 in doContent (parser=0x80d1000, startTagLevel=0, enc=0x281499e0, s=0x8115fe6, end=0x8116400, nextPtr=0x80d1018, haveMore=1 '\001') at lib/xmlparse.c:2429 #14 0x28131981 in contentProcessor (parser=0x80d1000, start=0x8114405, end=0x8116400, endPtr=0x80d1018) at lib/xmlparse.c:2002 #15 0x28133427 in cdataSectionProcessor (parser=0x80d1000, start=0x8114405, end=0x8116400, endPtr=0x80d1018) at lib/xmlparse.c:2998 #16 0x28131249 in XML_ParseBuffer (parser=0x80d1000, len=8192, isFinal=0) at lib/xmlparse.c:1562 #17 0x0804a900 in parse_xml () #18 0x08049c24 in perform_work () #19 0x08049530 in main () #20 0x08049125 in _start () So, my chief question is, does anybody see anything blatantly wrong in the way I'm using SpiderMonkey, along the lines of something that would dump core? My second question is, what defines a script for the purposes of SpiderMonkey: e.g., if I had one big javascript file that contained all the functions, would that be considered a single script? Does the way I load the files conflict with the definition of script? I ask because I notice that there should be a one-to-one between a script and a context, but I have many "scripts" and only one context. The third question, asked above, is about forceably calling the GC or something more explicit to free a string I (think I) know that I'm done with. Thanks! <:) Lyndon .