Silent failure trying to call a Mac OS X routine using js-ctypes

RESOLVED WORKSFORME

Status

()

RESOLVED WORKSFORME
9 years ago
9 years ago

People

(Reporter: sheppy, Unassigned)

Tracking

Trunk
x86
Mac OS X
Points:
---

Firefox Tracking Flags

(Not tracked)

Details

Attachments

(1 attachment)

(Reporter)

Description

9 years ago
Created attachment 435979 [details]
Sample extension exhibiting the problem

I'm working on a demo of js-ctypes that calls a number of Mac OS X system framework routines to exercise its capabilities. A call to a ctypes-defined accessor for the Launch Services routine LSOpenURLsWithRole is failing silently, aborting my script.

When I try my extension in a debug build of Minefield, I get this error on the OS X console:

JavaScript error: chrome://add-to-iphoto/content/iphoto.js, line 252: expected type pointer, got ctypes.PointerType("CFMutableArrayRef")(ctypes.UInt64("0x1cea8380"))

The line in question is:

var status = AppServices.LSOpenURLsWithRole(array, 0, null, appParams.address(), null, 0);

The LSOpenURLsWithRole function is declared thusly:

    this.LSOpenURLsWithRole = this.lib.declare("LSOpenURLsWithRole",
                                ctypes.default_abi,                 // ABI type
                                OSStatus,                           // Returns OSStatus
                                CoreFoundation.CFArrayRef,          // Should be CoreFoundation.CFArrayRef
                                OptionBits,                         // Roles mask
                                ctypes.voidptr_t,                   // inAEParam
                                this.struct_LSApplicationParameters.ptr, // this.struct_LSApplicationParameters.ptr
                                ctypes.voidptr_t,                   // PSN array pointer
                                CFIndex);                           // max PSN count

CoreFoundation.CFArrayRef is declared as an opaque pointer type.

I've attached the extension for reference.

Comment 1

9 years ago
Sigh. I really need to fix ctypes error reporting to be more useful. (Bug 551057.)

This is... strange. The console error may be a strawman; it *could* be ExplicitConvert calling ImplicitConvert, which throws, and then ExplicitConvert clears the pending exception. Which could be happening earlier in the file. If you execute everything up to, but not including, the LSOpenURLsWithRole function, do you still see the console error? If not, strawman. (But still a bug.)

In which case, it must be one of our methods (or a JSAPI method) failing, but not throwing. Which would silently stop script. I'll have to get this in a debugger.
(Reporter)

Comment 2

9 years ago
The console error does not occur if I comment out the call to LSOpenURLsWithRole.

Let me know what if anything else I can do to help. I have a debug build of Firefox handy and can do quick builds with patches if need be to help track this down. Let me know if there are tweaks to my extension's code that might help as well.
(Reporter)

Comment 3

9 years ago
What I'm gathering here is there's an error reporting issue here, but the key problem is a bug in my own code I can't find. Any advice would be appreciated.
(Reporter)

Comment 4

9 years ago
Interestingly, if I change the declaration of LSOpenURLsWithRole to use ctypes.voidptr_t instead of CoreFoundation.CFArrayRef as the type of the first parameter, Firefox terminates with an assertion:

Assertion failure: fp && currentCallStack && !currentCallStack->isSuspended(), at /builds/slave/mozilla-central-macosx-debug/build/js/src/jscntxt.h:1441

I wouldn't think this should happen, since an opaque pointer is an opaque pointer.

Comment 5

9 years ago
Oh, duh.

JavaScript error: chrome://add-to-iphoto/content/iphoto.js, line 252: expected
type pointer, got
ctypes.PointerType("CFMutableArrayRef")(ctypes.UInt64("0x1cea8380"))

You're trying to pass a CFMutableArrayRef into a function that expects a CFArrayRef.

    this.CFArrayRef = new ctypes.PointerType("CFArrayRef");
    this.CFMutableArrayRef = new ctypes.PointerType("CFMutableArrayRef");

Those are totally different types, and ctypes will not allow you to implicitly convert (i.e. when supplying as a function argument) between them.

I think you want to rename 'array' to 'mutableArray', and then before your function call:

    let array = ctypes.cast(mutableArray, this.CFArrayRef);

That will fix it.

With regard to the error reporting, let's be clear: are you saying it didn't throw an exception? i.e. the Minefield error console doesn't report an "uncaught exception"? And you're not catching the exception yourself?
(Reporter)

Comment 6

