JS::CallArgs - Arguments are not being parsed in C++

33 views
Skip to first unread message

amande...@gmail.com

unread,
Apr 30, 2020, 5:37:19 PM4/30/20
to
I am using Spidermonkey 52 and below is my sample implementation.



static JSClassOps global_ops = {
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
JS_GlobalObjectTraceHook
};

//Creating Global Context Object
JSContext * createContext() {
JSContext *cx = JS_NewContext(8L * 1024 * 1024,8192);
if (!cx)
return NULL;

return cx;
}


static JSClass * basicGlobalClass() {

static JSClass c = {
"global",
JSCLASS_GLOBAL_FLAGS,
&global_ops
};
return &c;
}

JSClass * getGlobalClass() {
return basicGlobalClass();
}
//Creating Global Object and initiating basic initializers
void createGlobal(JSPrincipals *principals)
{
JS::CompartmentOptions options;
options.behaviors().setVersion(JSVERSION_LATEST);

JS::RootedObject globalTemp(cx);

globalTemp = JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook, options);

JSAutoCompartment ac(cx, globalTemp);
if (!JS_InitStandardClasses(cx, globalTemp)) {
globalTemp = nullptr;
}

globalHandle = globalTemp;

global = globalTemp;
}

static bool
doit(JSContext *cx, unsigned argc, JS::Value *vp)
{
JS::CallArgs args = CallArgsFromVp(argc, vp);
JSString *temp = JS::ToString(cx, args[0]);
char* name = JS_EncodeString(cx, temp); //This value comes as undefined
}

int
testApp_init()
{
JS_Init();
cx = createContext();
if (cx == NULL)
return 0;
if (!JS::InitSelfHostedCode(cx))
return 0;
createGlobal(NULL);
if (!global)
return 0;

JSAutoRequest ar(cx);

JS::RootedValue rval(cx);
retval = rval;

JS_EnterCompartment(cx, global);

static JSFunctionSpec my_functions[] = {
JS_FN("doit", doit, 1, 0),
/* etc... */
JS_FS_END
};
bool ok = JS_DefineFunctions(cx, global, my_functions);
return 1;
}

Now when I call method "var testDo = doit("Testinggggg");" from my javascript, number of arguments in my C++ function doit reaches as 1 but value of the argument comes as undefined.
Any idea what I am doing wrong? Thanks in advance!

James Stortz

unread,
Apr 30, 2020, 10:26:01 PM4/30/20
to amande...@gmail.com, dev-tech-...@lists.mozilla.org
Just try 'args[0].toString()`

like so

char* name = JS_EncodeString(cx, args[0].toString());

also a good idea to check for argument type like so

if(args[0].isString()) {
char* name = JS_EncodeString(cx, args[0].toString());
}

full example like so

bool stdout_log(JSContext *cx, unsigned argc, JS::Value *vp) {

JS::CallArgs args = JS::CallArgsFromVp(argc, vp);

for(int i=0; i<args.length(); i++) {
if(args[i].isString()){

cout << JS_EncodeString(cx, args[i].toString()) <<endl;

}
}

args.rval().setNull();
return true;
};
> _______________________________________________
> dev-tech-js-engine mailing list
> dev-tech-...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-tech-js-engine
>

amande...@gmail.com

unread,
May 1, 2020, 12:03:33 AM5/1/20
to
Thanks James for your advice. I tried that but my argument does not pass isString check.Further diagnosis pointed to me that isNumber evaluation becomes true.So argument is coming as Number.This is even more crazier that passed argument is a String value.Although if I change number of arguments then count comes correct but data type is completely incorrect.Getting out of ideas here.

amande...@gmail.com

unread,
May 1, 2020, 12:05:03 AM5/1/20
to
James, I tried that but my argument does not pass isString check.Further diagnosis pointed to me that isNumber evaluation becomes true.So argument is coming as Number.This is even more crazier that passed argument is a String value.Although if I change number of arguments then count comes correct but data type is completely incorrect.Getting out of ideas here.

