CVE-2020-22875 (published 2021-07-13T15:15Z)

Integer overflow vulnerability in function Jsi_ObjSetLength in jsish before 3.0.6, allows remote attackers to execute arbitrary code.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-190
cwe_name: Integer Overflow or Wraparound
description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
extended_description: 
            
            
            
            
         
         

Fix information:
repo_url: https://github.com/pcmacdon/jsish
commit_details: repo_url: https://github.com/pcmacdon/jsish
author: pmacdona
author_date: 2020-04-13 16:07:27+00:00
msg: Release "3.0.6": Fix crashes in Array for "integer overflow #10"

FossilOrigin-Name: 50642d64b8f0a4e62df68e59fcb2ef0923c3dbec8fc8a15d38b1ddbe655c38d6
repository: repo_url: https://github.com/pcmacdon/jsish
repo_name: pcmacdon/jsish
description: Jsi is a small, C-embeddable javascript interpreter with tightly woven Web and DB support.
repo_language: C
owner: pcmacdon
file_changes: filename: Reference.md
change_type: ModificationType.MODIFY
diff: @@ -519,7 +519,7 @@ Otherwise second argument must be a set of options.</td></tr>
 <tr><td>level</td><td>level(level:number=void):number|array|object </td><td>Return current level or details of a call-stack frame. With no arg, returns the number of the current stack frame level.
 Otherwise returns details on the specified level.
 The topmost level is 1, and 0 is the current level, and a negative level translates as relative to the current level.</td></tr>
-<tr><td>locals</td><td>locals(varsOnly:boolean=void):object </td><td>Return functions/vars inside local function.</td></tr>
+<tr><td>locals</td><td>locals(filter:boolean=void):object </td><td>Return locals; use filter=true/false just vars/functions.</td></tr>
 <tr><td>lookup</td><td>lookup(name:string) </td><td>Given string name, lookup and return value, eg: function.</td></tr>
 <tr><td>methods</td><td>methods(val:string|regexp):array|object </td><td>Return functions and commands.</td></tr>
 <tr><td>named</td><td>named(name:string=void):array|userobj </td><td>Returns command names for builtin Objects, eg: 'File', 'Interp', sub-Object names, or the named object.</td></tr>
@@ -1328,6 +1328,7 @@ With one argument, loads the package (if necessary) and returns its version.
 With two arguments, returns object containing: version, loadFile, func.
 A third argument sets options for package or module.
 Note an error is thrown if requested version is greater than actual version.</td></tr>
+<tr><td>runMain</td><td>runMain(cmd:string|null|function=void, conf:array=undefined) </td><td>If isMain invokes runModule.</td></tr>
 <tr><td>runModule</td><td>runModule(cmd:string|null|function=void, conf:array=undefined) </td><td>Invoke named module. If name is empty, uses file basename. If isMain and no args givine parses console.args.</td></tr>
 <tr><td>setInterval</td><td>setInterval(callback:function, ms:number):number </td><td>Setup recurring function to run every given millisecs.</td></tr>
 <tr><td>setTimeout</td><td>setTimeout(callback:function, ms:number):number </td><td>Setup function to run after given millisecs.</td></tr>

programming_language: HTML
filename: jsi.h
change_type: ModificationType.MODIFY
diff: @@ -4,7 +4,7 @@
 
 #define JSI_VERSION_MAJOR   3
 #define JSI_VERSION_MINOR   0
-#define JSI_VERSION_RELEASE 4
+#define JSI_VERSION_RELEASE 6
 
 #define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))
 

programming_language: C
filename: jsiArray.c
change_type: ModificationType.MODIFY
diff: @@ -7,6 +7,12 @@
 #define NO_QSORT_R 1
 #endif
 