9 years ago
Hm, okay, I'm used to being able to just pass CFMutableArrayRef anywhere that calls for CFArrayRef without having to cast anything, so I didn't think of this.

I see no "uncaught exception" notifications.
(Reporter)

Comment 7

9 years ago
After changing it to cast to CFArrayRef, like this:

var array = ctypes.cast(mutableArray, CoreFoundation.CFArrayRef);
var status = AppServices.LSOpenURLsWithRole(array, 0, null, appParams.address(), null, 0);

(with the corresponding changes above), I now get this in the OS X console, followed by an app termination. If I comment out the call to LSOpenURLsWithRole, no output occurs and the rest of the code executes without incident.

2010-03-30 16:36:23.728 firefox-bin[867:903] -[NSCFString scheme]: unrecognized selector sent to instance 0x297400a0
2010-03-30 16:36:23.729 firefox-bin[867:903] Mozilla has caught an Obj-C exception [NSInvalidArgumentException: -[NSCFString scheme]: unrecognized selector sent to instance 0x297400a0]
2010-03-30 16:36:23.730 firefox-bin[867:903] Generating stack trace for Obj-C exception...
Assertion failure: fp && currentCallStack && !currentCallStack->isSuspended(), at /builds/slave/mozilla-central-macosx-debug/build/js/src/jscntxt.h:1441
(In reply to comment #5)
> You're trying to pass a CFMutableArrayRef into a function that expects a
> CFArrayRef.
typedef struct __CFArray *CFMutableArrayRef;
typedef const struct __CFArray *CFArrayRef;

Can CTypes not figure that they are really the same type out?

Comment 9

9 years ago
(In reply to comment #7)
> (with the corresponding changes above), I now get this in the OS X console,
> followed by an app termination. If I comment out the call to
> LSOpenURLsWithRole, no output occurs and the rest of the code executes without
> incident.

OK. That means something is semantically wrong with the input you're giving to the function. Not much I can help with there, other than suggesting that you dump the contents of your inputs, and check that it agrees with what the function expects. :(

> Assertion failure: fp && currentCallStack && !currentCallStack->isSuspended(),
> at /builds/slave/mozilla-central-macosx-debug/build/js/src/jscntxt.h:1441

Once the native function explodes, it's game over, and this is probably a side effect of that.

(In reply to comment #6)
> Hm, okay, I'm used to being able to just pass CFMutableArrayRef anywhere that
> calls for CFArrayRef without having to cast anything, so I didn't think of
> this.

From CFArray.h:

/*!
	@typedef CFArrayRef
	This is the type of a reference to immutable CFArrays.
*/
typedef const struct __CFArray * CFArrayRef;

/*!
	@typedef CFMutableArrayRef
	This is the type of a reference to mutable CFArrays.
*/
typedef struct __CFArray * CFMutableArrayRef;

So CFArrayRef is really just a const version of CFMutableArrayRef, and the compiler will implicitly cast from mutable -> nonmutable for you. Unfortunately ctypes has no concept of 'const' yet, so you either cast yourself, or you declare 'this.CFArrayRef == this.CFMutableArrayRef' to get around it. The cast is ugly, but will help prevent mistakes.

(In reply to comment #8)
> typedef struct __CFArray *CFMutableArrayRef;
> typedef const struct __CFArray *CFArrayRef;
> 
> Can CTypes not figure that they are really the same type out?

Of course not. They're declared as different opaque types in the js file.

Comment 10

9 years ago
OK. I've been trying to test this out, but I've run into so many bugs on OSX Minefield trying to do it that it's getting ridiculous.

The big one is that when I install the extension, I get a dialog box that's half off the screen, which I can't move, seemingly saying there's a missing script or something. An OK button is visible, but clicking it doesn't do anything. I have to kill the app.

Any suggestions? :)
(Reporter)

Comment 11

9 years ago
Not sure where that's coming from... weird.

Comment 12

9 years ago
OK, got the test running under xpcshell. (xpcshell was busted on trunk for a bit.)

Wrapping the LSOpenURLsWithRole call in a try/catch shows me that it throws, with the error you were seeing; without the try/catch, the xpcshell test fails due to the exception bubbling up.

So, no ctypes bug here -- there might be something else catching your exception and dropping it on the floor, but it's not us. :)
Status: NEW → RESOLVED
Last Resolved: 9 years ago
Resolution: --- → WORKSFORME
You need to log in before you can comment on or make changes to this bug.