Kannan Vijayan

unread,
May 1, 2020, 12:45:06 AM5/1/20
to amande...@gmail.com, dev-tech-...@lists.mozilla.org
Hi,

I haven't run your code directly, but I noticed a couple of things that are
off here.

For one: You want to use JS::RootedString instead of a raw JSString* to
hold the string pointer. Also, I'm not sure where you're able to call a
plain JS_EncodeString, but I think you should be using
JS_EncodeStringToUTF8, and you also want to hold the result of the
JS_EncodeStringToUTF8 in a JS::UniqueChars instead of a raw char pointer.
Please consider this example from the shell code to use as a guide:

https://searchfox.org/mozilla-central/rev/7fd1c1c34923ece7ad8c822bee062dd0491d64dc/js/src/shell/js.cpp#2785

Hope that helps.
Kannan

amande...@gmail.com

unread,
May 1, 2020, 1:20:04 AM5/1/20
to
Kannan

I tried with RootedString as well.Also JS_EncodeStringToUTF8 does not allow(compile error) assignment to UniqueChars type but it did allow assignment to char * but in that case value still came as undefined. I am surprised how your example allow assignment . My compiler is clang.

JS::CallArgs args = CallArgsFromVp(argc, argv);
for(int i=0; i<args.length(); i++) {
JS::RootedString str(cx, JS::ToString(cx, args[i]));
if (!str) {
return false;
}
char *bytes = JS_EncodeStringToUTF8(cx, str);;
if (!bytes) {
return false;
}
print_error("DEBUG: doit value : %s\n",bytes); //Output -> DEBUG: doit value : undefined
}

James Stortz

unread,
May 1, 2020, 1:40:09 AM5/1/20
to amande...@gmail.com, dev-tech-...@lists.mozilla.org
It seems to me like JS_InitStandardClasses didn't make it's way into
your runtime scope. I'll share a working example for me. As far as I
can tell, the only difference is you are using EnterCompartment, after
outsourcing your global scope creation, whereas and I am using
AutoCompartment and InitStandardClasses right before defining the JS
function.

If InitStandardClasses isn't applied, that's the only reason I can
think of why something would return undefined but show the correct arg
count. Hope that helps. Try InitStandardClasses after entering the
compartment?


bool Init(runtime_t *rt) {

if (!(rt->cx = JS_NewContext(8L * 1024 * 1024)))
return 1;
if (!JS::InitSelfHostedCode(rt->cx))
return 1;

{
JSAutoRequest ar(rt->cx);

JS::CompartmentOptions options;
if(!(rt->gl = JS::PersistentRooted<JSObject*>
(rt->cx , JS_NewGlobalObject(rt->cx,
&global_class, nullptr,
JS::FireOnNewGlobalHook, options))
))
return 1;

{
JSAutoCompartment ac(rt->cx, rt->gl);
JS_InitStandardClasses(rt->cx,
rt->gl); //!!! <-- try this!

unsigned flags = JSPROP_READONLY |
JSPROP_PERMANENT;

if (!JS_DefineFunction(rt->cx, rt->gl,
"log", &stdout_log, 1, flags))
return 1;

//...

}
}
return 0;
};

amande...@gmail.com

unread,
May 1, 2020, 5:46:09 PM5/1/20
to
James

In Spidermonkey 52 , there is no way to create runtime.I think its take care inbuilt while creating context.
One more update is that If I pass double or integer value , then I am able to extract while if I Pass String It crashes when I try to convert to char* using method JS_EncodeString.

JSString *testStr = argv[0].toString();
char *proxy = JS_EncodeString(cx, testStr);//Crashes at this line where stack trace points to crash at #0 0x0000000100329361 in JSString::isLinear() const [inlined] at /Users/test/Documents/spidermonkey/mozjs-52.9.1pre1/js/src/vm/String.h:376

I checked testStr object is not null.
Reply all
Reply to author
Forward
0 new messages