程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> SEH 的應用:實現安全的內存操作

SEH 的應用:實現安全的內存操作

編輯:.NET實例教程

使用SEH(結構化異常處理),可以使程序結構看起來更清晰 ,更安全。根據經驗發現至少90%的程序崩潰都是因為訪問了沒有讀寫權限的內存區域(比如
在Windows中的內核區域0x80000000-0xFFFFFFFF)和沒有提交物理內存或者沒有保留的區域(比如空指針區域0x00000000 開始的64kb)。
在很多筆試/面試考試中,對內存的考察幾乎都是通過讓面試者寫一個strcpy函數,下面這個是給出了滿分的標准答案:
(注:http://tech.163.com/06/0628/09/2KMP8QP60009159Q.Html)

char* strcpy(char *strDest, const char *strSrc )
{
 assert((strDest != NULL)&&(strSrc!=NULL));
 char *address = strDest;
 while((*strDest++ = * strSrc++)!='\0');
 return address;
}

這個就是滿分的標准答案了,先檢查 strDest,strSrc 是否是 0 指針,很好。可是,是不是所有不為0的地址都能夠訪問呢?看看這個測試:
void test()
{
 char* buf;
 strcpy(buf,"Welcome!\n");
}

這個可能是初學者最容易搞錯的現象之一了,局部變量 buf 可能為隨機的一個數,然後調用strcpy,assert 沒有檢查出來,運行的結果就是Windows
提示非法操作(用戶可能是最討厭這個的了,感覺就是系統壞了似的),進程被強制結束。

在Windows中的內核區域0x80000000-0xFFFFFFFF)和沒有提交物理內存或者沒有保留的區域(比如空指針區域0x00000000 開始的64kb,這些都是絕對不
能訪問的。那麼我們怎麼檢查這類錯誤了?再說上面的 assert 也只能檢查到debug版本的設計錯誤,在release版本下這句就被忽略掉了。所以是不
全面的,不可靠的。

Windows提供了SEH機制,可以檢測到任何內存方面的錯誤(當然不僅是內存方面的,還有很多)。其實在Visual C++ 中自實現一組關鍵字實現SEH,
(__try __except )。下面是改進版(很簡單的,就不多說了):

char* safe_strcpy(char *strDest, const char *strSrc )
{
 char *address = strDest;
 __try
 {
  while((*strDest++ = * strSrc++)!='\0');
 }
 __except(EXCEPTION_EXECUTE_HANDLER)
 {
  char err_info[1024];
  sprintf_s(err_info,sizeof(err_info),"調用文件%s,第%d行 char* safe_strcpy(char *strDest=%.8X, const char *strSrc=%.8X) 函數失敗\n",
   __FILE__,__LINE__,strDest,strSrc);
  OutputDebugStringA(err_info);printf(err_info);
 }
 return address;
}

同上,像其他內存操作函數,也可以這麼做。留給大家了。 

注:

群裡有人說使用這種機制可能會帶來性能上的開銷。

我可以告訴大家,建立SEH幀的開銷是很小的。

大家說的開銷大可能是基於這樣的考慮:每次讀寫都要檢測相應的內存塊的讀寫屬性。

其實這點是由硬件--處理器來完成的,就算是你沒有檢查,操作系統也會做的,當然,你懶惰的結果就是程序崩潰。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved