Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

Commit c912ee30 authored by rswindell's avatar rswindell

Invoking a JavaScripot global hot key event handler (e.g. nodelist.js) *while*

running a JavaScript module would crash (e.g. segfault) sbbs:
Create and use a separate JS runtime, context, and global object/scope for
global hotkey events. This means that the hotkey won't benefit from any
previously loaded/required scripts, possibly effecting the performance of the
first invocation of the hotkey handler. Subsequent JS hotkey events will reuse
the same runtime/context/global, so they'll execute fast(er).

One questionalbe change to js_execfile():
With the JS_GC (garbage collection) call *before* the JS_ENDREQUEST() call, the
process would crash in libmozjs. Moving the JS_GC() call to *after* the
JS_ENDREQUEST() resolved this issue and I'm not clear why. This 'js_cx'
parameter here is not always sbbs_t::js_cx. When called to handle a JS hotkey
event, it's sbbs_t::js_hotkey_cx, so it shouldn't interfere with the
sbs_t::js_cx being used by the currently executing JS module (shell or door).
<scratches chin>
parent aa2bcd61
......@@ -562,7 +562,7 @@ js_OperationCallback(JSContext *cx)
return ret;
}
long sbbs_t::js_execfile(const char *cmd, const char* startup_dir, JSObject* scope)
long sbbs_t::js_execfile(const char *cmd, const char* startup_dir, JSObject* scope, JSContext* js_cx)
{
char* p;
char* args=NULL;
......@@ -577,6 +577,9 @@ long sbbs_t::js_execfile(const char *cmd, const char* startup_dir, JSObject* sco
jsval rval;
int32 result=0;
if(js_cx == NULL)
js_cx = this->js_cx;
if(js_cx==NULL) {
errormsg(WHERE,ERR_CHK,"JavaScript support",0);
errormsg(WHERE,ERR_EXEC,cmd,0);
......@@ -720,9 +723,8 @@ long sbbs_t::js_execfile(const char *cmd, const char* startup_dir, JSObject* sco
JS_RemoveValueRoot(js_cx, &old_js_argc);
}
JS_GC(js_cx);
JS_ENDREQUEST(js_cx);
JS_GC(js_cx);
return(result);
}
......
......@@ -183,10 +183,14 @@ char sbbs_t::handle_ctrlkey(char ch, long mode)
attr(LIGHTGRAY);
CRLF;
}
if(cfg.hotkey[i]->cmd[0]=='?')
js_execfile(cmdstr(cfg.hotkey[i]->cmd+1,nulstr,nulstr,NULL), /* startup_dir: */NULL, /* scope: */js_glob);
else
external(cmdstr(cfg.hotkey[i]->cmd,nulstr,nulstr,NULL),0);
if(cfg.hotkey[i]->cmd[0]=='?') {
if(js_hotkey_cx == NULL) {
js_hotkey_cx = js_init(&js_hotkey_runtime, &js_hotkey_glob, "HotKey");
js_create_user_objects(js_hotkey_cx, js_hotkey_glob);
}
js_execfile(cmdstr(cfg.hotkey[i]->cmd+1,nulstr,nulstr,tmp), /* startup_dir: */NULL, /* scope: */js_hotkey_glob, js_hotkey_cx);
} else
external(cmdstr(cfg.hotkey[i]->cmd,nulstr,nulstr,tmp),0);
if(!(sys_status&SS_SPLITP)) {
CRLF;
RESTORELINE;
......
......@@ -66,7 +66,7 @@ bool sbbs_t::logon()
client_on(client_socket,&client,TRUE /* update */);
#ifdef JAVASCRIPT
js_create_user_objects();
js_create_user_objects(js_cx, js_glob);
#endif
if(useron.rest&FLAG('Q'))
......
......@@ -1259,22 +1259,23 @@ js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
JS_RESUMEREQUEST(cx, rc);
}
bool sbbs_t::js_init(ulong* stack_frame)
JSContext* sbbs_t::js_init(JSRuntime** runtime, JSObject** glob, const char* desc)
{
JSContext* js_cx;
if(startup->js.max_bytes==0) startup->js.max_bytes=JAVASCRIPT_MAX_BYTES;
if(startup->js.cx_stack==0) startup->js.cx_stack=JAVASCRIPT_CONTEXT_STACK;
lprintf(LOG_DEBUG,"JavaScript: Creating runtime: %lu bytes"
,startup->js.max_bytes);
if((js_runtime = jsrt_GetNew(startup->js.max_bytes, 1000, __FILE__, __LINE__))==NULL)
return(false);
lprintf(LOG_DEBUG,"JavaScript: Creating %s runtime: %lu bytes"
,desc, startup->js.max_bytes);
if((*runtime = jsrt_GetNew(startup->js.max_bytes, 1000, __FILE__, __LINE__)) == NULL)
return NULL;
lprintf(LOG_DEBUG,"JavaScript: Initializing context (stack: %lu bytes)"
,startup->js.cx_stack);
lprintf(LOG_DEBUG,"JavaScript: Initializing %s context (stack: %lu bytes)"
,desc, startup->js.cx_stack);
if((js_cx = JS_NewContext(js_runtime, startup->js.cx_stack))==NULL)
return(false);
if((js_cx = JS_NewContext(*runtime, startup->js.cx_stack))==NULL)
return NULL;
JS_BEGINREQUEST(js_cx);
memset(&js_callback,0,sizeof(js_callback));
......@@ -1300,22 +1301,22 @@ bool sbbs_t::js_init(ulong* stack_frame)
,&startup->js
,&client, client_socket, -1 /* client */
,&js_server_props /* server */
,&js_glob
,glob
))
break;
rooted=true;
#ifdef BUILD_JSDOCS
js_CreateUifcObject(js_cx, js_glob);
js_CreateConioObject(js_cx, js_glob);
js_CreateUifcObject(js_cx, *glob);
js_CreateConioObject(js_cx, *glob);
#endif
/* BBS Object */
if(js_CreateBbsObject(js_cx, js_glob)==NULL)
if(js_CreateBbsObject(js_cx, *glob)==NULL)
break;
/* Console Object */
if(js_CreateConsoleObject(js_cx, js_glob)==NULL)
if(js_CreateConsoleObject(js_cx, *glob)==NULL)
break;
success=true;
......@@ -1324,16 +1325,16 @@ bool sbbs_t::js_init(ulong* stack_frame)
if(!success) {
if(rooted)
JS_RemoveObjectRoot(js_cx, &js_glob);
JS_RemoveObjectRoot(js_cx, glob);
JS_ENDREQUEST(js_cx);
JS_DestroyContext(js_cx);
js_cx=NULL;
return(false);
return NULL;
}
else
JS_ENDREQUEST(js_cx);
return(true);
return js_cx;
}
void sbbs_t::js_cleanup(void)
......@@ -1353,17 +1354,36 @@ void sbbs_t::js_cleanup(void)
jsrt_Release(js_runtime);
js_runtime=NULL;
}
if(js_hotkey_cx!=NULL) {
lprintf(LOG_DEBUG,"JavaScript: Destroying HotKey context");
JS_BEGINREQUEST(js_hotkey_cx);
JS_RemoveObjectRoot(js_hotkey_cx, &js_hotkey_glob);
JS_ENDREQUEST(js_hotkey_cx);
JS_DestroyContext(js_hotkey_cx);
js_hotkey_cx=NULL;
}
if(js_hotkey_runtime!=NULL) {
lprintf(LOG_DEBUG,"JavaScript: Destroying HotKey runtime");
jsrt_Release(js_hotkey_runtime);
js_hotkey_runtime=NULL;
}
}
void sbbs_t::js_create_user_objects(void)
bool sbbs_t::js_create_user_objects(JSContext* cx, JSObject* glob)
{
if(js_cx==NULL)
return;
JS_BEGINREQUEST(js_cx);
if(!js_CreateUserObjects(js_cx, js_glob, &cfg, &useron, &client, NULL, subscan))
lprintf(LOG_ERR,"!JavaScript ERROR creating user objects");
JS_ENDREQUEST(js_cx);
bool result = false;
if(cx != NULL) {
JS_BEGINREQUEST(cx);
if(!js_CreateUserObjects(cx, glob, &cfg, &useron, &client, NULL, subscan))
lprintf(LOG_ERR,"!JavaScript ERROR creating user objects");
else
result = true;
JS_ENDREQUEST(cx);
}
return result;
}
extern "C" BOOL DLLCALL js_CreateCommonObjects(JSContext* js_cx
......@@ -2490,7 +2510,6 @@ void output_thread(void* arg)
void event_thread(void* arg)
{
ulong stack_frame;
char str[MAX_PATH+1];
char bat_list[MAX_PATH+1];
char semfile[MAX_PATH+1];
......@@ -2524,7 +2543,7 @@ void event_thread(void* arg)
#ifdef JAVASCRIPT
if(!(startup->options&BBS_OPT_NO_JAVASCRIPT)) {
if(!sbbs->js_init(&stack_frame)) /* This must be done in the context of the events thread */
if((sbbs->js_cx = sbbs->js_init(&sbbs->js_runtime, &sbbs->js_glob, "event")) == NULL) /* This must be done in the context of the events thread */
lprintf(LOG_ERR,"!JavaScript Initialization FAILURE");
}
#endif
......@@ -3389,6 +3408,8 @@ sbbs_t::sbbs_t(ushort node_num, union xp_sockaddr *addr, size_t addr_len, const
#ifdef JAVASCRIPT
js_runtime=NULL; /* runtime */
js_cx=NULL; /* context */
js_hotkey_runtime = NULL;
js_hotkey_cx = NULL;
#endif
for(i=0;i<TOTAL_TEXT;i++)
......@@ -4407,7 +4428,6 @@ void sbbs_t::logoffstats()
void node_thread(void* arg)
{
ulong stack_frame;
char str[128];
int file;
uint curshell=0;
......@@ -4427,7 +4447,7 @@ void node_thread(void* arg)
#ifdef JAVASCRIPT
if(!(startup->options&BBS_OPT_NO_JAVASCRIPT)) {
if(!sbbs->js_init(&stack_frame)) /* This must be done in the context of the node thread */
if((sbbs->js_cx = sbbs->js_init(&sbbs->js_runtime, &sbbs->js_glob, "node")) == NULL) /* This must be done in the context of the node thread */
lprintf(LOG_ERR,"Node %d !JavaScript Initialization FAILURE",sbbs->cfg.node_num);
}
#endif
......
......@@ -474,7 +474,7 @@ BOOL sbbs_t::newuser()
answertime=starttime=time(NULL); /* set answertime to now */
#ifdef JAVASCRIPT
js_create_user_objects();
js_create_user_objects(js_cx, js_glob);
#endif
if(cfg.newuser_mod[0])
......
......@@ -394,11 +394,14 @@ public:
JSRuntime* js_runtime;
JSContext* js_cx;
JSObject* js_glob;
JSRuntime* js_hotkey_runtime;
JSContext* js_hotkey_cx;
JSObject* js_hotkey_glob;
js_callback_t js_callback;
long js_execfile(const char *fname, const char* startup_dir, JSObject* scope=NULL);
bool js_init(ulong* stack_frame);
long js_execfile(const char *fname, const char* startup_dir, JSObject* scope = NULL, JSContext* cx = NULL);
JSContext* js_init(JSRuntime**, JSObject**, const char* desc);
void js_cleanup(void);
void js_create_user_objects(void);
bool js_create_user_objects(JSContext*, JSObject* glob);
#endif
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment