Error 0x800706F7 "The stub received bad data" on Windows XP SP3 - com

In my VB6 application I make several calls to a COM server my team created from a Ada project (using GNATCOM). There are basically 2 methods available on the COM server. Their prototypes in VB are:
Sub PutParam(Param As Parameter_Type, Value)
Function GetParam(Param As Parameter_Type)
where Parameter_Type is an enumerated type which distinguishes the many parameters I can put to/get from the COM server and 'Value' is a Variant type variable. PutParam() receives a variant and GetParam() returns a variant. (I don't really know why in the VB6 Object Browser there's no reference to the Variant type on the COM server interface...).
The product of this project has been used continuously this way for years without any problems in this interface on computers with Windows XP with SP2. On computers with WinXP SP3 we get the error 0x800706F7 "The stub received bad data" when trying to put parameters with the 'Long' type.
Does anybody have any clue on what could be causing this? The COM server is still being built in a system with SP2. Should make any difference building it on a system with SP3? (like when we build for X64 in X64 systems).
One of the calls that are causing the problem is the following (changed some var names):
Dim StructData As StructData_Type
StructData.FirstLong = 1234567
StructData.SecondLong = 8901234
StructData.Status = True
ComServer.PutParam(StructDataParamType, StructData)
Where the definition of StructData_Type is:
Type StructData_Type
FirstLong As Long
SecondLong As Long
Status As Boolean
End Type
(the following has been added after the question was first posted)
The definition of the primitive calls on the interface of the COM server in IDL are presented below:
// Service to receive data
HRESULT PutParam([in] Parameter_Type Param, [in] VARIANT *Value);
//Service to send requested data
HRESULT GetParam([in] Parameter_Type Param, [out, retval] VARIANT *Value);
The definition of the structure I'm trying to pass is:
struct StructData_Type
{
int FirstLong;
int SecondLong;
VARIANT_BOOL Status;
} StructData_Type;
I found it strange that this definition here is using 'int' as the type of FirstLong and SeconLong and when I check the VB6 object explorer they are typed 'Long'. Btw, when I do extract the IDL from the COM server (using a specific utility) those parameters are defined as Long.
Update:
I have tested the same code with a version of my COM server compiled for Windows 7 (different version of GNAT, same GNATCOM version) and it works! I don't really know what happened here. I'll keep trying to identify the problem on WinXP SP3 but It is good to know that it works on Win7. If you have a similar problem it may be good to try to migrate to Win7.

