Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

js-ctype callback throwing unhandled exception

256 views
Skip to first unread message

gigasof...@gmail.com

unread,
May 16, 2013, 1:48:23 PM5/16/13
to
Hi All,

I have run into a problem with a js-ctypes callback. I am currently on windows, but this will also have to support the mac.

I am calling a a function with the JavaScript callback as a parameter. If I call the callback immediately within the exported function the JavaScript executes without issue. However if I save the callback as a member variable in a class to be called asynchronously at a later time, the DLL throws and unhandled exception at

> mozjs.dll!00d490f3()

I am thinking that somehow the callback is no longer valid?

The JavaScript functionality is all global so-to-speak.

I am defining my javascript callback as:

var funcType = ctypes.FunctionType(
ctypes.stdcall_abi,
ctypes.void_t,
[ctypes.jschar.ptr,
ctypes.int32_t,
ctypes.bool]);

Is there something I am missing in my C++ library? Do I have to perform some sort of special memory allocation?

Any help would be greatly appreciated.

Thanks,
Tom

Benjamin Smedberg

unread,
May 16, 2013, 2:04:38 PM5/16/13
to gigasof...@gmail.com, dev-ext...@lists.mozilla.org
On 5/16/2013 1:48 PM, gigasof...@gmail.com wrote:
> Hi All,
>
> I have run into a problem with a js-ctypes callback. I am currently on windows, but this will also have to support the mac.
>
> I am calling a a function with the JavaScript callback as a parameter. If I call the callback immediately within the exported function the JavaScript executes without issue. However if I save the callback as a member variable in a class to be called asynchronously at a later time, the DLL throws and unhandled exception at
>
>> mozjs.dll!00d490f3()
> I am thinking that somehow the callback is no longer valid?
Correct. What's happening is that the javascript function which you
passed as a callback only lives as long as some JS object references it.
So this pattern is always a GC hazard:

myCFunction(function(arg) {
...
});

Instead, you should do something like this:

var gCallback; // global

gCallback = function(arg) { // gCallback holds "myCallback" alive until
the C function is done with it
gCallback = null;
};
myCFunction(gCallback);

--BDS

gigasof...@gmail.com

unread,
May 16, 2013, 3:34:36 PM5/16/13
to
I am not sure I understand.

I have defined the JavaScript function as global. I have also tried defining the C++ callback variable as global.

No matter what I do, the exception is thrown if I call the callback sometime after the exported function returns.

I must be missing something. What I have going on is...

typedef void (__stdcall *ASYNCCALLBACK )(const wchar_t*, int, bool);
ASYNCCALLBACK g_callback;

__declspec(dllexport)MyExportedCFunc(callback)
{
g_callback = callback;
}

void AThread()
{
.
.
.
// Max smoke...minimum efficiency...kaboom
g_callback("blah", 1, true);
}

I read on the web that somebody had what seems to be a very similar issue

https://forums.mozilla.org/addons/viewtopic.php?t=7901&p=19729



Benjamin Smedberg

unread,
May 17, 2013, 10:08:59 AM5/17/13
to gigasof...@gmail.com, dev-ext...@lists.mozilla.org
On 5/16/2013 3:34 PM, gigasof...@gmail.com wrote:
> I am not sure I understand.
>
> I have defined the JavaScript function as global. I have also tried defining the C++ callback variable as global.
Could you post your JS code? I have a thought about what's actually
going wrong, and I suspect that we're auto-converting a JS function into
a ctypes function pointer. But without reading the code, I can't be sure
of my hunch and don't want to make any other guesses!

--BDS

gigasof...@gmail.com

unread,
May 17, 2013, 10:14:12 AM5/17/13
to
Sure ...give me an hour. I have to strip out some of our proprietary code and give you something to experiment with.

gigasof...@gmail.com

unread,
May 17, 2013, 11:16:39 AM5/17/13
to
Hi,
here is the js code. If you want me to produce an XPI with the actual dll...just let me know. I could send it to you as an email


is.onAsyncCall = function ()
{
try
{
is.component.asyncHttpReq();

}
catch(e)
{
is.IS_Log(' asyncHttpReq; ' + e + ' Error line: ' + e.lineNumber);
}
}