+static uint jsi_SizeOfArray(Jsi_Interp *interp, Jsi_Obj *obj) {
+    if (!obj || !obj->arr)
+        return 0;
+    return obj->arrCnt;
+}
+
 static Jsi_RC jsi_ArrayPushCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
     Jsi_Value **ret, Jsi_Func *funcPtr)
 {
@@ -19,11 +25,7 @@ static Jsi_RC jsi_ArrayPushCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_
     obj = _this->d.obj;
     
     int argc = Jsi_ValueGetLength(interp, args);
-    int curlen = Jsi_ObjGetLength(interp, obj);
-    if (curlen < 0) {
-        Jsi_ObjSetLength(interp, obj, 0);
-    }
-    
+    int curlen = jsi_SizeOfArray(interp, obj);    
     int i;
     for (i = 0; i < argc; ++i) {
         Jsi_Value *ov = Jsi_ValueArrayIndex(interp, args, i);
@@ -31,7 +33,7 @@ static Jsi_RC jsi_ArrayPushCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_
         Jsi_ValueInsertArray(interp, _this, curlen + i, ov, 0);
     }
     
-    Jsi_ValueMakeNumber(interp, ret, Jsi_ObjGetLength(interp, obj));
+    Jsi_ValueMakeNumber(interp, ret, jsi_SizeOfArray(interp, obj));
     return JSI_OK;
 }
 
@@ -45,7 +47,7 @@ static Jsi_RC jsi_ArrayPopCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_t
     Jsi_Value *v;
     Jsi_Obj *obj;
     obj = _this->d.obj;
-    int i = Jsi_ObjGetLength(interp, obj) - 1;
+    int i = jsi_SizeOfArray(interp, obj) - 1;
 
     if (i < 0) {
         Jsi_ValueMakeUndef(interp, ret);
@@ -78,7 +80,7 @@ static Jsi_RC jsi_ArrayJoinCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_
     int argc, curlen;
     Jsi_DString dStr = {};
 
-    curlen = Jsi_ObjGetLength(interp, _this->d.obj);
+    curlen = jsi_SizeOfArray(interp, _this->d.obj);
     if (curlen == 0) {
         goto bail;
     }
@@ -89,7 +91,7 @@ static Jsi_RC jsi_ArrayJoinCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_
             jstr = Jsi_ValueToString(interp, sc, NULL);
     }
     
-    if (0 == (argc=Jsi_ObjGetLength(interp, _this->d.obj))) {
+    if (0 == (argc=jsi_SizeOfArray(interp, _this->d.obj))) {
         goto bail;
     }
     int i;
@@ -233,7 +235,7 @@ void Jsi_ValueArrayShift(Jsi_Interp *interp, Jsi_Value *v)
         return;
     }
     
-    int len = Jsi_ObjGetLength(interp, v->d.obj);
+    int len = jsi_SizeOfArray(interp, v->d.obj);
     if (len <= 0) return;
     
     Jsi_Value *v0 = Jsi_ValueArrayIndex(interp, v, 0);
@@ -255,10 +257,10 @@ void Jsi_ValueArrayShift(Jsi_Interp *interp, Jsi_Value *v)
 
 static Jsi_RC jsi_ArrayFlatSub(Jsi_Interp *interp, Jsi_Obj* nobj, Jsi_Value *arr, int depth) {
     
-    int i, n = 0, len = Jsi_ObjGetLength(interp, arr->d.obj);
+    int i, n = 0, len = jsi_SizeOfArray(interp, arr->d.obj);
     if (len <= 0) return JSI_OK;
     Jsi_RC rc = JSI_OK;
-    int clen = Jsi_ObjGetLength(interp, nobj);
+    int clen = jsi_SizeOfArray(interp, nobj);
     for (i = 0; i < len && rc == JSI_OK; i++) {
         Jsi_Value *t = Jsi_ValueArrayIndex(interp, arr, i);
         if (t && depth>0 && Jsi_ValueIsArray(interp, t))
@@ -302,10 +304,7 @@ static Jsi_RC jsi_ArrayConcatCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value
     obj = _this->d.obj;
     
     argc = Jsi_ValueGetLength(interp, args);
-    curlen = Jsi_ObjGetLength(interp, obj);
-    if (curlen < 0) {
-        Jsi_ObjSetLength(interp, obj, 0);
-    }
+    curlen = jsi_SizeOfArray(interp, obj);
     Jsi_ObjListifyArray(interp, obj);
    
     nobj = Jsi_ObjNewType(interp, JSI_OT_ARRAY);
@@ -377,10 +376,7 @@ static Jsi_RC jsi_ArrayMapCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_t
     if (!sthis)
         sthis = nthis = Jsi_ValueNew1(interp);
     obj = _this->d.obj;
-    curlen = Jsi_ObjGetLength(interp, obj);    
-    if (curlen < 0) {
-        Jsi_ObjSetLength(interp, obj, 0);
-    }
+    curlen = jsi_SizeOfArray(interp, obj);    
     Jsi_ObjListifyArray(interp, obj);
     nobj = Jsi_ObjNewType(interp, JSI_OT_ARRAY);
     nsiz = obj->arrCnt;
@@ -439,10 +435,7 @@ static Jsi_RC jsi_ArrayFilterCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value
     if (!sthis)
         sthis = nthis = Jsi_ValueNew1(interp);
     obj = _this->d.obj;
-    curlen = Jsi_ObjGetLength(interp, obj);    
-    if (curlen < 0) {
-        Jsi_ObjSetLength(interp, obj, 0);
-    }
+    curlen = jsi_SizeOfArray(interp, obj);    
     Jsi_ObjListifyArray(interp, obj);
     nobj = Jsi_ObjNewType(interp, JSI_OT_ARRAY);
     nsiz = obj->arrCnt;
@@ -522,7 +515,6 @@ static Jsi_RC jsi_ArrayForeachCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value
     if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj)) 
         return Jsi_LogError("expected array object");
     Jsi_Obj *obj;
