What situations provoke a .net 2.0 String constructor to throw an exception? - c++-cli

I have some code which sometimes (but not always) throws the exception described in a Microsoft kb article when using a particular form of the String costructor.
In essence, my code looks like this (except the input string array varies in length depending on the input):
int arraySize = 8;
char* charArray3 = new char[arraySize];
memset(charArray3, 0x61, arraySize);
char * pstr3 = &charArray3[0];
String^ szAsciiUpper = gcnew String(pstr3, 0, arraySize);
The kb article suggests this 'may' cause the exception to be thrown but my unit tests and most of the time in the wild, it never appears.
I'd like to know what would provoke the exception so that I can replicate it in my unit tests and verify it's fixed permanently in our codebase.

This bug appears in src/vm/comstring.cpp, COMString::StringInitCharHelper() function. This is the evil-doer:
if( IsBadReadPtr(pszSource, (UINT_PTR)length + 1)) {
COMPlusThrowArgumentOutOfRange(L"ptr", L"ArgumentOutOfRange_PartialWCHAR");
}
Or in other words, it will peek at length+1 and take a nose-dive when IsBadReadPtr() returns false. Yes, you have to be unlucky, your charArray3 would have to be allocated exactly at the end of a memory page and the next page must be inaccessible. That doesn't happen very often.
Not so sure there is any point in trying to repro the bug, it is just too random. Simply make your array 1 element bigger to avoid it. Or move to .NET 4, they did fix it simply by removing the check completely.

They fixed it in 4.0, still broken in 2.0:
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication13
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
// For .NET 4.0
//[System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions]
static unsafe void Main(string[] args)
{
IntPtr ptr = VirtualAlloc(
IntPtr.Zero,
(IntPtr)(4096 * 2),
0x1000 /* MEM_COMMIT */ | 0x2000 /* MEM_RESERVE */,
0x04 /* PAGE_READWRITE */);
IntPtr page1 = ptr;
IntPtr page2 = (IntPtr)((long)ptr + 4096);
uint oldAccess;
bool res = VirtualProtect(page2, 4096, 0x01 /* PAGE_NOACCESS */, out oldAccess);
try
{
Marshal.WriteByte(page1, 1);
Console.WriteLine("OK");
}
catch (AccessViolationException)
{
Console.WriteLine("KO");
}
try
{
Marshal.WriteByte(page2, 1);
Console.WriteLine("KO");
}
catch (AccessViolationException)
{
Console.WriteLine("OK");
}
try
{
byte b1 = Marshal.ReadByte(page1);
Console.WriteLine("OK");
}
catch (AccessViolationException)
{
Console.WriteLine("KO");
}
try
{
byte b2 = Marshal.ReadByte(page2);
Console.WriteLine("KO");
}
catch (AccessViolationException)
{
Console.WriteLine("OK");
}
for (int i = 0; i < 4096; i++)
{
Marshal.WriteByte(page1, i, (byte)'A');
}
sbyte* ptr2 = (sbyte*)page1;
try
{
var st1 = new string(ptr2, 0, 4096);
Console.WriteLine("OK");
}
catch (ArgumentOutOfRangeException)
{
Console.WriteLine("KO");
}
}
}
}
You have to uncomment a line in .NET 4.0 . Note that this code doesn't free the memory it allocates, but it isn't a big problem, because when a process ends the memory is reclaimed by the OS.
What does this program do? It allocates 8192 bytes (2 pages) using VirtualAlloc. By using VirtualAlloc the two pages are page aligned. It disable access to the second page (with VirtualProtect). Then it fills the first page with 'A'. Then it tries to create a string from the first page. On .NET 2.0, the string constructor tries to read the first byte of the second page (even if you told it that the string was only long 4096 bytes).
In the middle there are some tests that check if the pages can be read/written.
Normally it is difficult to check this condition because it is difficult to have a block of memory that is exactly at the end of the allocated readable memory space.