I'll focus on explaining what the error means, there are too few hints in the question to provide a simple answer.
A "stub" is used in COM when you make calls across an execution boundary. It wasn't stated explicitly in the question but your Ada program is probably an EXE and implements an out-of-process COM server. Crossing the boundary between processes in Windows is difficult due to their strong isolation. This is done in Windows by RPC, Remote Procedure Call, a protocol for making calls across such boundaries, a network being the typical case.
To make an RPC call, the arguments of a function must be serialized into a network packet. COM doesn't know how to do this because it doesn't know enough about the actual arguments to a function, it needs the help of a proxy. A piece of code that does know what the argument types are. On the receiving end is a very similar piece of code that does the exact opposite of what the proxy does. It deserializes the arguments and makes the internal call. This is the stub.
One way this can fail is when the stub receives a network packet and it contains more or less data than required for the function argument values. Clearly it won't know what to do with that packet, there is no sensible way to turn that into a StructData_Type value, and it will fail with "The stub received bad data" error.
So the very first explanation for this error to consider is a DLL Hell problem. A mismatch between the proxy and the stub. If this app has been stable for a long time then this is not a happy explanation.
There's another aspect about your code snippet that is likely to induce this problem. Structures are very troublesome beasts in software, their members are aligned to their natural storage boundary and the alignment rules are subject to interpretation by the respective compilers. This can certainly be the case for the structure you quoted. It needs 10 bytes to store the fields, 4 + 4 + 2 and they align naturally. But the structure is actually 12 bytes long. Two bytes are padded at the end to ensure that the ints still align when the structure is stored in an array. It also makes COM's job very difficult, since COM hides implementation detail and structure alignment is a massive detail. It needs help to copy a structure, the job of the IRecordInfo interface. The stub will also fail when it cannot find an implementation of that interface.
I'll talk a bit about the proxy, stub and IRecordInfo. There are two basic ways a proxy/stub pair are generated. One way is by describing the interfaces in a language called IDL, Interface Description Language, and compile that with MIDL. That compiler is capable of auto-generating the proxy/stub code, since it knows the function argument types. You'll get a DLL that needs to be registered on both the client and the server. Your server might be using that, I don't know.
The second way is what VB6 uses, it takes advantage of a universal proxy that's built into Windows. Called FactoryBuffer, its CLSID is {00000320-0000-0000-C000-000000000046}. It works by using a type library. A type library is a machine readable description of the functions in a COM server, good enough for FactoryBuffer to figure out how to serialize the function arguments. This type library is also the one that provides the info that IRecordInfo needs to figure out how the members of a structure are aligned. I don't know how it is done on the server side, never heard of GNATCOM before.
So a strong explanation for this problem is that you are having a problem with the type library. Especially tricky in VB6 because you cannot directly control the guids that it uses. It likes to generate new ones when you make trivial changes, the only way to avoid it is by selecting the binary compatibility option. Which uses an old copy of the type library and tries to keep the new one as compatible as possible. If you don't have that option turned on then do expect trouble, especially for the guid of the structure. Kaboom if it changed and the other end is still using the old guid.
Just some hints on where to start looking. Do not assume it is a problem caused by SP3, this COM infrastructure hasn't changed for a very long time. But certainly expect this kind of problem due to a new operating system version being installed and having to re-register everything. SysInternals' ProcMon is a good utility to see the programs use the registry to find the proxy, stub and type library. And you'd certainly get help from a COM Spy kind of utility, albeit that they are very hard to find these days.

If it suddenly stopped working happily on XP, the first culprit I'd look for is type mismatches. It is possible that "long" on such systems is now 64-bits, while your Ada COM code (and/or perhaps your C ints) are exepecting 32-bits. With a traditionally-compiled system this would have been checked for you by your compiler, but the extra indirection you have with COM makes that difficult.
The bit you wrote in there about "when we compile for 64-bit systems" makes me particularly leery. 64-bit compiles may change the size of many C types, you know.

This Related Post suggests you need padding in your struct, as marshalling code may expect more data than you actually send (which is a bug, of course). Your struct contains 9 bytes (assuming 4 bytes for each of the ints/longs and one for the boolean). Try to add padding so that your struct contains a multiple of 4 bytes (or, failing that, multiple of 8, as the post isn't clear on the expected size)

I am also suggesting that the problem is due to a padding issue in your structure. I don't know whether you can control this using a #pragma, but it might be worth looking at your documentation.
I think it would be a good idea to try and patch your struct so that the resulting type library struct is a multiple of four (or eight). Your Status member takes up 2 bytes, so maybe you should insert a dummy value of the same type either before or after Status - which should bring it up to 12 bytes (if packing to eight bytes, this would have to be three dummy variables).

Related

Does the ABI persist any more error information than an HRESULT?

While porting a regular C++ class to a Windows Runtime class, I hit a fairly significant road block. My C++ class reports certain error conditions by throwing custom error objects. This allows clients to conveniently filter on exceptions, documented in the public interface.
I cannot seem to find a reliable way to pass enough information across the ABI to replicate the same fidelity1 using the Windows Runtime. Under the assumption, that an HRESULT is the only generalized error reporting information, I have evaluated the following options:
The 'obvious' choice: Map the exception condition to any of the predefined HRESULT values. While this technically works (presumably), there is no way at the call site to distinguish between errors originating from the implementation, and errors originating from callees of the implementation.
Invent custom HRESULTs. If this layout still applies to the Windows Runtime, I could easily set the Customer bit and go crazy with my 27 bits worth of error code representation. This works, until someone else does the same. I'm not aware of any way to attribute an HRESULT to an interface, which would solve this ambiguity.
Even if either of the above could be made to work as intended, throwing hresult_errors as prescribed, the call site would still be at the mercy of the language projection. While C# seemingly allows to pass any System.Exception(-derived) error object across the ABI, and have them re-thrown at the call site, C++/WinRT only supports some 14 distinct exception types (see throw_hresult).
With neither of these options allowing for sufficiently complete error information to cross the ABI, it seems that an HRESULT simply may not be enough. Does the Windows Runtime have any provisioning to allow for additional (arbitrary) error information to cross the ABI?
1 I'm not strictly interested in passing actual C++ exceptions across. Instead, I'm looking for a way to allow clients to uniquely identify documented error conditions, in a natural way. Passing custom Windows Runtime error types would be fine.
There are a few options here. Our general API guidance for Windows Runtime APIs that have well-defined, expected failure modes is that failure information should be part of the normal parameters and return value. We would normally create a TryDoSomething API in this situation and provide extended error information via either a return or out parameter. This works best for us due to the fact that there's no consistent way to map exceptions across all languages. This is a topic we hope to revisit more in xlang in the future.
HRESULTs are usable with a caveat. HRESULT values can be a nuisance in anything but C++, where you need to redefine them locally because you can't just use the header. They will generate exceptions in most languages, so if this is common, you'll be creating debugger noise for your components' clients.
The last option allows you to transit a language-specific exception stored in a COM object across the ABI boundary (and up the COM logical stack, including across marshalled calls). In practice it will only be usable by C++ code compiled with the same compiler, settings, and type definitions as the component itself. E.g. passing it from a component compiled with VC to a component compiled with Clang could potentially lead to memory corruption.
Assuming I haven't scared you off, you'll want to look at RoOriginateLanguageException. It allows you to wrap the exception in a COM object and store it with other winrt error data in the TLS. We use this in projections to enable exceptions thrown within a callback to propagate to the outer code using the same projection in a controlled way that unwinds safely through other code potentially written using other languages or tools. This is how the support in C# and other languages is implemented.
Thanks,
Ben

C++ Interop: embedding an array in a UDT

I have an application that involves a lot of communication between managed (C#) and unmanaged (C++) code. We are using Visual Studio 2005 (!), and we use the interop assembly generated automatically by tlbimp.
We have fairly good luck passing simple structs back and forth as function arguments. And because our objects are fairly simple, we can pack them into SAFEARRAYs using the IRecordInfo interface. Passing these arrays as arguments to COM methods seems to work properly.
We would like to be able to embed variable-length arrays in our UDTs, but this fails badly. I don't think I have been able to find a single piece of documentation showing how someone has accomplished this. Nor have I found documentation that says it can't be done.
1) Naive approach: Simply declare a safearray in the managed code:
struct MyUdt {
int member1;
BSTR member2;
SAFEARRAY *m3;
};
The C++ compiler is happy with this, but the generated IDL confounds tblimp.exe. It reports that it is unable to convert the signature for member m3, and the signature for member tagSAFEARRAY.rgsabound. These are only warnings, but they are meaningful, the resulting assembly is not usable.
Using LPSAFEARRAY, oddly enough, fails in different ways, but for the same reason, tblimp just can't deal with it.
2) Trickier: Pack it into a variant:
struct MyUdt {
int member1;
BSTR member2;
VARIANT m3;
};
We have code that builds safearrays of UDTs, and it never gives us any trouble. It's basically copied from MSDN. Using that code to create a safearray, then:
pVal->m3.vt = VT_SAFEARRAY | VT_RECORD;
pval->parray = p;
Fails in odd ways. It always breaks, some variations produce an OutOFMemoryException... odd, others fail in different ways. (I'm not sure if a pRecInfo pointer is required here or not, but it fails the same way, present or not.)
The Google search space for this is badly polluted with answers to questions that I am not asking:
How do you pass UDT/structs from unmanaged code.
How do you pass a SAFEARRAY of structs? (We're doing this fine.)
How do you use p/invoke or customer marshalling to pass UDTs.
And many answers describing how to define things from the managed side, not the unmanaged side.
And then there are a couple of Microsoft KBs describing problems with VT_RECORD in early versions of .NET. I don't think these are germane - VT_RECORD types work with VARIANT and with SAFEARRAY. (But maybe not with the UDT marshallling...)
If this won't ever work, it would be nice to at least know why.
Mark

How to receive bytes in Managed C++ project from COM plus project

I have a module A in Managed C++, it depends on module B in native C++ which wrapped as COM plus.
In module B, I read bytes from a file. Now I am trying to call the file reading functionality from A. But failed.
Dependency detail: I used tlbimp.exe and generated the interop according to Module B. A referrs to the interop.
I tried to pass an "array^" but only one char was received, which is understandable because marshaling doesn't know the array length and could NOT handle the whole array.
I searched out some recommendation about safe array, but could NOT use it successfully in my projects.
Could somebody help me on this?
Thanks a lot.
If you are going to be talking to your native object via COM, you're going to have to pass the array the COM way.
SAFEARRAY would definitely work, but you don't have to use it. It is a fair amount of work to set up anyway. If neither component is a scripting language or VB6, there is little value to using a SAFEARAY.
COM can marshal the array just fine, you just have to tell it how big it is. The two most common mechanisms in COM to pass (native) arrays are "fixed-sized arrays" and "conformant arrays".
Fixed-size array:
If you know at compile time the size of the array, this is the way to go. Declare your COM method as follows in your IDL:
...
const long ARRAY_SIZE = 1024;
...
HRESULTS MethodAbc(MyClass array[ARRAY_SIZE]);
Marshalling will take care of passing the whole array.
Conformant Arrays:
You declare them as follows in IDL:
HRESULT MethodAbc([size_is(arraySize)] MyClass array[], long arraySize);
This tells COM that the arraySize parameter holds the count of elements.
My experience with CLI is minimal, but I don't think you can just pass a CLI handle. Among other things, I believe you need to pin the pointer so that GC doesn't move the array during the COM call. Others please correct me here if I'm wrong.

Is it OK to use boost::shared ptr in DLL interface?

Is it valid to develop a DLL in C++ that returns boost shared pointers and uses them as parameters?
So, is it ok to export functions like this?
1.) boost::shared_ptr<Connection> startConnection();
2.) void sendToConnection(boost::shared_ptr<Connection> conn, byte* data, int len);
In special: Does the reference count work across DLL boundaries or would the requirement be that exe and dll use the same runtime?
The intention is to overcome the problems with object ownership. So the object gets deleted when both dll and exe don't reference it any more.
According to Scott Meyers in Effective C++ (3rd Edition), shared_ptrs are safe across dll boundaries. The shared_ptr object keeps a pointer to the destructor from the dll that created it.
In his book in Item 18 he states, "An especially nice feature of
tr1::shared_ptr is that it automatically uses its per-pointer deleter
to eliminate another potential client error, the "cross-DLL problem."
This problem crops up when an object is created using new in one
dynamically linked library (DLL) but is deleted in a different DLL. On
many platforms, such cross-DLL new/delete pairs lead to runtime
errors. tr1::shared_ptr avoid the problem, because its default deleter
uses delete from the same DLL where the tr1::shared_ptr is created."
Tim Lesher has an interesting gotcha to watch for, though, that he mentions here. You need to make sure that the DLL that created the shared_ptr isn't unloaded before the shared_ptr finally goes out of scope. I would say that in most cases this isn't something you have to watch for, but if you're creating dlls that will be loosely coupled then I would recommend against using a shared_ptr.
Another potential downside is making sure both sides are created with compatible versions of the boost library. Boost's shared_ptr has been stable for a long while. At least since 1.34 it's been tr1 compatible.
In my opinion, if it's not in the standard and it's not an object/mechanism provided by your library, then it shouldn't be part of the interface to the library. You can create your own object to do the reference counting, and perhaps use boost underneath, but it shouldn't be explicitly exposed in the interface.
DLLs do not normally own resources - the resources are owned by the processes that use the DLL. You are probably better off returning a plain pointer, which you then store in a shared pointer on the calling side. But without more info it's hard to be 100% certain about this.
Something to lookout for if you expose raw pointers from a dll interface. It forces you to use the shared dll CRT, memory allocated in one CRT cannot be deallocated in a different CRT. If you use the shared dll CRT in all your modules ( dll's & exe's ) then you are fine, they all share the same heap, if you dont you will be crossing CRT's and the world will meltdown.
Aside from that issue, I agree with the accepted answer. The creation factory probably shouldn't define ownership & lifecycle management for the client code.
No it is not.
The layout of boost::shared_ptr<T> might not be the same on both sides of the DLL boundary. (Layout is influenced by compiler version, packing pragmas, and other compiler options, as well as the actual version of the Boost source code.)
Only "standard layout" (a new concept in C++11, related to the old "POD = plain old data" concept) types can safely be passed between separately-built modules.