-    int curlen;
     uint i;
     Jsi_Value *func, *vpargs;
 
@@ -535,10 +527,6 @@ static Jsi_RC jsi_ArrayForeachCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value
         sthis = nthis = Jsi_ValueNew1(interp);
 
     obj = _this->d.obj;
-    curlen = Jsi_ObjGetLength(interp, obj);    
-    if (curlen < 0) {
-        Jsi_ObjSetLength(interp, obj, 0);
-    }
     Jsi_ObjListifyArray(interp, obj);
     Jsi_RC rc = JSI_OK;
     
@@ -566,7 +554,6 @@ static Jsi_RC jsi_ArrayFindSubCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value
     if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj)) 
         return Jsi_LogError("expected array");
     Jsi_Obj *obj;
-    int curlen;
     uint i;
     Jsi_RC rc = JSI_OK;
     Jsi_Value *func, *vpargs, *sthis = Jsi_ValueArrayIndex(interp, args, 1);
@@ -579,10 +566,6 @@ static Jsi_RC jsi_ArrayFindSubCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value
         sthis = nthis = Jsi_ValueNew1(interp);
 
     obj = _this->d.obj;
-    curlen = Jsi_ObjGetLength(interp, obj);    
-    if (curlen < 0) {
-        Jsi_ObjSetLength(interp, obj, 0);
-    }
     Jsi_ObjListifyArray(interp, obj);
     int fval = 0;
     Jsi_Value *nrPtr = Jsi_ValueNew1(interp);
@@ -628,7 +611,7 @@ static Jsi_RC jsi_ArrayReduceSubCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Val
     if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj)) 
         return Jsi_LogError("expected array");
     Jsi_RC rc = JSI_OK;
-    int curlen, i;
+    int i;
     Jsi_Obj *obj;
     Jsi_Value *func, *vpargs, *ini = Jsi_ValueArrayIndex(interp, args, 1);
 
@@ -638,9 +621,6 @@ static Jsi_RC jsi_ArrayReduceSubCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Val
 
     Jsi_Value *nrPtr = Jsi_ValueNew1(interp);
     obj = _this->d.obj;
-    curlen = Jsi_ObjGetLength(interp, obj);    
-    if (curlen < 0)
-        Jsi_ObjSetLength(interp, obj, 0);
     Jsi_ObjListifyArray(interp, obj);
     Jsi_Value *vobjs[4];
     int n, rev = (op==2);
@@ -717,7 +697,7 @@ static Jsi_RC jsi_ArrayIndexSubCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Valu
         goto bail;
     }
     
-    n = Jsi_ObjGetLength(interp, obj);    
+    n = jsi_SizeOfArray(interp, obj);    
     if (n == 0) {
         goto bail;
     }
@@ -769,7 +749,7 @@ static Jsi_RC jsi_ArrayIncludesCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Valu
 static Jsi_RC jsi_ArraySizeOfCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,Jsi_Value **ret, Jsi_Func *funcPtr) {
     if (_this->vt != JSI_VT_OBJECT || !Jsi_ObjIsArray(interp, _this->d.obj))
         return Jsi_LogError("expected array object");
-    int i = Jsi_ObjGetLength(interp, _this->d.obj);
+    int i = jsi_SizeOfArray(interp, _this->d.obj);
     Jsi_ValueMakeNumber(interp, ret, i);
     return JSI_OK;
 }
@@ -780,8 +760,7 @@ static Jsi_RC jsi_ArrayShiftCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *
     Jsi_Value *v;
     Jsi_Obj *obj = _this->d.obj;
     Jsi_ObjListifyArray(interp, obj);
-    uint n = Jsi_ObjGetLength(interp, obj);
-    assert(n <= obj->arrCnt);
+    uint n = jsi_SizeOfArray(interp, obj);
     if (n<=0) {
         Jsi_ValueMakeUndef(interp, ret);
     } else {
@@ -802,10 +781,7 @@ static Jsi_RC jsi_ArrayUnshiftCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value
 
     Jsi_Obj *obj = _this->d.obj;
     int argc = Jsi_ValueGetLength(interp, args);
-    int curlen = Jsi_ObjGetLength(interp, obj);
-    if (curlen < 0) {
-        Jsi_ObjSetLength(interp, obj, 0);
-    }
+    int curlen = jsi_SizeOfArray(interp, obj);
     if (argc <= 0) {
         Jsi_ValueMakeNumber(interp, ret, 0);
         return JSI_OK;
@@ -825,7 +801,7 @@ static Jsi_RC jsi_ArrayUnshiftCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value
     }
     Jsi_ObjSetLength(interp, obj, curlen+argc);
     
-    Jsi_ValueMakeNumber(interp, ret, Jsi_ObjGetLength(interp, obj));
+    Jsi_ValueMakeNumber(interp, ret, jsi_SizeOfArray(interp, obj));
     return JSI_OK;
 }
 
@@ -839,7 +815,7 @@ static Jsi_RC jsi_ArrayFillCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_
         *start = Jsi_ValueArrayIndex(interp, args, 1),
         *end = Jsi_ValueArrayIndex(interp, args, 2);
     Jsi_Obj *obj = _this->d.obj;
-    n = Jsi_ObjGetLength(interp, obj);
+    n = jsi_SizeOfArray(interp, obj);
 
     if (start && Jsi_GetNumberFromValue(interp, start, &nstart) == JSI_OK) {
         istart = (int)nstart;
@@ -902,7 +878,7 @@ static Jsi_RC jsi_ArraySliceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *
         goto bail;
     }
     obj = _this->d.obj;
-    n = Jsi_ObjGetLength(interp, obj);
+    n = jsi_SizeOfArray(interp, obj);
     if (Jsi_GetNumberFromValue(interp,start, &nstart) == JSI_OK) {
         istart = (int)nstart;
         if (istart > n)
@@ -1166,7 +1142,7 @@ static Jsi_RC jsi_ArraySpliceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value
     argc = Jsi_ValueGetLength(interp, args);
     istart = 0;
     ilen = (argc>=2 ? argc - 2 : 0);
-    n = Jsi_ObjGetLength(interp, obj);
+    n = jsi_SizeOfArray(interp, obj);
     curlen = n;
     
     if (!start) {
@@ -1202,7 +1178,7 @@ static Jsi_RC jsi_ArraySpliceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value
     }
     
     if (curlen < 0) {
-        Jsi_ObjSetLength(interp, obj, 0);
+        Jsi_ObjSetLength(interp, obj, curlen=0);
     }
     Jsi_ObjListifyArray(interp, obj);
    

programming_language: C
filename: jsiCmds.c
change_type: ModificationType.MODIFY
diff: @@ -4509,6 +4509,14 @@ done:
     return rc;
 }
 
