why does this ATL/COM code check for successful alloc? I would have expected a custom allocation to be visible through CoGetALloc or some such api. A standards-conforming C++ runtime should be throwing std::bad_alloc, but then again maybe the allocator has indeed been traded out for a non-throwing impl.
DDClientData* pNewData = new DDClientData();
if (pNewData==NULL)
return E_OUTOFMEMORY;
COM methods are not allowed to let exceptions out - the implementation can throw exceptions, but it must handle them before they escape the method and translate to an appropriate HRESULT.
The code above will not have desired effect - once new fails std::bad_alloc is thrown and the check for a null pointer is not executed. The implementation has to either wrap the new call into try-catch or wrap the whole method implementation into try-catch. ATL usually uses _ATLTRY-like macros around the new call.
COM doesn't use exceptions: any COM object is supposed to return a valid HRESULT on failure. Plus there are guarantees about setting return values on exit, which any conforming COM object has to comply with. For these reasons, exceptions play badly with COM/ATL, and aren't used at all internally at Microsoft[1], not even for allocations. The code sample shown above simply reflects that convention.
[1] Sez me, an MS FTE. COM components at MS are compiled with C++ exceptions disabled.
Related
I have a really big project that I can not easily strip down.
When the application is being closed, I get the error
"InvalidComObjectException: A COM object that has been disconnected from the RCW can not be used."
Details:
System.Runtime.InteropServices.InvalidComObjectException has occured.
HResult=-2146233049
Message=A COM object that has been disconnected from its RCW can not be used.
Source=mscorlib
StackTrace:
at System.StubHelpers.StubHelpers.StubRegisterRCW(Object pThis)
InnerException:
Unfortunately I can not see what COM object this is about.
Does anybody know how I can find that out? Unfortunately I can't read ASM to analyze the disassembly.
There are some steps you could try and since you haven't posted any code I will try to enumerate some of the most common key factors...
First, there is no order when disposing objects. If a close/dispose/finalize action is invoked, object C might be disposed before object A and if some object is still alive it might try to access an already disposed object.
Second, beware of events. It's very common to get errors about accessing a disposed object originated from an event call.
Third, do not dispose objects inside an event scope nor destructors. Create your own method to free your object(s).
Since you don't know which COM object is the culprit, I suggest you look for the ones that you do close, dispose, disconnect, etc...
You might want to read this blog in order to better understand how RCW's work and also to help you with your problem.
Edit:
After reading your comment, I felt I should add two possible causes:
If after removing Microsoft.VisualBasic runtime methods you've solved your problem, then I suspect that inside one, or more, of those methods you have incremented the count of a reference to one, or more, of your COM(s) and did not release properly.
Be sure to ReleaseComObject checking the reference count until it's 0 and then set it to nothing(VB) or null(C#) and let the Garbage Collector do the rest.
The other option is that one of those methods tried to access an already disposed reference to a COM object, resulting in a RCW error, since is no longer callable.
As a final comment, after releasing the COM object always set it to nothing or null, this will release the reference to the variable and you can always check it's availability anywhere in the code.
In Apple's Concurrency Programming Guide the NSOperation subclass examples (both non-concurrent and concurrent varieties) use exception handling and I'm wondering why they are encouraging this style within operations.
Listing 2-4 Responding to a cancellation request
- (void)main {
#try {
BOOL isDone = NO;
while (![self isCancelled] && !isDone) {
// Do some work and set isDone to YES when finished
}
}
#catch(...) {
// Do not rethrow exceptions.
}
}
My understanding is that generally exception handling is not a common practice in Objective-C code - exceptions are essentially programmer errors and should cause the app to crash whereas unexpected inputs are best handled by NSError. (My possibly misinformed understanding comes from things like this and this)
I'm wondering if NSOperations present a particular situation in which exception handling is important, or if this is more the preferred style of the particular author of that guide.
As a side note, some of the NSOperation example code follows this style, other examples do not. Most high-visibility OSS does not use exceptions (AFNetworking, for example).
Your understanding is correct - NSError (or similar) should be used to convey error information, rather than exceptions. Most Objective-C code is not exception-safe and will at the very least leak resources. As a general rule, never let your code leak an exception into anyone else's code - whether Apple's or a 3rd parties. Some 3rd party frameworks may explicitly indicate they are exception safe, but it's rare.
By that principle you can see why you should have a catch-all exception handler in your main method regardless. But there's actually another reason: your operation will be run on a dedicated thread. Exceptions thrown from your operation will propagate up the stack, but no further. The logical caller or owner of the operation won't get them, as they're running on a different thread (or not at all). So leaked exceptions will either kill your whole program, or be swallowed silently with no other indication. Your program may then get stuck in a weird state - since you didn't realise an error occurred, you may continue waiting for the result of your operation that will never arrive.
Additionally, Apple has a section in the Concurrency Programming Guide where they talk about Handling Errors and Exceptions. Their first point on "discrete entities" is alluding to what I said in the previous paragraph:
Handling Errors and Exceptions
Because operations are essentially
discrete entities inside your application, they are responsible for
handling any errors or exceptions that arise. In OS X v10.6 and later,
the default start method provided by the NSOperation class does not
catch exceptions. (In OS X v10.5, the start method does catch and
suppress exceptions.) Your own code should always catch and suppress
exceptions directly. It should also check error codes and notify the
appropriate parts of your application as needed. And if you replace
the start method, you must similarly catch any exceptions in your
custom implementation to prevent them from leaving the scope of the
underlying thread.
Among the types of error situations you should be prepared to handle
are the following:
Check and handle UNIX errno-style error codes.
Check explicit error
codes returned by methods and functions.
Catch exceptions thrown by
your own code or by other system frameworks.
Catch exceptions thrown
by the NSOperation class itself, which throws exceptions in the
following situations:
When the operation is not ready to execute but
its start method is called
When the operation is executing or finished
(possibly because it was canceled) and its start method is called
again
When you try to add a completion block to an operation that is
already executing or finished
When you try to retrieve the result of
an NSInvocationOperation object that was canceled
If your custom code
does encounter an exception or error, you should take whatever steps
are needed to propagate that error to the rest of your application.
The NSOperation class does not provide explicit methods for passing
along error result codes or exceptions to other parts of your
application. Therefore, if such information is important to your
application, you must provide the necessary code.
I think this post and the accompanying answer elaborates very well on the general exception- vs. no exception handling topic!
It is unsafe to throw exceptions in circumstances where resources are
not automatically managed. This is the case of the Cocoa framework
(and neighbor frameworks), as they use manual reference counting.
If you throw an exception, any release call you skip over by unwinding
the stack will result in a leak. This should limit you tothrowing only
if you're certain that you're not going to recover since all resources
are returned to the OS when a process quits.
Unfortunately, NSRunLoops tend to catch all exceptions that propagate
to them, so if you throw during an event, you'll resume to the next
event. This is, obviously, very bad. Therefore, it's better that you
simply don't throw.
This problem is diminished if you use garbage-collected Objective-C,
as any resource represented by an Objective-C object will be properly
released. However, C resources (such as file descriptors or
malloc-allocated memory) that are not wrapped in an Objective-C object
will still leak.
So, all in all, don't throw.
The Cocoa API has several workarounds to this, as you mentioned.
Returning nil and the NSError** pattern are two of them.
The scenario is pretty straighforward, I've embedded mono runtime 2.10.8 in my app, and I'm calling the managed methods via pointers obtained by: mono_method_get_unmanaged_thunk:
// obtain pointer
bool (__stdcall*foo) (MonoException**);
foo = mono_method_get_unmanaged_thunk(somemethod);
// call it
MonoException* exc;
foo(&exc);
if(exc)
// handle exception
// nothing else...
What puzzles me, that I'm doing nothing else with the MonoException pointer (documentation I've read doesn't say anything about this). Is it removal handled by the managed runtime? If so, how it can be sure that my native side is not holding a pointer to it?
Edit
I've read through the sources and found out that exceptions are just pointers to objects created with mono_object_new, so they are subject of the garbage collection.
Now, I've also read that if I want to keep some pointer on native side and prevent it from being garbaged I need to obtain GC handle for it. So the (modified) question now is:
If the point of returned pointer to exception object is only to serve as error reporting facility, and such error reporting is made right after the managed call, is it safe to assume it won't get garbaged before I handle it (without using gc handle)?
To quote the page you linked:
Note that this registration is not necessary for LOCAL variables, as they are stored on the stack. It is only necessary for global variables, as they are not a part of the GC's root set.
So that means in your scenario you don't have to allocate a handle.
I'm new to Objective-C world. What I have noticed while studying some iOS/Mac apps is that try -catch is rarely used, if used at all.
For example in Java it is used almost all the time.
Why isn't it so common in Objective-C ?
Exceptions in Objective-C are generally to be used for truly exceptional circumstances and almost always programmer error. To convey a recoverable error use the NSError** pattern.
There are a lot of SDK methods that take an NSError** parameter and return BOOL. To indicate an error they return false and feed an error back through the error parameter to communicate info.
Exceptions are used, but generally for cases in which there is some failure at the runtime level - e.g. some object can't handle a selector. Although it may seem contrary to what I just wrote, exceptions tend to indicate an error in design rather than a runtime error.
The NSError** idiom is all you need for things such as failed URL connections, data conversions, etc, where an error condition exists but a program really shouldn't be killed outright.
Start reading: Error Handling Programming Guide
i am working on an application which calls the COM component of a partner's application. Ours is .Net, theirs isn't. I don't know much about COM; I know that the component we're calling is late-bound i.e.
obj As Object = CreateObject("THIRDPARTY.ThirdPartyObject")
We then call a method on this COM object (Option Strict Off in the head of the VB file):
obj.AMethod(ByVal Arg1 As Integer, ByVal Arg2 As Integer, ByVal Arg3 as Boolean)
I am a bit nonplussed that even though this call works, this overload doesn't exist in the COM interop .dll that is created if I instead add a reference to the COM server using Add Reference. The only available call to this method that it says is available is AMethod().
However, this in itself is not what bothers me. What bothers me is that this call works for a while, THEN throws a TargetParameterCountException after a few dozen calls have executed successfully.
I ask thee thus, StackOverflow:
What. The. Hell.
The only thing I can guess at is that the documentation for the COM component states that this method is executed synchronously - so therefore maybe whatever's responsible for throwing that exception is being blocked until some indeterminate point in time? Other than that, I'm completely stumped at this bizarre, and more importantly inconsistent behaviour.
edit #1:
More significant information that I've just remembered - from time to time the call throws an ExecutionEngineException instead. It only took one glance at the documentation to realise that this is VERY BAD. Doing a little bit of digging suggests to me that the late-binding call is causing stack corruption, crashing the entire CLR. Presumably this means that the runtime is shooting down bad calls (with TargetParameterCountException) some of the time and missing them (ExecutionEngineException) others.
edit #2:
Answering David Lively's questions:
The call with zero arguments that's currently in the code has been there for a long time. I haven't been able to get hold of a manual for the third party's COM implementation past two major revisions ago, so it's possible that they've withdrawn that signature from service
There is only one location that this method is called from
This is one desktop app calling another, on the same machine. Nothing fancy
The object is persisted throughout the scope of the user's interaction with the application, so there's never a new one created.
Unfortunately, it seems likely that there is indeed a bug in the implementation, as you suggest. The trouble with this vendor is that, when we report a bug, their response tends to follow the general form: i) deny there's a problem; ii) deny it's their problem; iii) refuse to fix it. These three steps tend to span a frustratingly long period of time.
No, it can't cause stack corruption. IDispatch::Invoke() is used to call the method, the arguments are packaged in an array. The stock implementation of IDispatch certainly would detect the argument mismatch, it uses the type library info to check. But it is conceivable that the COM server author implemented it himself. Imperfectly. It is something a C++ hacker might do, the stock implementation is dreadfully slow. The GC heap getting corrupted is the kind of thing that happens when imperfect code executes.
I haven't played with calling COM objects from VB in quite a while, but I'll take a wild guess:
I would expect an exception to be thrown if you're calling the object with too few or too many arguments, but it appears that's not the case. What is the real signature of the method you're calling?
In some languages and some situations, when you call a method, arguments are placed on the stack. If you place too many arguments, it's possible for the extraneous ones to remain on the stack after the method completes. This should cause lots of other problems, though.
Some possibilities/considerations:
The object is throwing this exception internally. This should be taken up with the author.
You're calling with too many parameters. If, as you said, the overload you're trying to call isn't published in the object's type library, you may actually be calling a different published method with a different signature. I'd REALLY expect a compiler error if this is the case.
Are your later calls taking place in the same part of your code, or is there a different execution branch that might be doing things a bit differently, and causing the error?
Are you running this from a desktop app/script, or a website? If a website, are you receiving a valid, expected response, or does the request hang as if an internal long-running process doesn't complete?
The object may be allocating and not releasing resources, which could cause undefined behavior when those resources are exhausted.
Are you releasing the object between calls, or is it recreated every time?
Also, re: your comments about late binding: the .CreateObject() method of instantiating a COM object is the normal, accepted way to do this. That shouldn't have anything to do with the issue. Based on the exceptions you listed, I'm strongly inclined to believe that there is an internal issue with the object.
Good luck.
OK, basically - false alarm. I've done it wrong - I've copied some code over from somewhere improperly and the thing I'm calling was never supposed to support that overload. What I find interesting is that the component didn't reject that late-bound call out of hand, but did everything it was supposed to do, at least initially.