Commit ed96479f authored by deuce's avatar deuce
Browse files

Root the created object in js_CreateGlobalObject() and js_CreateCommonObjects()

and leave it rooted until the script is done or the context is destroyed.

This should clean up crashes before a script starts (ie: While creating
common objects)
parent 88c4e0a7
......@@ -480,8 +480,8 @@ static JSContext*
js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, JSObject** ftp, js_callback_t* cb)
{
JSContext* js_cx;
JSObject* js_glob;
BOOL success=FALSE;
BOOL rooted=FALSE;
lprintf(LOG_DEBUG,"%04d JavaScript: Initializing context (stack: %lu bytes)"
,sock,startup->js.cx_stack);
......@@ -501,35 +501,35 @@ js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, JSObject** ftp, js_c
do {
lprintf(LOG_DEBUG,"%04d JavaScript: Initializing Global object",sock);
if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL, &startup->js))==NULL)
if(!js_CreateGlobalObject(js_cx, &scfg, NULL, &startup->js, glob))
break;
rooted=TRUE;
if(!JS_DefineFunctions(js_cx, js_glob, js_global_functions))
if(!JS_DefineFunctions(js_cx, *glob, js_global_functions))
break;
/* Internal JS Object */
if(js_CreateInternalJsObject(js_cx, js_glob, cb, &startup->js)==NULL)
if(js_CreateInternalJsObject(js_cx, *glob, cb, &startup->js)==NULL)
break;
lprintf(LOG_DEBUG,"%04d JavaScript: Initializing System object",sock);
if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime, startup->host_name, SOCKLIB_DESC)==NULL)
if(js_CreateSystemObject(js_cx, *glob, &scfg, uptime, startup->host_name, SOCKLIB_DESC)==NULL)
break;
if((*ftp=JS_DefineObject(js_cx, js_glob, "ftp", NULL
if((*ftp=JS_DefineObject(js_cx, *glob, "ftp", NULL
,NULL,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL)
break;
if(js_CreateServerObject(js_cx,js_glob,&js_server_props)==NULL)
if(js_CreateServerObject(js_cx,*glob,&js_server_props)==NULL)
break;
if(glob!=NULL)
*glob=js_glob;
success=TRUE;
} while(0);
if(!success) {
if(rooted)
JS_RemoveObjectRoot(js_cx, glob);
JS_ENDREQUEST(js_cx);
JS_DestroyContext(js_cx);
return(NULL);
......@@ -4575,6 +4575,9 @@ static void ctrl_thread(void* arg)
#ifdef JAVASCRIPT
if(js_cx!=NULL) {
lprintf(LOG_DEBUG,"%04d JavaScript: Destroying context",sock);
JS_BEGINREQUEST(js_cx);
JS_RemoveObjectRoot(js_cx, &js_glob);
JS_ENDREQUEST(js_cx);
JS_DestroyContext(js_cx); /* Free Context */
}
......
......@@ -128,6 +128,7 @@ static void background_thread(void* arg)
result=exit_code;
js_EvalOnExit(bg->cx, bg->obj, &bg->cb);
js_enqueue_value(bg->cx, bg->msg_queue, result, NULL);
JS_RemoveObjectRoot(bg->cx, &bg->obj);
JS_ENDREQUEST(bg->cx);
JS_DestroyContext(bg->cx);
jsrt_Release(bg->runtime);
......@@ -252,14 +253,19 @@ js_load(JSContext *cx, uintN argc, jsval *arglist)
bg->cb.counter=0;
bg->cb.gc_attempts=0;
if((bg->runtime = jsrt_GetNew(JAVASCRIPT_MAX_BYTES, 1000, __FILE__, __LINE__))==NULL)
if((bg->runtime = jsrt_GetNew(JAVASCRIPT_MAX_BYTES, 1000, __FILE__, __LINE__))==NULL) {
free(bg);
return(JS_FALSE);
}
if((bg->cx = JS_NewContext(bg->runtime, JAVASCRIPT_CONTEXT_STACK))==NULL)
if((bg->cx = JS_NewContext(bg->runtime, JAVASCRIPT_CONTEXT_STACK))==NULL) {
jsrt_Release(bg->runtime);
free(bg);
return(JS_FALSE);
}
JS_BEGINREQUEST(bg->cx);
if((bg->obj=js_CreateCommonObjects(bg->cx
if(!js_CreateCommonObjects(bg->cx
,p->cfg /* common config */
,NULL /* node-specific config */
,NULL /* additional global methods */
......@@ -271,8 +277,14 @@ js_load(JSContext *cx, uintN argc, jsval *arglist)
,NULL /* client */
,INVALID_SOCKET /* client_socket */
,NULL /* server props */
))==NULL)
,&bg->obj
)) {
JS_ENDREQUEST(bg->cx);
JS_DestroyContext(bg->cx);
jsrt_Release(bg->runtime);
free(bg);
return(JS_FALSE);
}
bg->msg_queue = msgQueueInit(NULL,MSG_QUEUE_BIDIR);
......@@ -309,16 +321,39 @@ js_load(JSContext *cx, uintN argc, jsval *arglist)
if(argn==argc) {
JS_ReportError(cx,"no filename specified");
if(background) {
JS_RemoveObjectRoot(bg->cx, &bg->obj);
JS_ENDREQUEST(bg->cx);
JS_DestroyContext(bg->cx);
jsrt_Release(bg->runtime);
free(bg);
}
return(JS_FALSE);
}
JSVALUE_TO_STRING(cx, argv[argn++], filename, NULL);
if(filename==NULL)
if(filename==NULL) {
if(background) {
JS_RemoveObjectRoot(bg->cx, &bg->obj);
JS_ENDREQUEST(bg->cx);
JS_DestroyContext(bg->cx);
jsrt_Release(bg->runtime);
free(bg);
}
return(JS_FALSE);
}
if(argc>argn || background) {
if((js_argv=JS_NewArrayObject(exec_cx, 0, NULL)) == NULL)
if((js_argv=JS_NewArrayObject(exec_cx, 0, NULL)) == NULL) {
if(background) {
JS_RemoveObjectRoot(bg->cx, &bg->obj);
JS_ENDREQUEST(bg->cx);
JS_DestroyContext(bg->cx);
jsrt_Release(bg->runtime);
free(bg);
}
return(JS_FALSE);
}
JS_DefineProperty(exec_cx, exec_obj, "argv", OBJECT_TO_JSVAL(js_argv)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
......@@ -427,8 +462,15 @@ js_load(JSContext *cx, uintN argc, jsval *arglist)
JS_ClearPendingException(exec_cx);
if((script=JS_CompileFile(exec_cx, exec_obj, path))==NULL)
if((script=JS_CompileFile(exec_cx, exec_obj, path))==NULL) {
if(background) {
JS_RemoveObjectRoot(bg->cx, &bg->obj);
JS_DestroyContext(bg->cx);
jsrt_Release(bg->runtime);
free(bg);
}
return(JS_FALSE);
}
if(background) {
......@@ -3801,36 +3843,41 @@ static JSClass js_global_class = {
,js_global_finalize /* finalize */
};
JSObject* DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods, js_startup_t* startup)
BOOL DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods, js_startup_t* startup, JSObject**glob)
{
JSObject* glob;
private_t* p;
if((p = (private_t*)malloc(sizeof(private_t)))==NULL)
return(NULL);
return(FALSE);
p->cfg = cfg;
p->methods = methods;
p->startup = startup;
if((glob = JS_NewCompartmentAndGlobalObject(cx, &js_global_class, NULL)) ==NULL)
return(NULL);
if((*glob = JS_NewCompartmentAndGlobalObject(cx, &js_global_class, NULL)) ==NULL)
return(FALSE);
if(!JS_AddObjectRoot(cx, glob))
return(FALSE);
if(!JS_SetPrivate(cx, glob, p)) /* Store a pointer to scfg_t and the new methods */
return(NULL);
if(!JS_SetPrivate(cx, *glob, p)) { /* Store a pointer to scfg_t and the new methods */
JS_RemoveObjectRoot(cx, glob);
return(FALSE);
}
if (!JS_InitStandardClasses(cx, glob))
return(NULL);
if (!JS_InitStandardClasses(cx, *glob)) {
JS_RemoveObjectRoot(cx, glob);
return(FALSE);
}
#ifdef BUILD_JSDOCS
js_DescribeSyncObject(cx,glob
js_DescribeSyncObject(cx,*glob
,"Top-level functions and properties (common to all servers and services)",310);
#endif
return(glob);
return(TRUE);
}
JSObject* DLLCALL js_CreateCommonObjects(JSContext* js_cx
BOOL DLLCALL js_CreateCommonObjects(JSContext* js_cx
,scfg_t* cfg /* common */
,scfg_t* node_cfg /* node-specific */
,jsSyncMethodSpec* methods /* global */
......@@ -3842,64 +3889,72 @@ JSObject* DLLCALL js_CreateCommonObjects(JSContext* js_cx
,client_t* client /* client */
,SOCKET client_socket /* client */
,js_server_props_t* props /* server */
,JSObject** glob
)
{
JSObject* js_glob;
BOOL success=FALSE;
if(node_cfg==NULL)
node_cfg=cfg;
/* Global Object */
if((js_glob=js_CreateGlobalObject(js_cx, cfg, methods, js_startup))==NULL)
return(NULL);
if(!js_CreateGlobalObject(js_cx, cfg, methods, js_startup, glob))
return(FALSE);
/* System Object */
if(js_CreateSystemObject(js_cx, js_glob, node_cfg, uptime, host_name, socklib_desc)==NULL)
return(NULL);
do {
/* System Object */
if(js_CreateSystemObject(js_cx, *glob, node_cfg, uptime, host_name, socklib_desc)==NULL)
break;
/* Internal JS Object */
if(cb!=NULL
&& js_CreateInternalJsObject(js_cx, js_glob, cb, js_startup)==NULL)
return(NULL);
/* Internal JS Object */
if(cb!=NULL
&& js_CreateInternalJsObject(js_cx, *glob, cb, js_startup)==NULL)
break;
/* Client Object */
if(client!=NULL
&& js_CreateClientObject(js_cx, *glob, "client", client, client_socket)==NULL)
break;
/* Client Object */
if(client!=NULL
&& js_CreateClientObject(js_cx, js_glob, "client", client, client_socket)==NULL)
return(NULL);
/* Server */
if(props!=NULL
&& js_CreateServerObject(js_cx, *glob, props)==NULL)
break;
/* Socket Class */
if(js_CreateSocketClass(js_cx, *glob)==NULL)
break;
/* Server */
if(props!=NULL
&& js_CreateServerObject(js_cx, js_glob, props)==NULL)
return(NULL);
/* Queue Class */
if(js_CreateQueueClass(js_cx, *glob)==NULL)
break;
/* Socket Class */
if(js_CreateSocketClass(js_cx, js_glob)==NULL)
return(NULL);
/* MsgBase Class */
if(js_CreateMsgBaseClass(js_cx, *glob, cfg)==NULL)
break;
/* Queue Class */
if(js_CreateQueueClass(js_cx, js_glob)==NULL)
return(NULL);
/* File Class */
if(js_CreateFileClass(js_cx, *glob)==NULL)
break;
/* MsgBase Class */
if(js_CreateMsgBaseClass(js_cx, js_glob, cfg)==NULL)
return(NULL);
/* User class */
if(js_CreateUserClass(js_cx, *glob, cfg)==NULL)
break;
/* File Class */
if(js_CreateFileClass(js_cx, js_glob)==NULL)
return(NULL);
/* COM Class */
if(js_CreateCOMClass(js_cx, *glob)==NULL)
break;
/* User class */
if(js_CreateUserClass(js_cx, js_glob, cfg)==NULL)
return(NULL);
/* Area Objects */
if(!js_CreateUserObjects(js_cx, *glob, cfg, /* user: */NULL, client, /* html_index_fname: */NULL, /* subscan: */NULL))
break;
/* COM Class */
if(js_CreateCOMClass(js_cx, js_glob)==NULL)
return(NULL);
success=TRUE;
} while(0);
/* Area Objects */
if(!js_CreateUserObjects(js_cx, js_glob, cfg, /* user: */NULL, client, /* html_index_fname: */NULL, /* subscan: */NULL))
return(NULL);
if(!success)
JS_RemoveObjectRoot(js_cx, glob);
return(js_glob);
return(success);
}
#endif /* JAVSCRIPT */
......@@ -667,7 +667,7 @@ js_OperationCallback(JSContext *cx)
JS_SetOperationCallback(cx, js_OperationCallback);
return ret;
}
#endif
static BOOL js_CreateEnvObject(JSContext* cx, JSObject* glob, char** env)
{
char name[256];
......@@ -723,12 +723,13 @@ static BOOL js_init(char** environ)
JS_SetErrorReporter(js_cx, js_ErrorReporter);
/* Global Object */
if((js_glob=js_CreateCommonObjects(js_cx, &scfg, NULL, js_global_functions
if(!js_CreateCommonObjects(js_cx, &scfg, NULL, js_global_functions
,time(NULL), host_name, SOCKLIB_DESC /* system */
,&cb,&startup /* js */
,NULL,INVALID_SOCKET /* client */
,NULL /* server */
))==NULL) {
,&js_glob
)) {
JS_ENDREQUEST(js_cx);
return(FALSE);
}
......@@ -1182,6 +1183,7 @@ int main(int argc, char **argv, char** environ)
fprintf(statfp,"\n");
result=js_exec(module,&argv[argn]);
JS_RemoveObjectRoot(js_cx, &js_glob);
JS_ENDREQUEST(js_cx);
YIELD();
......
......@@ -1800,13 +1800,14 @@ js_mailproc(SOCKET sock, client_t* client, user_t* user, struct mailproc* mailpr
if(*js_glob==NULL) {
/* Global Objects (including system, js, client, Socket, MsgBase, File, User, etc. */
if((*js_glob=js_CreateCommonObjects(*js_cx, &scfg, &scfg, NULL
if(!js_CreateCommonObjects(*js_cx, &scfg, &scfg, NULL
,uptime, startup->host_name, SOCKLIB_DESC /* system */
,&js_callback /* js */
,&startup->js
,client, sock /* client */
,&js_server_props /* server */
))==NULL)
,js_glob
))
break;
if(!JS_DefineFunctions(*js_cx, *js_glob, js_global_functions))
......@@ -1918,10 +1919,14 @@ js_mailproc(SOCKET sock, client_t* client, user_t* user, struct mailproc* mailpr
return(success);
}
void js_cleanup(JSRuntime* js_runtime, JSContext* js_cx)
void js_cleanup(JSRuntime* js_runtime, JSContext* js_cx, JSObject** js_glob)
{
if(js_cx!=NULL)
if(js_cx!=NULL) {
JS_BEGINREQUEST(js_cx);
JS_RemoveObjectRoot(js_cx, js_glob);
JS_ENDREQUEST(js_cx);
JS_DestroyContext(js_cx);
}
if(js_runtime!=NULL)
jsrt_Release(js_runtime);
}
......@@ -4052,7 +4057,7 @@ static void smtp_thread(void* arg)
remove(rcptlst_fname);
if(spy!=NULL)
fclose(spy);
js_cleanup(js_runtime, js_cx);
js_cleanup(js_runtime, js_cx, &js_glob);
status(STATUS_WFC);
......
......@@ -1119,14 +1119,8 @@ bool sbbs_t::js_init(ulong* stack_frame)
return(false);
JS_BEGINREQUEST(js_cx);
memset(&js_branch,0,sizeof(js_branch));
js_branch.limit = startup->js.branch_limit;
js_branch.gc_interval = startup->js.gc_interval;
js_branch.yield_interval = startup->js.yield_interval;
js_branch.terminated = &terminated;
js_branch.auto_terminate = TRUE;
bool success=false;
bool rooted=false;
do {
......@@ -1135,14 +1129,16 @@ bool sbbs_t::js_init(ulong* stack_frame)
JS_SetContextPrivate(js_cx, this); /* Store a pointer to sbbs_t instance */
/* Global Objects (including system, js, client, Socket, MsgBase, File, User, etc. */
if((js_glob=js_CreateCommonObjects(js_cx, &scfg, &cfg, js_global_functions
if(!js_CreateCommonObjects(js_cx, &scfg, &cfg, js_global_functions
,uptime, startup->host_name, SOCKLIB_DESC /* system */
,&js_branch /* js */
,&js_callback /* js */
,&startup->js
,&client, client_socket /* client */
,&js_server_props /* server */
))==NULL)
,&js_glob
))
break;
rooted=true;
/* BBS Object */
if(js_CreateBbsObject(js_cx, js_glob)==NULL)
......@@ -1156,12 +1152,16 @@ bool sbbs_t::js_init(ulong* stack_frame)
} while(0);
JS_ENDREQUEST(js_cx);
if(!success) {
if(rooted)
JS_RemoveObjectRoot(js_cx, &js_glob);
JS_ENDREQUEST(js_cx);
JS_DestroyContext(js_cx);
js_cx=NULL;
return(false);
}
else
JS_ENDREQUEST(js_cx);
return(true);
}
......@@ -1171,6 +1171,9 @@ void sbbs_t::js_cleanup(const char* node)
/* Free Context */
if(js_cx!=NULL) {
lprintf(LOG_DEBUG,"%s JavaScript: Destroying context",node);
JS_BEGINREQUEST(js_cx);
JS_RemoveObjectRoot(js_cx, &js_glob);
JS_ENDREQUEST(js_cx);
JS_DestroyContext(js_cx);
js_cx=NULL;
}
......
......@@ -1045,8 +1045,8 @@ extern "C" {
,js_server_props_t* props);
/* js_global.c */
DLLEXPORT JSObject* DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods, js_startup_t*);
DLLEXPORT JSObject* DLLCALL js_CreateCommonObjects(JSContext* cx
DLLEXPORT BOOL DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods, js_startup_t*, JSObject**);
DLLEXPORT BOOL DLLCALL js_CreateCommonObjects(JSContext* cx
,scfg_t* cfg /* common */
,scfg_t* node_cfg /* node-specific */
,jsSyncMethodSpec* methods /* global */
......@@ -1058,6 +1058,7 @@ extern "C" {
,client_t* client /* client */
,SOCKET client_socket /* client */
,js_server_props_t* props /* server */
,JSObject** glob
);
/* js_internal.c */
......
......@@ -833,9 +833,9 @@ static JSContext*
js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client, JSObject** glob)
{
JSContext* js_cx;
JSObject* js_glob;
JSObject* server;
BOOL success=FALSE;
BOOL rooted=FALSE;
if((js_cx = JS_NewContext(js_runtime, service_client->service->js.cx_stack))==NULL)
return(NULL);
......@@ -849,50 +849,51 @@ js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client,
JS_SetContextPrivate(js_cx, service_client);
if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL, &service_client->service->js))==NULL)
if(!js_CreateGlobalObject(js_cx, &scfg, NULL, &service_client->service->js, glob))
break;
rooted=TRUE;
if (!JS_DefineFunctions(js_cx, js_glob, js_global_functions))
if (!JS_DefineFunctions(js_cx, *glob, js_global_functions))
break;
/* Internal JS Object */
if(js_CreateInternalJsObject(js_cx, js_glob, &service_client->callback, &service_client->service->js)==NULL)
if(js_CreateInternalJsObject(js_cx, *glob, &service_client->callback, &service_client->service->js)==NULL)
break;
/* Client Object */
if(service_client->client!=NULL)
if(js_CreateClientObject(js_cx, js_glob, "client", service_client->client, sock)==NULL)
if(js_CreateClientObject(js_cx, *glob, "client", service_client->client, sock)==NULL)
break;
/* User Class */
if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL)
if(js_CreateUserClass(js_cx, *glob, &scfg)==NULL)
break;
/* Socket Class */
if(js_CreateSocketClass(js_cx, js_glob)==NULL)
if(js_CreateSocketClass(js_cx, *glob)==NULL)
break;
/* MsgBase Class */
if(js_CreateMsgBaseClass(js_cx, js_glob, &scfg)==NULL)
if(js_CreateMsgBaseClass(js_cx, *glob, &scfg)==NULL)
break;
/* File Class */
if(js_CreateFileClass(js_cx, js_glob)==NULL)
if(js_CreateFileClass(js_cx, *glob)==NULL)
break;
/* Queue Class */
if(js_CreateQueueClass(js_cx, js_glob)==NULL)
if(js_CreateQueueClass(js_cx, *glob)==NULL)
break;
/* COM Class */
if(js_CreateCOMClass(js_cx, js_glob)==NULL)
if(js_CreateCOMClass(js_cx, *glob)==NULL)
break;
/* user-specific objects */
if(!js_CreateUserObjects(js_cx, js_glob, &scfg, /*user: */NULL, service_client->client, NULL, service_client->subscan))
if(!js_CreateUserObjects(js_cx, *glob, &scfg, /*user: */NULL, service_client->client, NULL, service_client->subscan))
break;
if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime, startup->host_name, SOCKLIB_DESC)==NULL)
if(js_CreateSystemObject(js_cx, *glob, &scfg, uptime, startup->host_name, SOCKLIB_DESC)==NULL)
break;
#if 0
char ver[256];
......@@ -900,7 +901,7 @@ js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client,
jsval val;
/* server object */
if((server=JS_DefineObject(js_cx, js_glob, "server", &js_server_class
if((server=JS_DefineObject(js_cx, *glob, "server", &js_server_class
,NULL,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL)
break;
......@@ -935,7 +936,7 @@ js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client,
&service_client->service->options;
}
if((server=js_CreateServerObject(js_cx,js_glob
if((server=js_CreateServerObject(js_cx,*glob
,&service_client->service->js_server_props))==NULL)
break;
#endif
......@@ -948,16 +949,14 @@ js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client,
JS_DefineFunction(js_cx, server, "client_update", js_client_update, 1, 0);
JS_DefineFunction(js_cx, server, "client_remove", js_client_remove, 1, 0);
if(glob!=NULL)
*glob=js_glob;
success=TRUE;
} while(0);
if(!success) {
if(rooted)
JS_RemoveObjectRoot(js_cx, glob);
JS_ENDREQUEST(js_cx);
JS_DestroyContext(js_cx);
return(NULL);
......@@ -1184,6 +1183,7 @@ static void js_service_thread(void* arg)
JS_ExecuteScript(js_cx, js_glob, js_script, &rval);
js_EvalOnExit(js_cx, js_glob, &service_client.callback);
}
JS_RemoveObjectRoot(js_cx, &js_glob);
JS_ENDREQUEST(js_cx);
JS_DestroyContext(js_cx); /* Free Context */