JIT code generation techniques

How does a virtual machine generate native machine code on the fly and execute it?
Assuming you can figure out what are the native machine op-codes you want to emit, how do you go about actually running it?
Is it something as hacky as mapping the mnemonic instructions to binary codes, stuffing it into an char* pointer and casting it as a function and executing?
Or would you generate a temporary shared library (.dll or .so or whatever) and load it into memory using standard functions like LoadLibrary ?
You can just make the program counter point to the code you want to execute. Remember that data can be data or code. On x86 the program counter is the EIP register. The IP part of EIP stands for instruction pointer. The JMP instruction is called to jump to an address. After the jump EIP will contain this address.
Is it something as hacky as mapping the mnemonic instructions to binary codes, stuffing it into an char* pointer and casting it as a function and executing?
Yes. This is one way of doing it. The resulting code would be cast to a pointer to function in C.
Is it something as hacky as mapping the mnemonic instructions to binary codes, stuffing it into an char* pointer and casting it as a function and executing?
Yes, if you were doing it in C or C++ (or something similar), that's exactly what you'd do.
It appears hacky, but that's actually an artifact of the language design. Remember, the actual algorithm you want to use is very simple: determine what instructions you want to use, load them into a buffer in memory, and jump to the beginning of that buffer.
If you really try to do this, though, make sure you get the calling convention right when you return to your C program. I think if I wanted to generate code I'd look for a library to take care of that aspect for me. Nanojit's been in the news recently; you could look at that.
Yup. You just build up a char* and execute it. However, you need to note a couple details. The char* must be in an executable section of memory and must have proper alignment.
In addition to nanojit you can also check out LLVM which is another library that's capable of compiling various program representations down to a function pointer. It's interface is clean and the generated code tends to be efficient.
As far as i know it compiles everything in memory because it has to run some heuristics to to optimize the code (i.e.: inlining over time) but you can have a look at the Shared Source Common Language Infrastructure 2.0 rotor release. The whole codebase is identical to .NET except for the Jitter and the GC.
As well as Rotor 2.0 - you could also take a look at the HotSpot virtual machine in the OpenJDK.
About generating a DLL: the additional required I/O for that, plus linking, plus the complexity of generating the DLL format, would make that much more complicate, and above all they'd kill performance; additionally, in the end you still call a function pointer to the loaded code, so...
Also, JIT compilation can happen one method at a time, and if you want to do that you'd generate lots of small DLLs.
About the "executable section" requirement, calling mprotect() on POSIX systems can fix the permissions (there's a similar API on Win32). You need to do that for a big memory segment instead that once per method since it'd be too slow otherwise.
On plain x86 you wouldn't notice the problem, on x86 with PAE or 64bit AMD64/Intel 64 bit machines you'd get a segfault.
Is it something as hacky as mapping
the mnemonic instructions to binary
codes, stuffing it into an char*
pointer and casting it as a function
and executing?
Yes, that works.
To do this in windows you must set PAGE_EXECUTE_READWRITE to the allocated block:
void (*MyFunc)() = (void (*)()) VirtualAlloc(NULL, sizeofblock, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
//Now fill up the block with executable code and issue-
MyFunc();