I have the following function written in C#
public static string GetNominativeDeclension(string surnameNamePatronimic)
{
if(surnameNamePatronimic == null)
throw new ArgumentNullException("surnameNamePatronimic");
IntPtr[] ptrs = null;
try
{
ptrs = StringsToIntPtrArray(surnameNamePatronimic);
int resultLen = MaxResultBufSize;
int err = decGetNominativePadeg(ptrs[0], ptrs[1], ref resultLen);
ThrowException(err);
return IntPtrToString(ptrs, resultLen);
}
catch
{
return surnameNamePatronimic;
}
finally
{
FreeIntPtr(ptrs);
}
}
Function decGetNominativePadeg is in unmanaged dll
[DllImport("Padeg.dll", EntryPoint = "GetNominativePadeg")]
private static extern Int32 decGetNominativePadeg(IntPtr surnameNamePatronimic,
IntPtr result, ref Int32 resultLength);
and throws an exception:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
The catch that is in C# code doesn't actually catch it. Why? How to handle this exception?
Thank you for your help!
"The CLR no longer delivers exceptions for corrupted process state to exception handlers in managed code."
.NET Framework 4 Migration Issues.
Just add this to the config file:
http://msdn.microsoft.com/en-us/library/dd638517.aspx
If the IntPtr result parameter is to receive the value from within the function, it must be marked ref.
I don't see ptrs[1] being assigned any value before passing.
Try changing the definition to:
[DllImport("Padeg.dll", EntryPoint = "GetNominativePadeg")]
private static extern Int32 decGetNominativePadeg(IntPtr surnameNamePatronimic,
**ref** IntPtr result, ref Int32 resultLength);
The reason probably is that it's trying to write to "result" which is marked as input-only.
you have probably turned off debugging of unmanaged code.
"Enable unmanaged code debugging option" must be check in project properties under the Debug section. After this, the exception is shown in the debugging process.
Related
I am using DllImport to call method in c wrapper library from my own .net class. This method in c dll creates a string variable and returns the pointer of the string.
Something like this;
_declspec(dllexport) int ReturnString()
{
char* retval = (char *) malloc(125);
strcat(retval, "SOMETEXT");
strcat(retval, "SOMETEXT MORE");
return (int)retval;
}
Then i read the string using Marshall.PtrToStringAnsi(ptr). After i get a copy of the string, i simply call another c method HeapDestroy which is in c wrapper library that calls free(ptr).
Here is the question;
Recently while it is working like a charm, I started to get "Attempted to read or write protected memory area" exception. After a deeper analysis, i figured out, i beleive, although i call free method for this pointer, value of the pointer is not cleared, and this fills the heap unattended and makes my iis worker process to throw this exception. By the way, it is an web site project that calls this method in c library.
Would you kindly help me out on this issue?
Sure, here is C# code;
[DllImport("MyCWrapper.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private extern static int ReturnString();
[DllImport("MyCWrapper.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private extern static void HeapDestroy(int ptr);
public static string GetString()
{
try
{
int i = ReturnString();
string result = String.Empty;
if (i > 0)
{
IntPtr ptr = new IntPtr(i);
result = Marshal.PtrToStringAnsi(ptr);
HeapDestroy(i);
}
return result;
}
catch (Exception e)
{
return String.Empty;
}
}
What may be the problem is the underlying C code. You are not adding a NULL terminator to the string which strcat relies on (or checking for a NULL return from malloc). It's easy to get corrupted memory in that scenario. You can fix that by doing the following.
retval[0] = '\0';
strcat(retval, "SOMETEXT");
Also part of the problem is that you are playing tricks on the system. It's much better to write it correctly and let the system work on correctly functioning code. The first step is fixing up the native code to properly return the string. One thing you need to consider is that only certain types of memory can be natively freed by the CLR (HGlobal and CoTask allocations). So lets change the function signature to return a char* and use a different allocator.
_declspec(dllexport) char* ReturnString()
{
char* retval = (char *) CoTaskMemAlloc(125);
retval[0] = '\0';
strcat(retval, "SOMETEXT");
strcat(retval, "SOMETEXT MORE");
return retval;
}
Then you can use the following C# signature and free the IntPtr with Marshal.FreeCoTaskMem.
[DllImport("SomeDll.dll")]
public static extern IntPtr ReturnString();
Even better though. When marshalling, if the CLR ever thinks it needs to free memory it will use FreeCoTaskMem to do so. This is typically relevant for string returns. Since you allocated the memory with CoTaskMemAlloc you can save yourself the marshalling + freeing steps and do the following
[DllImport("SomeDll.dll", CharSet=Ansi)]
public static extern String ReturnString();
Freeing memory doesn't clear it, it just frees it up so it can be re-used. Some debug builds will write over the memory for you to make it easier to find problems with values such as 0xBAADFOOD
Callers should allocate memory, never pass back allocated memory:
_declspec(dllexport) int ReturnString(char*buffer, int bufferSize)
{
if (bufferSize < 125) {
return 125;
} else {
strcat(buffer, "SOMETEXT");
strcat(buffer, "SOMETEXT MORE");
return 0;
}
}
Although memory is allocated by the DLL in the same heap as your application, it MAY be using a different memory manager, depending on the library it was linked with. You need to either make sure you're using the same exact library, or add code to release the memory that the DLL allocates, in the DLL code itself.
I have the basic MiniDumpWriteDump method interop copied off the internet in my C# (3.5) project.
Up till now, i have used this code to register on the UnhandledException event, to take a crash dump before the process shuts down.
In a particular scenario i am facing now, i have set this function to be used in some other case, to take a diagnostic memory dump of the process.
Whenever this function gets called (not from the UnhandledException handler), it throws an AccessViolationException
Here's what the MiniDump code looks like (removed some redundant parts):
using (var fs = new System.IO.FileStream(fileName,
System.IO.FileMode.Create,
System.IO.FileAccess.Write,
System.IO.FileShare.None))
{
MiniDumpExceptionInformation exp;
exp.ThreadId = GetCurrentThreadId();
exp.ClientPointers = false;
exp.ExceptionPointers = Marshal.GetExceptionPointers();
bool bRet = MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
fs.SafeFileHandle.DangerousGetHandle(),
(uint)dumpType,
ref exp,
IntPtr.Zero,
IntPtr.Zero);
return bRet;
}
Native types are defined like so:
//typedef struct _MINIDUMP_EXCEPTION_INFORMATION {
// DWORD ThreadId;
// PEXCEPTION_POINTERS ExceptionPointers;
// BOOL ClientPointers;
//} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;
// Pack=4 is important! So it works also for x64!
[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct MiniDumpExceptionInformation
{
public uint ThreadId;
public IntPtr ExceptionPointers;
[MarshalAs(UnmanagedType.Bool)]
public bool ClientPointers;
}
Marshal.GetExceptionPointers() might return IntPtr.Zero (maybe when the OS sees the exception as handled). If this is the case you can try to put the call of 'MiniDumpWriteDump' somewhere else. I have had the same problem and solved it by putting 'MiniDumpWriteDump' into the event handler 'AppDomain.CurrentDomain.FirstChanceException'.
When I run the code below for the GetWindowText I get the following error thrown as an inner Exception:
{"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."}
[DllImport("user32.dll", EntryPoint = "GetWindowTextLength", SetLastError = true)]
internal static extern int GetWindowTextLength(IntPtr hwnd);
[DllImport("user32.dll", EntryPoint = "GetWindowText", SetLastError = true)]
internal static extern int GetWindowText(IntPtr hwnd, ref StringBuilder wndTxt, int MaxCount);
try{
int strLength = NativeMethods.GetWindowTextLength(wndHandle);
var wndStr = new StringBuilder(strLength);
GetWindowText(wndHandle, ref wndStr, wndStr.Capacity);
}
catch(Exception e){ LogError(e) }
I have 2 questions:
Why is the Error not being caught by the try catch?
Any idea how I can stop the program crashing when it hits this type of error other than using try/catch
Cheers
1.
There are some exceptions that cannot be caught. One type is StackOverflow or OutOfMemory because there is literally no memory to allocate for the handler to run. Another type is one delivered to the CLR via the windows OS. This mechanism is called structured exception handling. These kinds of exceptions can be very bad because the CLR cannot be sure that its own internal state is consistent and are sometimes called corrupted state exceptions. In .Net 4, managed code does not handle these exceptions by default.
The above message is from an AccessViolationException, which is a kind of corrupted state exception. This is happening because you are calling an unmanaged method which is writing past the end of a buffer. See this article on possibly handling these exceptions.
2.
Does the sample code here work? You need to make sure the unmanaged code doesn't write past the end of the StringBuilder's buffer.
public static string GetText(IntPtr hWnd)
{
// Allocate correct string length first
int length = GetWindowTextLength(hWnd);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(hWnd, sb, sb.Capacity);
return sb.ToString();
}
It's possible that calling these external methods is causing problems because of the parameters you're providing to GetWindowText. I think you should try the following:
try{
int strLength = NativeMethods.GetWindowTextLength(wndHandle);
var wndStr = new StringBuilder(strLength + 1);
GetWindowText(wndHandle, wndStr, wndStr.Capacity);
}
catch(Exception e){ LogError(e) }
I get an intermittent error when calling Message.GetLParam, getting messages sent between processes.
I have two processes, both written in C# (.Net 3.5). I am using the Win32 function SendMessage() to send data from one process (the source) to the other (the target). The target process's main window (it's a Windows Forms app) overrides the WndProc() function to receive messages.
The source process locates the other by using the Process.GetProcessesByName() function, then using the Process.MainWindowHandle to get the window handle that I want to send the message to. The code of the source looks like this:
Process[] procs = Process.GetProcessesByName("MyTargetProcess");
if (procs != null
&& procs.Length > 0)
{
IntPtr win = procs[0].MainWindowHandle;
var someData = new Win32.COPYDATASTRUCT // This is a struct that I defined
{
// Initialize fields of the struct
};
Win32.SendMessage(win,
Win32.MyMsgCode, // my custom message
IntPtr.Zero, // wParam = 0
ref someData);
}
The target process code looks like this:
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == Win32.MyMsgCode)
{
Win32.COPYDATASTRUCT ds;
try
{
ds = (Win32.COPYDATASTRUCT)m.GetLParam(typeof(Win32.COPYDATASTRUCT));
}
catch (Exception ex)
{
log.ErrorFormat("Got exception in WndProc", ex);
}
// Do something with the message
....
}
Win32 is a static class I defined that gets all my P/Invoke definitions.
I do not understand why I am catching an AccessViolationException in WndProc.
Does anybody have an idea why? and why it only happens some of the time?
Thanks for your attention!
-------------------------------- EDIT ------------------------------------------
Another thing that baffles me: the COPYDATASTRUCT is declared as
public static readonly int WM_COPYDATA = 0x004a;
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
// Specifies data to be passed to the receiving application.
public string dwData;
// Specifies the size, in bytes, of the data pointed to by the lpData member.
public int cbData;
// Pointer to data to be passed to the receiving application. This member can be NULL.
public string lpData;
}
It is initialized like this:
string payload = " some data ";
var someData = new Win32.COPYDATASTRUCT // This is a struct that I defined
{
dwData = "bogusData",
cbData = sizeof(char) * payload.Length,
lpData = payload
};
And in target code, I always receive dwData = null.
----------------------- 2nd edit --------------------------------------
I just tried with adding the zero terminator, and I still get the error.
If I change the marshalling code to do my own marshalling as in
IntPtr pcds = Marshal.AllocHGlobal(Marshal.SizeOf(someData));
Marshal.StructureToPtr(someData, pcds, true);
Win32.SendMessage(win, (uint)Win32.WM_COPYDATA, IntPtr.Zero, pcds);
Then the error happens ALL THE TIME! However, if I repeat the GetLParam() call in the catch block, it succeeds almost all the time, on the 2nd try.
The thing that jumps out at me is that cbData is set incorrectly. You need to account for the zero-terminator at the end of the string.
cbData = sizeof(char) * (payload.Length+1)
That would certainly explain the error. When you send the message, the WM_COPYDATA marshalling would not copy the zero terminator and so the recipient would then read beyond the end of the buffer into uninitialized values.
I also wonder about sizeof(char). Are you calling the Unicode version of SendMessage? If not then I'd expect to see access violations in the sending code.
You should also be wary that the recipient application opens itself to buffer overruns. Because it ignores the value of cbData and treats the lpData field as a null-terminated pointer it may be possible for an attacker to force your app to execute arbitrary code. To defend against this, you should copy the data, cbData bytes of it, into a byte array and then convert to a string.
The other issue is that you need to declare dwData as UIntPtr. The way you have defined the struct, the recipient code treats dwData as a pointer to a string which will provoke AVs because you have crossed process boundaries.
I'd also point out that cbData is unsigned and should be uint but that is a benign error here.
I am interfacing with code that takes a char** (that is, a pointer to a string):
int DoSomething(Whatever* handle, char** error);
Basically, it takes a handle to its state, and if something goes wrong, it returns an error code and optionally an error message (the memory is allocated externally and freed with a second function. That part I've figued out :) ).
I, however, am unsure how to handle in in C#. What I have currently:
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
private static unsafe extern int DoSomething(IntPtr handle, byte** error);
public static unsafe int DoSomething(IntPtr handle, out string error) {
byte* buff;
int ret = DoSomething(handle, &buff);
if(buff != 0) {
// ???
} else {
error = "";
}
return ret;
}
I've poked around, but I can't figure out how to turn that into a byte[], suitable for feeding to UTF8Encoding.UTF8.GetString()
Am I on the right track?
EDIT: To make more explicit, the library function allocates memory, which must be freed by calling another library function. If a solution does not leave me with a pointer I can free, the solution is unacceptable.
Bonus question: As implied above, this library uses UTF-8 for its strings. Do I need to do anything special in my P/Invokes, or just use string for normal const char* parameters?
You should just be able to use a ref string and have the runtime default marshaller take care of this conversion for you. You can hint the char width on the parameter with [MarshalAs(UnmanagedType.LPStr)] to make sure that you are using 8-bit characters.
Since you have a special deallocation method to call, you'll need to keep the pointer, like you've already shown in your question's example.
Here's how I'd write it:
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
private static unsafe extern int DoSomething(
MySafeHandle handle, void** error); // byte** should work, too, I'm just lazy
Then you can get a string:
var errorMsg = Marshal.PtrToStringAnsi(new IntPtr(*error));
And cleanup:
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int FreeMyMemory(IntPtr h);
// ...
FreeMyMemory(new IntPtr(error));
And now we have the marshalled error, so just return it.
return errorMsg;
Also note the MySafeHandle type, which would inherit from System.Runtime.InteropServices.SafeHandle. While not strictly needed (you can use IntPtr), it gives you a better handle management when interoping with native code. Read about it here: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx.
For reference, here is code that compiles (but, not tested yet, working on that next tested, works 100%) that does what I need. If anyone can do better, that's what I'm after :D
public static unsafe int DoSomething(IntPtr handle, out string error) {
byte* buff;
int ret = DoSomething(handle, &buff);
if(buff != null) {
int i = 0;
//count the number of bytes in the error message
while (buff[++i] != 0) ;
//allocate a managed array to store the data
byte[] tmp = new byte[i];
//(Marshal only works with IntPtrs)
IntPtr errPtr = new IntPtr(buff);
//copy the unmanaged array over
Marshal.Copy(buff, tmp, 0, i);
//get the string from the managed array
error = UTF8Encoding.UTF8.GetString(buff);
//free the unmanaged array
//omitted, since it's not important
//take a shot of whiskey
} else {
error = "";
}
return ret;
}
Edit: fixed the logic in the while loop, it had an off by one error.