var tmp = null;
var theCallback= null;
var asyncHttpReq1 = null;
var funcType = ctypes.FunctionType(
ctypes.stdcall_abi,
ctypes.void_t,
[ctypes.jschar.ptr,
ctypes.int32_t,
ctypes.bool]);
var funcPtrType = funcType.ptr;


is.component = {
is_lib: null,
asyncHttpReq: null,
callback: null,
done: false,
unload: function()
{
try
{
if(this.is_lib)
{
this.is_lib.close();
}
}
catch(e)
{
is.IS_Log(' component unload; ' + e + ' Error line: ' + e.lineNumber);
}

},
load : function()
{
try
{

var fp = Components.classes["@mozilla.org/file/directory_service;1"]
.createInstance(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);

fp.append("extensions");
fp.append(is.EXTENSION_ID);
fp.append("components");
fp.append("is.dll");
is.component.is_lib = ctypes.open(fp.path);
is.component.done = true;

}
catch(e)
{
is.IS_Log(' component load; ' + e + ' Error line: ' + e.lineNumber);
alert(' component load; ' + e + ' Error line: ' + e.lineNumber)
}
},
asyncHttpReq: function()
{
try
{


//tmp = this.asyncCallback;
tmp = another_asyncCallback;
theCallback = funcPtrType(tmp);


//this.asyncHttpReq = this.is_lib.declare("asyncHttpRequest",
asyncHttpReq1 = this.is_lib.declare("asyncHttpRequest",
ctypes.winapi_abi,
ctypes.void_t,
ctypes.jschar.ptr,
ctypes.jschar.ptr,
ctypes.jschar.ptr,
ctypes.jschar.ptr,
funcPtrType
);


asyncHttpReq1('get', 'https://www.google.com/', null, 'Accept: */*', theCallback);


}
catch(e)
{
is.IS_Log(e + ' Error line: ' + e.lineNumber);
}
},
asyncCallback: function(data, res, success)
{
alert('received');
alert(data.readString());
//alert('Success = ' + success + "\ncurl http ret = " + res + "\n response = " + data.readString());
}


}

function another_asyncCallback(data, res, success)
{
alert('testing...')
alert(data.readString());
}

Neil

unread,
May 17, 2013, 12:06:43 PM5/17/13
to
gigasof...@gmail.com wrote:

>void AThread()
>{
>.
>.
>.
>// Max smoke...minimum efficiency...kaboom
>g_callback("blah", 1, true);
>}
>
>
Are you trying to callback on a different thread? That won't work.

--
Warning: May contain traces of nuts.

gigasof...@gmail.com

unread,
May 17, 2013, 12:22:34 PM5/17/13
to
It is a boost thread.

So I have to callback to the original thread to call the Javascript function?

So there is no way to fire and event back to JavaScript from a worker thread?

Benjamin Smedberg

unread,
May 17, 2013, 1:05:20 PM5/17/13
to gigasof...@gmail.com, dev-ext...@lists.mozilla.org
On 5/17/2013 12:22 PM, gigasof...@gmail.com wrote:
>
> So I have to callback to the original thread to call the Javascript function?
Yes. Our JS impl is not multithreaded.

>
> So there is no way to fire and event back to JavaScript from a worker thread?
No. However, you can use ctypes from a DOM worker thread and just make
it a blocking call...

--BDS

gigasof...@gmail.com

unread,
May 17, 2013, 1:12:53 PM5/17/13
to
Thanks for your help.

I totally miss C++ XPCOM.
Message has been deleted

kilche...@gmail.com

unread,
Jul 22, 2013, 1:37:51 AM7/22/13
to
2013년 5월 17일 금요일 오전 2시 48분 23초 UTC+9, gigasof...@gmail.com 님의 말:
Hi, Tom

Now, I am investigating how to use native library on B2G(FirefoxOS).
Unfortunately, I have a same problem about js-ctypes callback.
Did you find any solution to use js-ctypes callback?
If yes, please let me know how to fix it.
Thanks.

Kilcheon.

Noit

unread,
Feb 19, 2015, 12:27:34 PM2/19/15
to
did you get this fixed? the solution is easy. i hit this same issue. i fixed by defining the var globally: https://gist.github.com/Noitidart/e8105a5f702dc9e6a4b8

Noit

unread,
Feb 19, 2015, 12:28:10 PM2/19/15
to
yes found solution, was very simple make the var global, as done here: https://gist.github.com/Noitidart/e8105a5f702dc9e6a4b8
0 new messages