Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A heap has been corrupted. C# dllimport, delphi PChar return value

I have dll imported. All the other parts work, but the string return value of imported method gives this:

Unhandled exception at 0x7748EA5F (ntdll.dll) in ***.exe: 0xC0000374: A heap has been corrupted (parameters: 0x774C4270).

It still returns the string, but I'm worried that this causes some other errors later on, that are hard to debug. From what I have tested, it feels like it can be anything, that is causing this.

This is my importing code:

[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
private delegate String GetStringDelegate(int handle, int index);

private static GetStringDelegate getString { get; set; }

var addressOfGetString = NativeMethods.GetProcAddress(_handle, "GetString");
getString = (GetStringDelegate)Marshal.GetDelegateForFunctionPointer(addressOfGetString, typeof(GetStringDelegate));

usage

getString(Handle, 1);

This works, but it causes the error. While debugging, just pressing "continue" will allow it to process it and show the results. Result is correct.

This is how it is done in delphi dll

function GetString(Hnd,Index : Integer) : PChar; stdcall;
begin
 Result:=TControl(Hnd).Stack.GetString(Index);
end;

I have same kind of code for integers, doubles, bools and everything else in the dll works, without errors. So I think it creates somekind of overflow or wrong size of memory allocation.

Note: If I create console application, it just fails, without breaking on error, if I run console without debugger ( ctrl+f5 ), it works, still without error. Heap error is generated when I call this from forms application.

TL;DR; This code works, but it shows the heap error, while returning ints, bools etc works perfectly.

like image 801
Katu Avatar asked May 20 '15 12:05

Katu


People also ask

What is heap corruption in C?

Heap corruption occurs when a program damages the allocator's view of the heap. The outcome can be relatively benign and cause a memory leak (where some memory isn't returned to the heap and is inaccessible to the program afterward), or it may be fatal and cause a memory fault, usually within the allocator itself.

How do I track down heap corruption?

Check for heap corruption Most memory corruption is actually due to heap corruption. Try using the Global Flags Utility (gflags.exe) or pageheap.exe. See /windows-hardware/drivers/debugger/gflags-and-pageheap.

Which of the following heap corruption examples refers to writing past the end of a heap allocation?

Overrun and underrun errors They're one of the most difficult type of heap corruption to track down, and usually the most fatal to program execution. Overrun errors occur when the program writes past the end of the allocated block.


1 Answers

When you return a string as a function return value of a p/invoke function the marshaller takes responsibility for freeing that memory. It assumes the memory was allocated on the COM heap, e.g. with CoTaskMemAlloc. Your string does not meet that requirement.

  • You could change the Delphi code to allocate the memory that way.
  • You could return IntPtr and use Marshal.PtrToStringAnsi to manually marshal. The question then remains as to whether the memory needs to be freed, and if so how.
  • You could return a COM BSTR, but that only works with Delphi as an out parameter and not a function return value. See Why can a WideString not be used as a function return value for interop?
  • You could ask the caller to allocate memory and have the callee populate it.

I cannot see all the way into your code to be sure, but I would not be surprised if you were returning PChar(s) where s was a local variable. That would mean that you would be returning the address of freed memory.

The bottom line here is that passing strings (or indeed arrays or other dynamic structures) from callee to caller is much more complex than passing simple value types. You are going to need to re-consider how you do this.

like image 119
David Heffernan Avatar answered Oct 04 '22 13:10

David Heffernan