In case anyone's interested, this is how to replicate it in C++/CLI (based entirely on xanatos' answer):
LPVOID ptr = VirtualAlloc(0, 4096 * 2, 0x1000, 0x04); // ReadWrite
LPVOID page1 = ptr;
LPVOID page2 = (LPVOID)((long)ptr + 4096);
DWORD oldAccess;
bool res = VirtualProtect(page2, 4096, 0x01, &oldAccess);
char* ptr2 = (char*)page1;
String^ st1 = gcnew String(ptr2, 0, 4096); // <-- This will cause the exception.
Console::WriteLine(st1);

Related

I have to write logfile to trace init sequence from my simulator application

So, I dont have much idea about logfile and i need to write a logfile using fprintf between BlueModPlusS50::Send and BlueModPlusS50::Receive as you can check in the code, so that it can trace init, scan and print sequences from the simulator application that i use. So please help me to understand what it actually means and how to do that. Even if there are different versions of your understanding, you may let me know. I am using Visual Studio 2019.
void BlueModPlusS50::Send(std::shared_ptr< Message > msg, const ms timeout) {
#ifdef SIMULATION
DWORD BytesWritten = 0;
printf(">>>>>>%s<<<<<<", msg->GetPayload());
bool Status = WriteFile(com_handle_, // Handle to the Serialport
msg->GetPayload(), // Data to be written to the port
msg->GetSize(), // No of bytes to write into the port
&BytesWritten, // No of bytes written to the port
NULL);
if (Status == FALSE) {
printf_s("\nFail to Written");
}
#endif // SIMULATION
}
void BlueModPlusS50::Receive(std::shared_ptr<Message> msg) {
#ifdef SIMULATION
DWORD NoBytesRead; // Bytes read by ReadFile()
char ReadData; // temporary Character
unsigned char received = 0;
auto payload = msg->GetPayload();
do {
bool Status = ReadFile(com_handle_, &ReadData, sizeof(ReadData), &NoBytesRead, NULL);
if (NoBytesRead > 0) {
payload[received] = ReadData;
printf("%c", ReadData);
++received;
}
} while (received < msg->GetSize());
msg->SetSize(received);

Read output from Process in custiom action dont return symbols selected language Wix

I use the same code in custom action wix and console app. In custom action it dont return polish symbol "ł" and "ą" in custom action. Replaces them with other symbols or spaces. In console app it works well.
Already in the "message" variable there isnt polish letters.
private static void RunTest(Session session)
{
try
{
Process p = CreateProcess();
p.StartInfo.FileName = "....exe"; ;
p.StartInfo.Arguments = "-t";
string message = "";
int errorCount = 0;
p.OutputDataReceived += (sender, args) =>
{
if (args.Data == null)
return;
message += args.Data;
message += "\n";
};
p.ErrorDataReceived += (sender, args) =>
{
if (args.Data == null)
return;
errorCount++;
message += args.Data;
message += "\n";
};
p.Start();
p.BeginOutputReadLine();
p.WaitForExit();
SaveNewRtf(session, message);
}
catch (Exception)
{
}
}
private static Process CreateProcess()
{
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
return p;
}
Edit:
This is happen because Massages from Process are in Unicode. But unfortunately I don't know how repair that. I changed encoding to utf-8 for messages in Program I run by Process and still the message are download in Unicode.
I solved it by
p.StartInfo.StandardOutputEncoding = OemEncoding.GetDefaultOemCodePageEncoding();
and
public static class OemEncoding
{
private const Int32 MAX_DEFAULTCHAR = 2;
private const Int32 MAX_LEADBYTES = 12;
private const Int32 MAX_PATH = 260;
private const UInt32 CP_OEMCP = 1;
public static Encoding GetDefaultOemCodePageEncoding()
{
CPINFOEX cpInfoEx;
if (GetCPInfoEx(CP_OEMCP, 0, out cpInfoEx) == 0)
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
"GetCPInfoEx() failed with error code {0}",
Marshal.GetLastWin32Error()));
return Encoding.GetEncoding((int)cpInfoEx.CodePage);
}
[DllImport("Kernel32.dll", EntryPoint = "GetCPInfoExW", SetLastError = true)]
private static extern Int32 GetCPInfoEx(UInt32 CodePage, UInt32 dwFlags, out CPINFOEX lpCPInfoEx);
[StructLayout(LayoutKind.Sequential)]
private unsafe struct CPINFOEX
{
internal UInt32 MaxCharSize;
internal fixed Byte DefaultChar[MAX_DEFAULTCHAR];
internal fixed Byte LeadByte[MAX_LEADBYTES];
internal Char UnicodeDefaultChar;
internal UInt32 CodePage;
internal fixed Char CodePageName[MAX_PATH];
}
}

