Windows下面就不多说了:IsBadReadPtr,IsBadStringPtr,IsBadWritePtr。
Linux内核态可以用__access_ok函数来判断内存区域的访问性。
用户态自己写了一个,就是利用了段错误这个信号,然后处理这个信号。用siglongjmp和sigsetjmp在栈里面跳转。
直接Posix族的代码贴出来,应该还有一些小bug,有待继续完善
只把读取权限的写了,别的同理
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>
/*
x86/Linux、x86/Solaris、SPARC/Solaris will sigal SIGSEGV
x86/FreeBSD、x86/NetBSD、x86/OpenBSD MacOS will sigal SIGBUS
*/
#if defined(__MACH__) && defined(__FreeBSD__) && defined(__NetBSD__) && defined(__OpenBSD__)\
&& defined(__DragonFly__)
#define ERROR_SIGNAL SIGBUS
#else
#define ERROR_SIGNAL SIGSEGV
#endif
static sigjmp_buf badreadjmpbuf;
static void badreadfunc(int signo)
{
/*write(STDOUT_FILENO, "catch\n", 6);*/
siglongjmp(badreadjmpbuf, 1);
}
int isbadreadptr(void *ptr, int length)
{
struct sigaction sa, osa;
int ret = 0;
/*init new handler struct*/
sa.sa_handler = badreadfunc;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
/*retrieve old and set new handlers*/
if(sigaction(ERROR_SIGNAL, &sa, &osa)<0)
return (-1);
if(sigsetjmp(badreadjmpbuf, 1) == 0)
{
int i, hi=length/sizeof(int), remain=length%sizeof(int);
int* pi = ptr;
char* pc = (char*)ptr + hi;
for(i=0;i<hi;i++)
{
int tmp = *(pi+i);
}
for(i=0;i<remain;i++)
{
char tmp = *(pc+i);
}
}
else
{
ret = 1;
}
/*restore prevouis signal actions*/
if(sigaction(ERROR_SIGNAL, &osa, NULL)<0)
return (-1);
return ret;
}
int main()
{
int *p = 0;
int flag;
int testint = 1234567890, *teststack = &testint;
int * testheap = malloc(sizeof(int) * 10);
printf("bad ptr %d\n", isbadreadptr(p, 4));
printf("bad ptr %d\n", isbadreadptr(teststack, 4));
printf("bad ptr %d\n", isbadreadptr(testheap, 40));
free(testheap);
printf("exiting main\n");
return 0;
}