+static Jsi_RC SysRunMainCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
+    Jsi_Value **ret, Jsi_Func *funcPtr)
+{
+    if (jsi_isMain(interp))
+        return SysRunModuleCmd(interp, args, _this, ret, funcPtr);
+    return JSI_OK;
+}
+
 static const char *jsi_FindHelpStr(const char *fstr, const char *key, Jsi_DString *dPtr) {
     if (!fstr) return "";
     Jsi_DSSetLength(dPtr, 0);
@@ -4762,7 +4770,7 @@ static Jsi_CmdSpec infoCmds[] = {
     { "execZip",    InfoExecZipCmd,     0,  0, "", .help="If executing a .zip file, return file name", .retType=(uint)JSI_TT_STRING|JSI_TT_VOID },
     { "files",      InfoFilesCmd,       0,  0, "", .help="Return list of all sourced files", .retType=(uint)JSI_TT_ARRAY },
     { "funcs",      InfoFuncsCmd,       0,  1, "string|regexp|object=void", .help="Return details or list of matching functions", .retType=(uint)JSI_TT_ARRAY|JSI_TT_OBJECT },
-    { "locals",     InfoLocalsCmd,      0,  1, "varsOnly:boolean=void", .help="Return functions/vars inside local function", .retType=(uint)JSI_TT_OBJECT },
+    { "locals",     InfoLocalsCmd,      0,  1, "filter:boolean=void", .help="Return locals; use filter=true/false just vars/functions", .retType=(uint)JSI_TT_OBJECT },
     { "interp",     jsi_InterpInfo,     0,  1, "interp:userobj=void", .help="Return info on given or current interp", .retType=(uint)JSI_TT_OBJECT },
     { "isMain",     InfoIsMainCmd,      0,  0, "", .help="Return true if current script was the main script invoked from command-line", .retType=(uint)JSI_TT_BOOLEAN },
     { "keywords",   InfoKeywordsCmd,    0,  2, "isSql=false, name:string=void", .help="Return/lookup reserved keyword", .retType=(uint)JSI_TT_ARRAY|JSI_TT_BOOLEAN },
@@ -4863,6 +4871,7 @@ static Jsi_CmdSpec sysCmds[] = {
     { "puts",       SysPutsCmd,      1, -1, "val, ...", .help="Output one or more values to stdout", .retType=(uint)JSI_TT_VOID, .flags=0, .info=FN_puts },
     { "quote",      SysQuoteCmd,     1,  1, "val:string", .help="Return quoted string", .retType=(uint)JSI_TT_STRING },
     { "require",    SysRequireCmd,   0,  3, "name:string=void, version:number|string=1, options:object=void", .help="Load/query packages", .retType=(uint)JSI_TT_NUMBER|JSI_TT_OBJECT|JSI_TT_ARRAY, .flags=0, .info=FN_require, .opts=jsiModuleOptions },
+    { "runMain",    SysRunMainCmd,   0,  2, "cmd:string|null|function=void, conf:array=undefined", .help="If isMain invokes runModule", .retType=(uint)JSI_TT_ANY, .flags=0},
     { "runModule",  SysRunModuleCmd, 0,  2, "cmd:string|null|function=void, conf:array=undefined", .help="Invoke named module. If name is empty, uses file basename. If isMain and no args givine parses console.args", .retType=(uint)JSI_TT_ANY, .flags=0},
     { "sleep",      SysSleepCmd,     0,  1, "secs:number=1.0",  .help="sleep for N milliseconds, minimum .001", .retType=(uint)JSI_TT_VOID },
 #ifndef JSI_OMIT_EVENT

programming_language: C
filename: locals.jsi
change_type: ModificationType.ADD
diff: @@ -0,0 +1,19 @@
+function foo() {
+
+
+  function bar() { }
+  var x = 1;
+;  Info.locals();
+;  Info.locals(false);
+;  Info.locals(true);
+}
+
+foo();
+
+/*
+=!EXPECTSTART!=
+Info.locals() ==> { bar:"function bar() {...}", x:1 }
+Info.locals(false) ==> { bar:"function bar() {...}" }
+Info.locals(true) ==> { x:1 }
+=!EXPECTEND!=
+*/

programming_language: TypeScript
filename: protos.jsi
change_type: ModificationType.MODIFY
diff: @@ -1,4 +1,4 @@
-//JSI Command Prototypes: version 3.0.4
+//JSI Command Prototypes: version 3.0.6
 throw("NOT EXECUTABLE: USE FILE IN GEANY EDITOR FOR CMD LINE COMPLETION + GOTO TAG");
 
 var Array = function(cmd,args) {};
@@ -140,7 +140,7 @@ Info.prototype.interp = function(interp:userobj=void):object {};
 Info.prototype.isMain = function():boolean {};
 Info.prototype.keywords = function(isSql=false, name:string=void):boolean|array {};
 Info.prototype.level = function(level:number=void):number|array|object {};
-Info.prototype.locals = function(varsOnly:boolean=void):object {};
+Info.prototype.locals = function(filter:boolean=void):object {};
 Info.prototype.lookup = function(name:string):any {};
 Info.prototype.methods = function(val:string|regexp):array|object {};
 Info.prototype.named = function(name:string=void):array|userobj {};
@@ -303,6 +303,7 @@ System.prototype.provide = function(name:string|function=void, version:number|st
 System.prototype.puts = function(val, ...):void {};
 System.prototype.quote = function(val:string):string {};
 System.prototype.require = function(name:string=void, version:number|string=1, options:object=void):number|array|object {};
+System.prototype.runMain = function(cmd:string|null|function=void, conf:array=undefined):any {};
 System.prototype.runModule = function(cmd:string|null|function=void, conf:array=undefined):any {};
 System.prototype.setInterval = function(callback:function, ms:number):number {};
 System.prototype.setTimeout = function(callback:function, ms:number):number {};
@@ -394,6 +395,7 @@ var provide = function(name:string|function=void, version:number|string=1.0, opt
 var puts = function(val, ...):void {};
 var quote = function(val:string):string {};
 var require = function(name:string=void, version:number|string=1, options:object=void):number|array|object {};
+var runMain = function(cmd:string|null|function=void, conf:array=undefined):any {};
 var runModule = function(cmd:string|null|function=void, conf:array=undefined):any {};
 var setInterval = function(callback:function, ms:number):number {};
 var setTimeout = function(callback:function, ms:number):number {};

programming_language: Lua
filename: reference.wiki
change_type: ModificationType.MODIFY
diff: @@ -552,7 +552,7 @@ Otherwise second argument must be a set of options.</td></tr>
 <tr><td>level</td><td>level(level:number=void):number|array|object </td><td>Return current level or details of a call-stack frame. With no arg, returns the number of the current stack frame level.
 Otherwise returns details on the specified level.
 The topmost level is 1, and 0 is the current level, and a negative level translates as relative to the current level.</td></tr>
-<tr><td>locals</td><td>locals(varsOnly:boolean=void):object </td><td>Return functions/vars inside local function.</td></tr>
+<tr><td>locals</td><td>locals(filter:boolean=void):object </td><td>Return locals; use filter=true/false just vars/functions.</td></tr>
 <tr><td>lookup</td><td>lookup(name:string) </td><td>Given string name, lookup and return value, eg: function.</td></tr>
 <tr><td>methods</td><td>methods(val:string|regexp):array|object </td><td>Return functions and commands.</td></tr>
 <tr><td>named</td><td>named(name:string=void):array|userobj </td><td>Returns command names for builtin Objects, eg: 'File', 'Interp', sub-Object names, or the named object.</td></tr>
@@ -1361,6 +1361,7 @@ With one argument, loads the package (if necessary) and returns its version.
 With two arguments, returns object containing: version, loadFile, func.
 A third argument sets options for package or module.
 Note an error is thrown if requested version is greater than actual version.</td></tr>
+<tr><td>runMain</td><td>runMain(cmd:string|null|function=void, conf:array=undefined) </td><td>If isMain invokes runModule.</td></tr>
 <tr><td>runModule</td><td>runModule(cmd:string|null|function=void, conf:array=undefined) </td><td>Invoke named module. If name is empty, uses file basename. If isMain and no args givine parses console.args.</td></tr>
 <tr><td>setInterval</td><td>setInterval(callback:function, ms:number):number </td><td>Setup recurring function to run every given millisecs.</td></tr>
 <tr><td>setTimeout</td><td>setTimeout(callback:function, ms:number):number </td><td>Setup function to run after given millisecs.</td></tr>

programming_language: HTML