Passing string array from Borland C++ to C#

I want to pass list of email address strings from Borland C++ to my C# library. Below my C# side code. I could make call to PrintName() method and it works. Now I want to print email addresses, but if I call PrintEmails() function nothing happens. Could you please suggest how I can pass multiple email addresses to C# lib.
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("4A686AB1-8425-43D9-BD89-B696BB5F6A18")]
public interface ITestConnector
{
void PrintEmails(string[] emails);
void PrintName(string name);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(ITestConnector))]
[Guid("7D818287-298A-41BF-A224-5EAC9C581BD0")]
public class TestConnector : ITestConnector
{
public void PrintEmails(string[] emails)
{
System.IO.File.WriteAllLines(#"c:\temp\emails.txt", emails);
}
public void PrintName(string name)
{
System.IO.File.WriteAllText(#"c:\temp\name.txt", name);
}
}
I have imported TLB file of above C# library into RAD Studio and my C++ side code is as below.
interface ITestConnector : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE PrintEmails(LPSAFEARRAY* emails/*[in,out]*/) = 0; // [-1]
virtual HRESULT STDMETHODCALLTYPE PrintName(WideString name/*[in]*/) = 0; // [-1]
};
TTestConnector *connector = new TTestConnector(this);
SAFEARRAYBOUND bounds[] = {{2, 0}}; //Array Contains 2 Elements starting from Index '0'
LPSAFEARRAY pSA = SafeArrayCreate(VT_VARIANT,1,bounds); //Create a one-dimensional SafeArray of variants
long lIndex[1];
VARIANT var;
lIndex[0] = 0; // index of the element being inserted in the array
var.vt = VT_BSTR; // type of the element being inserted
var.bstrVal = ::SysAllocStringLen( L"abc#xyz.com", 11 ); // the value of the element being inserted
HRESULT hr= SafeArrayPutElement(pSA, lIndex, &var); // insert the element
// repeat the insertion for one more element (at index 1)
lIndex[0] = 1;
var.vt = VT_BSTR;
var.bstrVal = ::SysAllocStringLen( L"pqr#xyz.com", 11 );
hr = SafeArrayPutElement(pSA, lIndex, &var);
connector->PrintEmails(pSA);
delete connector;
Below C++ side code worked in my case.
SAFEARRAYBOUND saBound[1];
saBound[0].cElements = nElements;
saBound[0].lLbound = 0;
SAFEARRAY *pSA = SafeArrayCreate(VT_BSTR, 1, saBound);
if (pSA == NULL)
{
return NULL;
}
for (int ix = 0; ix < nElements; ix++)
{
BSTR pData = SysAllocString(elements[ix]);
long rgIndicies[1];
rgIndicies[0] = saBound[0].lLbound + ix;
HRESULT hr = SafeArrayPutElement(pSA, rgIndicies, pData);
_tprintf(TEXT("%d"), hr);
}

PInvoke - Issue while calling DJVU function from C# code. Attempted to read or write protected memory

UPDATE 3-4-15:11IS
As recommended by David modified PInvoke as below, this time I am getting different error "Unhandled exception of type System.ExecutionEngineException occurred in mscorlib.dll"
[DllImport("C:\\Program Files\\DJVULIBRE\\LIBDJVULIBRE.dll", CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private unsafe static extern int ddjvu_page_render(IntPtr page, ddjvu_render_mode_t mode, ref ddjvu_rect_t pagerect,
ref ddjvu_rect_t renderrect,
IntPtr pixelformat,
uint rowsize,
[Out][MarshalAs(UnmanagedType.LPArray)]byte[] imagebuffer);
Thanks David for your valuable time, I think is close to a fix.
HISTORY
I know there are many questions in this subject but none of them help to resolve the issue I am currently facing.
Below is the API function in C Language
DDJVUAPI int
ddjvu_page_render(ddjvu_page_t *page,
const ddjvu_render_mode_t mode,
const ddjvu_rect_t *pagerect,
const ddjvu_rect_t *renderrect,
const ddjvu_format_t *pixelformat,
unsigned long rowsize,
char *imagebuffer );
Below is the PInvoke signature of C Function added in .NET code
[DllImport("C:\\Program Files\\DJVULIBRE\\LIBDJVULIBRE.dll", CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private unsafe static extern int ddjvu_page_render(IntPtr page, ddjvu_render_mode_t mode, IntPtr pagerect,
IntPtr renderrect,
IntPtr pixelformat,
ulong rowsize,
[Out][MarshalAs(UnmanagedType.LPArray)]byte[] imagebuffer);
Below is how I am calling this function in the c# code
byte* buffer = (byte *)Memory.Alloc(nSize);
try
{
IntPtr ptr1 = (IntPtr)Memory.Alloc(Marshal.SizeOf(prect));
Marshal.StructureToPtr(prect, ptr1, false);
IntPtr ptr2 = (IntPtr)Memory.Alloc(Marshal.SizeOf(rrect));
Marshal.StructureToPtr(rrect, ptr2, false);
byte[] array = new byte[nSize];
fixed (byte* p = array) Memory.Copy(buffer, p, nSize);
ddjvu_page_render(page, ddjvu_render_mode_t.DDJVU_RENDER_MASKONLY, ptr1, ptr2, fmt, (ulong)stride, array);
}
finally
{
Memory.Free(buffer);
}
call to ddjvu_page_render in above code is throwing "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Prior to this post I must have tried all the option could find in various blogs.
Appreciate any help, is almost a day I am clueless, your timely help could save my job
UPDATE 3-4-15:7:44IS
This code is using DJVULibre
UPDATE 3-4-15:8:35IS
Here is the code I have in Form Load
ctx = ddjvu_context_create(System.AppDomain.CurrentDomain.FriendlyName);
if (ctx != null)
{
string djFile = "C:\\Users\\rammohan.chavakula\\Documents\\eiasample.djvu";
doc = ddjvu_document_create_by_filename(ctx, djFile, 100);
if (doc != null)
{
while (ddjvu_job_status(ddjvu_document_job(doc)) >= ddjvu_status_t.DDJVU_JOB_OK)
SpinDdjvuMessageLoop(ctx, true);
int pageCount = ddjvu_document_get_pagenum(doc);
mediaboxes = new Rectangle[pageCount];
for (int i = 0; i < pageCount; i++)
{
ddjvu_status_t status;
ddjvu_pageinfo_t info = new ddjvu_pageinfo_t();
while ((status = ddjvu_document_get_pageinfo_imp(doc, i, ref info, (uint)System.Runtime.InteropServices.Marshal.SizeOf(info))) < ddjvu_status_t.DDJVU_JOB_OK)
SpinDdjvuMessageLoop(ctx, true);
if (status != ddjvu_status_t.DDJVU_JOB_OK)
continue;
mediaboxes[i] = new Rectangle(0, 0, info.width / info.dpi,
info.height / info.dpi);
}
}
ddjvu_context_release(ctx);
}
In OnPaint function I have this below code
if (doc == null)
{
base.OnPaint(e);
return;
}
Rectangle pageRc = PageMediabox(1);
Rectangle screen = Transform(pageRc, 1, zoom, rotation, false);
Rectangle full = Transform(PageMediabox(1), 1, zoom, rotation, false);
full.Intersect(screen);
IntPtr page = ddjvu_page_create_by_pageno(doc, 1);
if (page == null )
{
base.OnPaint(e);
return;
}
int rotation4 = (((-rotation / 90) % 4) + 4) % 4;
ddjvu_page_set_rotation(page, (ddjvu_page_rotation_t)rotation4);
while (ddjvu_job_status(ddjvu_page_job(page)) >= ddjvu_status_t.DDJVU_JOB_OK)
SpinDdjvuMessageLoop(ctx, true);
if (ddjvu_job_status(ddjvu_page_job(page)) >= ddjvu_status_t.DDJVU_JOB_FAILED)
{
base.OnPaint(e);
return;
}
IntPtr fmt = ddjvu_format_create(ddjvu_format_style_t.DDJVU_FORMAT_BGR24, 0, (UIntPtr)null);
ddjvu_format_set_row_order(fmt, /* top_to_bottom */1);
ddjvu_rect_t prect = new ddjvu_rect_t(full.X, full.Y, (uint)full.Width, (uint)full.Height);
ddjvu_rect_t rrect = new ddjvu_rect_t(screen.X, 2 * full.Y + screen.Y + full.Height - screen.Height, (uint)screen.Width, (uint)screen.Height);
int stride = ((screen.Width * 3 + 3) / 4) * 4;
//byte tmp;
////ScopedMem<char> bmpData(SAZA(char, stride * (screen.dy + 5)));
//for (int y = 0; y < rrect.h; y++) {
// int step_y = y * SCREEN_WIDTH;
// for (int x=0; x < rrect.w; x++) {
// tmp = (byte)((imagebuf[x + step_y] >> 5) << 5);
// }
//}
int rowsize = mediaboxes[0].Width * 3;
int nSize = rowsize * (mediaboxes[0].Height) * 10;
unsafe
{
byte* buffer = (byte *)Memory.Alloc(nSize);
try
{
IntPtr ptr1 = (IntPtr)Memory.Alloc(Marshal.SizeOf(prect));
Marshal.StructureToPtr(prect, ptr1, false);
IntPtr ptr2 = (IntPtr)Memory.Alloc(Marshal.SizeOf(rrect));
Marshal.StructureToPtr(rrect, ptr2, false);
byte[] array = new byte[nSize];
fixed (byte* p = array) Memory.Copy(buffer, p, nSize);
ddjvu_page_render(page, ddjvu_render_mode_t.DDJVU_RENDER_MASKONLY, ptr1, ptr2, fmt, (ulong)stride, array);
}
finally
{
Memory.Free(buffer);
}
ddjvu_page_render should return arbitrary data of page which is to be rendered in a given rectangle area. Once after that I should be able to create image from arbitrary data & display in the screen
Here's how I would write the p/invoke:
[DllImport(dllname, CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern int ddjvu_page_render(
[In] IntPtr page,
[In] ddjvu_render_mode_t mode,
[In] ref ddjvu_rect_t pagerect,
[In] ref ddjvu_rect_t renderrect,
[In] ref ddjvu_format_t pixelformat,
[In] uint rowsize,
[Out] byte[] imagebuffer
);
Note that I've stopped using unsafe, and am letting the marshaler handle the structs automatically.
There are quite a few assumptions here that I cannot verify:
The calling convention. It might not be cdecl. The C++ header will would have the definitive answer.
The first parameter is a void* handle type, I presume.
ddjvu_render_mode_t is an enum that you have translated correctly.
The three ref parameters are structs, passed by reference. I cannot check that you have translated them correctly.
Calling this function would be something like this:
byte[] imagebuffer = new byte[nSize];
int retval = ddjvu_page_render(
page,
ddjvu_render_mode_t.DDJVU_RENDER_MASKONLY,
ref prect,
ref rrect,
ref fmt,
(uint)stride,
imagebuffer
);
if (retval != ??)
// handle error
This is quite a broad brush answer. I hope it points you in the right direction. I don't think that all your problems will be solved by this.

WINCODEC_ERR_WIN32ERROR 0x88982F94 when calling IWICComponentFactory.CreateBitmapFromMemory

I'm getting the following error when calling IWICComponentFactory.CreateBitmapFromMemory and passing it a pointer to Scan0 of a 32bppArgb GDI+ bitmap
WINCODEC_ERR_WIN32ERROR
0x88982F94
Windows Codecs received an error from the Win32 system.
IWICComponentFactory interface decl:
new IWICBitmap CreateBitmapFromMemory(
uint uiWidth,
uint uiHeight,
[MarshalAs(UnmanagedType.LPStruct)]
Guid pixelFormat,
uint cbStride,
uint cbBufferSize,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)]
byte[] pbBuffer
);
new IWICBitmap CreateBitmapFromMemory(
uint uiWidth,
uint uiHeight,
[MarshalAs(UnmanagedType.LPStruct)]
Guid pixelFormat,
uint cbStride,
uint cbBufferSize,
IntPtr pbBuffer
);
Full code:
public static IWICBitmap ToWic(IWICComponentFactory factory, Bitmap bit) {
BitmapData bd = bit.LockBits(new Rectangle(0, 0, bit.Width, bit.Height),
ImageLockMode.ReadOnly, bit.PixelFormat);
IWICBitmap b = null;
try {
//Create WIC bitmap directly from unmanaged memory
b = factory.CreateBitmapFromMemory((uint)bit.Width, (uint)bit.Height,
ConversionUtils.FromPixelFormat(bit.PixelFormat), (uint)bd.Stride,
(uint)(bd.Stride * bd.Height), bd.Scan0);
return b;
} finally {
bit.UnlockBits(bd);
}
}
Width, Height, buffer size, format GUID, and scan size all seem correct. I can't figure out why this is happening (there are no google results for the error code or message
This isn't an answer as to why the original code doesn't work - but it's a workaround. Using IWICImagingFactory_CreateBitmapFromMemory_Proxy , everything works fine. But why didn't the original work as it's supposed to? And why the _Proxy methods with near-identical signatures?
[DllImport("WindowsCodecs.dll", EntryPoint = "IWICImagingFactory_CreateBitmapFromMemory_Proxy")]
internal static extern int CreateBitmapFromMemory(IWICComponentFactory factory, uint width, uint height, ref Guid pixelFormatGuid, uint stride, uint cbBufferSize, IntPtr pvPixels, out IWICBitmap ppIBitmap);
public static IWICBitmap ToWic(IWICComponentFactory factory, Bitmap bit) {
Guid pixelFormat = ConversionUtils.FromPixelFormat(bit.PixelFormat);
if (pixelFormat == Guid.Empty) throw new NotSupportedException("PixelFormat " + bit.PixelFormat.ToString() + " not supported.");
BitmapData bd = bit.LockBits(new Rectangle(0, 0, bit.Width, bit.Height), ImageLockMode.ReadOnly, bit.PixelFormat);
IWICBitmap b = null;
try {
//Create WIC bitmap directly from unmanaged memory
long result = CreateBitmapFromMemory(factory, (uint)bit.Width,
(uint)bit.Height, ref pixelFormat, (uint)bd.Stride,
(uint)(bd.Stride * bd.Height), bd.Scan0, out b);
if (result == 0x80070057) throw new ArgumentException();
if (result < 0) throw new Exception("HRESULT " + result);
return b;
} finally {
bit.UnlockBits(bd);
}
}
For reference, here is the COM method and here is the proxy method. Both use [IN] BYTE *pbBuffer.