char *a = "Peter"; char b[] = "Peter"; char *c = new char[6]; strcpy_s(c, 6, "Peter");
這裡a指向常量區
b指向棧區
c指向堆區
如果我們有這樣一個函數
void show(char *temp) { // // // }
我們如何判斷根據過來的temp的將這些區分出來呢?
1.我們可以首先將指向常量區的a區分出來
因為它所指向的地方是不可以修改的
判斷是否可以修改
a.使用函數IsBadReadPtr
函數原型如下
BOOL WINAPI IsBadWritePtr( _In_ LPVOID lp, _In_ UINT_PTR ucb );
lp:第一個字節的內存塊的指針。
ucb:指定的大小,單位為字節的內存塊。如果此參數為零,則返回值為零。
MSDN上部分的解釋如下
http://msdn.microsoft.com/en-us/library/windows/desktop/aa366716(v=vs.85).aspx
Verifies that the calling process has write access to the specified range of memory.
Important This function is obsolete and should not be used. Despite its name, it does not guarantee that the pointer is valid or that the memory pointed to is safe to use. For more information, see Remarks on this page.
翻譯(自己翻譯的):
驗證調用的進程是否可以寫入指定范圍的內存
主要的:這個函數是廢棄的,不應該被使用,不管它的名字,它不保證這個指向內存中的指針是合法的和這段內存是可以安全使用的,對於更多的信息,可以查看這頁的評論
示例:
bool isConst(void* pAddress, DWORD dwSize) { if (IsBadWritePtr(pAddress, dwSize)) return true; return false; } int main() { char *a = "Peter"; char b[] = "Peter"; char *c = new char[6]; strcpy_s(c, 6, "Peter"); cout << isConst(a,strlen(a))<< endl; cout << isConst(b, strlen(a)) << endl; cout << isConst(c, strlen(a)) << endl; system("pause"); }
結果
SIZE_T WINAPI VirtualQuery( _In_opt_ LPCVOID lpAddress, _Out_ PMEMORY_BASIC_INFORMATION lpBuffer, _In_ SIZE_T dwLength );
lpAddress:查詢內存的地址。
lpBuffer:指向MEMORY_BASIC_INFORMATION結構的指針,用於接收內存信息。
dwLength:MEMORY_BASIC_INFORMATION結構的大小。
MSDN上部分的解釋如下
http://msdn.microsoft.com/en-us/library/windows/desktop/aa366902(v=vs.85).aspx
Retrieves information about a range of pages in the virtual address space of the calling process.
檢索對於調用進程的虛擬內存中的頁的信息
用於接收的內存信息的MEMORY_BASIC_INFORMATION結構體定義如下
typedef struct _MEMORY_BASIC_INFORMATION { PVOID BaseAddress; PVOID AllocationBase; DWORD AllocationProtect; SIZE_T RegionSize; DWORD State; DWORD Protect; DWORD Type; } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
BaseAddress:保留區域的基地址
AllocationBase:分配的基地址
AllocationProtect:初次保留時所設置的保護屬性
RegionSize:區域大小
State:狀態(提交、保留或空閒)
Protect: 當前訪問保護屬性
Type:頁面類型
詳細請見MSDN
http://msdn.microsoft.com/en-us/library/windows/desktop/aa366775(v=vs.85).aspx
示例
bool isConst(void* pAddress) { _MEMORY_BASIC_INFORMATION mi = { 0 }; VirtualQuery(pAddress, &mi, sizeof(mi)); if (mi.Protect == PAGE_READONLY) { return true; } return false; } int main() { char *a = "Peter"; char b[] = "Peter"; char *c = new char[6]; strcpy_s(c, 6, "Peter"); cout << isConst(a)<< endl; cout << isConst(b) << endl; cout << isConst(c) << endl; system("pause"); }
結果
判斷是否位於棧上
參考了http://www.cppblog.com/weiym/archive/2012/05/12/174634.html
我們可以在函數內建一個位於棧的對象,然後獲得棧空間的初始地址,以及棧的最末尾的地址,就可以判斷一個東西是不是為與棧上了
VirtualQuery中用於接收內存信息_MEMORY_BASIC_INFORMATION結構體中有如下成員
BaseAddress:保留區域的基地址
RegionSize:區域大小
代碼示例
bool IsObjectOnStack(void* pObject) { int nStackValue(0); MEMORY_BASIC_INFORMATION mi = { 0 }; DWORD dwRet = VirtualQuery(&nStackValue, &mi, sizeof(mi)); if (dwRet > 0) { return pObject >= mi.BaseAddress && (DWORD)pObject < (DWORD)mi.BaseAddress + mi.RegionSize; } return FALSE; } int main() { char *a = "Peter"; char b[] = "Peter"; char *c = new char[6]; strcpy_s(c, 6, "Peter"); cout << IsObjectOnStack(a) << endl; cout << IsObjectOnStack(b) << endl; cout << IsObjectOnStack(c) << endl; system("pause"); }
運行結果
解釋:nStackValue是一個位於棧上的對象
我們針對它使用 VirtualQuery獲得相關的內存信息mi
mi.BaseAddress是棧的初始地址
(DWORD)mi.BaseAddress + mi.RegionSize是棧的最末尾的地址
我們只要判斷地址是不是在這二者之間,就可以判斷是不是位於棧上了