Writing C + + and c# crash free programs under windows

C + + has good performance, but because of the direct operation of memory many times, the stability has not been very good. Before the program goes online, we certainly hope that the defects can be solved, but no one can guarantee that there are zero defects after the program goes online. How to ensure that the program crashes after the program goes online has always been a troublesome problem. To this end, I spent two days studying various exceptions of C + + and C #.

Handling of C + + memory abnormal crash

Abnormal judgment of field pointer

There is a function under windows that can detect whether the pointer is abnormal. In fact, the same linux has similar code to judge. This solution has a great impact on the code. Generally, some processing is added at the key code.

bool isBadPtr(void* p)
{
#ifdef WIN
    return IsBadReadPtr(p,4);//To judge the validity function of memory under windows, it should be noted that this function is valid only when it is executed in release
#else
   int fh = open( p, 0, 0 );
   int e = errno;

   if ( -1 == fh && e == EFAULT ) //Invalid memory;
   {
      return true;
   }
   else if ( fh != -1 )
   {
      close( fh );
   }
   return false;
}
#endif
}

void main()
{
    int* p=new int(3);
    delete p;
    if(isBadPtr(p))
    {
        std::cout<<"pointer is bad";
    }
    std::cout<<"check point faild";
}

SEH anomaly detection

SEH exception I have a similar description in previous articles. What we want to solve here is to use the common exception method of C + + to solve the exception detection of windows. There is a method in the API of windows to convert the exception of windows into unified C + + exception handling (the main thing is that sEH exception is a thread exception, and the exception conversion function needs to be used in the entry function executed by the thread).

#include <windows.h>
#include <iostream>
#include  <TChar.h>
//Inherit the basic exception class of C + +;
class seh_excpetion : std::exception
{
	typedef ULONG(WINAPI *fpRtlNtStatusToDosError)(NTSTATUS Status);

public:
	seh_excpetion(unsigned int nExceptionCode, _EXCEPTION_POINTERS* pstExcptionInfor) :
		m_nExceptionCode(0),
		m_pExcptionInfor(NULL),
		m_szMsgBuff(NULL),
		m_hNtModule(NULL),
		RtlNtStatusToDosError(NULL)
	{
		m_nExceptionCode = nExceptionCode;
		m_pExcptionInfor = pstExcptionInfor;
		m_hNtModule = GetModuleHandle(_T("NTDLL.DLL"));
		if (NULL != m_hNtModule)
		{
			RtlNtStatusToDosError = (fpRtlNtStatusToDosError)GetProcAddress(m_hNtModule, "RtlNtStatusToDosError");
		}
	}

	virtual ~seh_excpetion()
	{
		m_nExceptionCode = 0;
		m_pExcptionInfor = NULL;
		RtlNtStatusToDosError = NULL;

		if (NULL != m_szMsgBuff)
		{
			LocalFree(m_szMsgBuff);
			m_szMsgBuff = NULL;
		}
	};

	const char* what() const noexcept
	{
		if (RtlNtStatusToDosError != NULL)
		{
			DWORD nConvertLen = FormatMessageA(
				FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE,
				m_hNtModule,
				RtlNtStatusToDosError(m_nExceptionCode),
				0,
				(char*)&m_szMsgBuff,
				0,
				NULL);

			if (0 != nConvertLen)
			{
				return m_szMsgBuff;
			}
		}

		return "SEH_UNKNOW_ERROR";
	}

	const PEXCEPTION_POINTERS info() const
	{
		return m_pExcptionInfor;
	}

	const unsigned int code() const
	{
		return m_nExceptionCode;
	}

private:
	HMODULE m_hNtModule;

	unsigned int m_nExceptionCode;
	char* m_szMsgBuff;
	PEXCEPTION_POINTERS m_pExcptionInfor;
	fpRtlNtStatusToDosError RtlNtStatusToDosError;

public:
	static void(__cdecl TranslateSEHtoCE)(unsigned int nExceptionCode, struct _EXCEPTION_POINTERS* pstExcptionInfor)
	{
		throw seh_excpetion(nExceptionCode, pstExcptionInfor);
	}

};

//use

void main()
{
    //Call the transformation function in the entrance function.
    _set_se_translator(seh_excpetion::TranslateSEHtoCE);
    
    try{
       int*p=NULL;
       *p=3;
    }
    catch(...)
    {
       std::cout<<"program is catch!";
    }
}

Through the exception handling method, as long as we add the exception detection of try catch when the function executes the code, we can ensure that our program will not crash and solve the problem of instability after C + + release. You can use bugtrap or breakpad to collect stack information after releasing the program.

C # handles SEH exceptions.

Most of the exceptions of C # itself can be caught by the program. However, the exception handling of C # code under normal circumstances can not catch the memory exception of C + +. Of course, it is not a good thing to handle exceptions in a unified way under normal circumstances, but in some cases, it can at least prevent various crash problems on the customer site.
From the perspective of program security and stability, catch(Exception e) is indeed not a good programming habit. However, it is done. Since programmers can not be avoided from being lazy, Microsoft can only take some remedial measures. This is the role of CLR's new exception handling mechanism.
In net4 After 0, Microsoft naturally crashes this crash exception and will not be output as an exception capture, but it still retains the processing method of this piece.

//Consider making a C + + Crash function
void test()
{
    int*p=NULL;
    *p=3;
}
 static class Program
 {
     
     //Using dllimport to declare the method of C + +, I use swig to deal with it, so I won't explain the process of calling C + +, which doesn't belong to the focus of this article
    
        [STAThread]
        static void Main()
        {
            try
            {
                test();
            }
            catch (Exception e)
            {
            
            }
        }
 };

The above code can't be captured by 100%, because Microsoft doesn't handle this exception by default. We need to use the app Add legacycorruptedstateexceptions policy setting in config to make the above exception handler take effect

After adding the above settings, you can solve the c# capture C + + memory error. Of course, if you don't want to set global settings, you can also add an annotation in the c# method, as shown in

 static class Program
 {
     
        //Memory exception is only valid for this method.
        [HandledProcessCorruptedStateExceptions] 
        static void Main()
        {
            try
            {
                test();
            }
            catch (Exception e)
            {
            
            }
        }
 };

It should be noted that if the code does not capture exceptions, the system error prompt box will appear, indicating whether to continue if an exception is encountered. As follows:

Tags: C++ C# Windows

Posted by kol090 on Mon, 11 Apr 2022 03:53:58 +0300