2

I currently have a heap corruption that is causing my application to crash. My application which is the COM server (C++) marshalls to a C# client application. It looks like a SysFreeString being called possibly from the C# side as part of a COM cleanup. I can't seem to pinpoint the cause but is it possible that doing a memset 0 on the C++ side on a structure that has a BSTR in it cause problems?

Is the following valid?

memset(pResult, 0, sizeof(RESULT)) where pResult is of type RESULT

typedef struct _Result
{
    DWORD dwResult;
    BSTR strData;
}   RESULT;

STACK_TEXT from WinDbg:

00000000`77b4b518 00000000`77a7bc35 ntdll! ?? ::FNODOBFM::`string'+0xea19
00000000`77b4b520 000007fe`ffc41377 oleaut32!SysFreeString+0x53
00000000`77b4b528 000007fe`ffc46b2e oleaut32!BSTR_UserFree+0x1e
00000000`77b4b530 000007fe`fe354a1c rpcrt4!NdrUserMarshalFree+0x4c
00000000`77b4b538 000007fe`fe3566eb rpcrt4!NdrpFreeParams+0x207
00000000`77b4b540 000007fe`fe365362 rpcrt4!NdrStubCall2+0xedc
00000000`77b4b548 000007fe`fe84f16e ole32!CStdStubBuffer_Invoke+0x8b
00000000`77b4b550 000007fe`fe850ccd ole32!SyncStubInvoke+0x5d
00000000`77b4b558 000007fe`fe850c43 ole32!StubInvoke+0xdb
00000000`77b4b560 000007fe`fe70a4f0 ole32!CCtxComChnl::ContextInvoke+0x190
00000000`77b4b568 000007fe`fe8514d6 ole32!AppInvoke+0xc2
00000000`77b4b570 000007fe`fe85122b ole32!ComInvokeWithLockAndIPID+0x52b
00000000`77b4b578 000007fe`fe84fd6d ole32!ThreadInvoke+0x30d
00000000`77b4b580 000007fe`fe363254 rpcrt4!DispatchToStubInCNoAvrf+0x14
00000000`77b4b588 000007fe`fe3633b6 rpcrt4!RPC_INTERFACE::DispatchToStubWorker+0x146
00000000`77b4b590 000007fe`fe365b8b rpcrt4!RPC_INTERFACE::DispatchToStub+0x9b
00000000`77b4b598 000007fe`fe365acb rpcrt4!RPC_INTERFACE::DispatchToStubWithObject+0x5b
00000000`77b4b5a0 000007fe`fe365a62 rpcrt4!LRPC_SCALL::DispatchRequest+0x422
00000000`77b4b5a8 000007fe`fe36375d rpcrt4!LRPC_SCALL::HandleRequest+0x20d
00000000`77b4b5b0 000007fe`fe3809ff rpcrt4!LRPC_ADDRESS::ProcessIO+0x3bf
00000000`77b4b5b8 000007fe`fe3805b5 rpcrt4!LrpcIoComplete+0xa5
00000000`77b4b5c0 00000000`77a2b6bb ntdll!TppAlpcpExecuteCallback+0x26b
00000000`77b4b5c8 00000000`77a2ff2f ntdll!TppWorkerThread+0x3f8
00000000`77b4b5d0 00000000`7790652d kernel32!BaseThreadInitThunk+0xd
00000000`77b4b5d8 00000000`77a3c541 ntdll!RtlUserThreadStart+0x1d
joce
  • 9,624
  • 19
  • 56
  • 74
sgobiraj
  • 29
  • 2
  • 5

3 Answers3

0

is it possible that doing a memset 0 on the C++ side on a structure that has a BSTR in it cause problems?

No, BSTR is a pointer type (typedef OLECHAR *BSTR;) so clearing it's value with memset would at most cause a memory leak but not a crash.

Captain Obvlious
  • 19,754
  • 5
  • 44
  • 74
  • Thanks for pointing that out. My only other hunch at the moment is the use of _bstr_t when marshalling between C++ and C#. I use _bstr_t and assign it to the BSTR in the struct when marshalling it to the C# application. My understanding is that a _bstr_t calls SysFreeString upon destruction. Would this mean that SysFreeString would be called twice one on the C++ side and one from the C# marshaller? – sgobiraj May 08 '14 at 15:53
  • 1
    Yes, that would be a problem `_bstr_t` has ownership semantics so yes, assigning the BSTR pointer means the `_bstr_t` object now owns the string and will delete on destruction. – Captain Obvlious May 08 '14 at 15:56
  • What do you suggest would be the best way to assign the _bstr_t object to the BSTR before marshalling it to the C# application? Would I have to do a Detach() to assign it to the BSTR object on the struct that is to be marshalled? Do you think this likely is the culprit where the BSTR is being freed twice? – sgobiraj May 08 '14 at 16:13
  • Yes, `Detach` is exactly what you're looking for. After the C# call returns call `Detach` to release ownership of the string -or- if performance isn't an issue make a copy of the string and stuff it into a `_bstr_t` object. – Captain Obvlious May 08 '14 at 16:16
  • I kind of didn't get what you meant. What if the C++ COM function is called from the C# app and the OUT parameter is a BSTR type. Do I just assign the OUT parameter with the _bstr_t Detach? Like for example bstrOutputParm = _bstr_t("test").Detach()? If I didn't do a Detach would this result in a double free for the BSTR within the _bstr_t? – sgobiraj May 08 '14 at 17:00
0

It has been a while since I messed with this stuff, but I think that a BSTR is an abomination where the wchar_t * pointer does not point to the beginning of the buffer. SysFreeString() will actually free (ptr-1) or something like that. Zeroing it with memset() sounds like a bad idea.

Michael J
  • 7,631
  • 2
  • 24
  • 30
  • The OP is zeroing out the pointer value held by in a BSTR variable not the contents the BSTR points to. – Captain Obvlious May 08 '14 at 21:56
  • That is right. BSTR is not (necessarily) nul terminated, so it has to have a length field. But they want to be able to seamlessley cast to wchar_t. So the actual object is 1 uint16 of size followed by some wchar_t bytes. ***BUT*** The BSTR * ptr points to the start of the char data, with the size at an offset of -1. So deep inside SysFreeString() is something vaguely like `free(ptr-1)`. We are talking ugly black magic. Contemplate what might happen if you pass `SysFreeString(NULL)`. – Michael J May 09 '14 at 01:11
  • Invoking `SysFreeString(NULL)` results in a no-op. – Captain Obvlious May 09 '14 at 01:18
  • @CaptainObvlious - You are right. I just checked with VC2013 disassembly and it tested for a null ptr. Oh well, I was just speculating on a possible cause. I still say BSTR is an abomination. :-) – Michael J May 09 '14 at 01:34
  • It's really weird how the BSTR works internally when the typedef is actually an OLECHAR*. So is memset a bad idea on a struct with a BSTR in it? – sgobiraj May 09 '14 at 15:36
  • @sgobiraj - My first reaction was that `memset()` is the problem, but that was probably prejudiced by my inate hatred of the `BSTR`. It will set the `BSTR` pointer to `NULL`, but that appears to be safe to do. Could you have assigned a regular `wchar_t *` to the `BSTR`? That would certainly cause a problem like yours. – Michael J May 10 '14 at 20:51
0

If the exception is coming in COM Clean up code. surely, there is problem in Allocation of this Result Structure.

Please ensure:

How this parameter is being passed to the function

In Parameter => If this Parameter is passed as In parameter than it is being allocated by the client and you cannot re-allocate this parameter otherwise you will get this exception.

InOut Parameter => If this parameter is InOut parameter than you can re-Allocate this parameter.

  • The problem is that because it is a COM call I don't know which RPC function call triggered this problem. Is there any way to find out which COM function call on my interface caused this heap corruption? – sgobiraj May 09 '14 at 21:47
  • You don't need to bother about COM Runtime functions, They will work fine. I can help you more if you can show me the code – Mustafa Muhammad May 12 '14 at 07:22