如何通过数值判断地址是合法的还是非法的?

时间:2014-01-05 04:13:04

标签: c++ c linux memory

我的意思是地址本身的数值,而不是它指向的值。 例如,如果地址是0x0,我们肯定知道它是非法的,但如果它是0xffffeeee234560,我怎么能告诉它是正常还是异常? 此外,如何知道此地址是属于文本段,还是数据段,堆或堆栈段?

我使用了pmap,cat /proc/id/smaps来查看是否有一些明确的规则,但是不能得到合理的方法,但只知道堆地址大于文本段,堆栈地址高于堆。

4 个答案:

答案 0 :(得分:2)

如果您正在调试程序(使用gcc -Wall -g编译),gdb调试器将告诉您某个地址是否非法。 还使用GCC 4.8(gcc -fsanitize=address)的valgrind和地址清理程序 ...

如果您希望程序内部知道某个特定地址是否在address space(运行您的程序的process)中以及它在哪个段中,您可以进行例行解析/proc/self/maps这样做。读取该文件(或来自proc(5)的其他文件...)非常快(因为这些文件不存在于磁盘上)。

通常没有文本,或数据单个堆栈(考虑multi-threaded应用程序和dynamic linking)在给定的进程中。地址空间中有几个段(运行程序的进程的地址空间),由于{{3},内核通常“随机”布局 }}。 (可以在系统范围内禁用ASLR)

但是,如果地址值在运行时对您的应用程序很重要(有时在地址中编码某些类型信息很有意思,即在一个段中分配对,在另一个段中分配三元组,在其他地方分配更大的对象),您应该采用相反的方法:使用ASLRmunmap(2)(由mmap(2)调用...)明确管理大内存段(例如,对齐到兆字节),当您保留段时,将它们注册到适当的容器中(例如C ++中的std::map)。然后你可以很容易地编写一个例程,给定一些任意地址(任何void*),得到包含它的段(或者nullptr)。不要忘记malloc可以被许多库例程(包括printf和C ++标准容器...)内部使用。因此,即使您不知道如何使用malloc也是如此。您可能会对posix_memalign(3)mallinfo(3)malloc_info(3)感兴趣。另请阅读mallopt(3)& C dynamic memory allocation wikipages,并根据需要研究malloc的源代码(memory management内的内容易于阅读)。

考虑阅读MUSL libc;它应该对你有帮助。

答案 1 :(得分:1)

无论是否绝对非法,代码的任何特定部分都是非法的,除非您知道,作为您获取该地址的合理结果,它是有效的并指向您可以合法修改的对象。

简而言之,如果你不得不问,这是非法的。

答案 2 :(得分:-1)

对于在Linux 32位中运行的用户进程,从0xc0000000向上的任何虚拟地址都是非法的,因为它属于内核。对于没有/3G启动开关的Windows 32位,任何等于或高于0x80000000的虚拟地址都是非法的,原因相同(如果使用/3G并且进程可执行文件具有LARGE_ADDRESS 1}}标志启用,边界与Linux中的地址相同

如果您无需离开Linux 32位,如果您能够浏览自己进程的页面目录,则可以获取任何虚拟地址,看看它是否映射到实际物理页面中的某个位置,如果是,则哪个该页面具有权限。

小心!因为用malloc()分配的内存当然是合法的,但是如果你试图通过剥离目录页来检查它的合法性,你会发现几乎所有分配的内存块都显示为“不存在”,因此你会推断出地址是非法的。当对块内的有效地址执行内存访问,并且该地址属于仍然不存在的页面时,会触发页面错误,但它不会成为段错误,但内核会静默分配实际内存来映射页面访问的地址所属的,并重新发出首先导致页面错误的指令。

使用合适的设备驱动程序,进程可以了解自己的内存映射并遍历其页面目录。当然,这是特定于实施的。有关详细信息,请参阅here

答案 3 :(得分:-2)

您可以在程序集中编写程序,在堆,堆栈,文本和数据段中存储一些值,然后获取这些值的地址并打印地址。

但是,这仅对该单个程序有效,并且可能在程序的不同运行中不一致。如果地址位于第一个和最后一个堆栈项的地址之间,则它应该是合法的,与第一个和最后一个文本项,第一个和最后一个数据项之间相同,等等。