我的意思是地址本身的数值,而不是它指向的值。 例如,如果地址是0x0,我们肯定知道它是非法的,但如果它是0xffffeeee234560,我怎么能告诉它是正常还是异常? 此外,如何知道此地址是属于文本段,还是数据段,堆或堆栈段?
我使用了pmap,cat /proc/id/smaps
来查看是否有一些明确的规则,但是不能得到合理的方法,但只知道堆地址大于文本段,堆栈地址高于堆。
答案 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)
但是,如果地址值在运行时对您的应用程序很重要(有时在地址中编码某些类型信息很有意思,即在一个段中分配对,在另一个段中分配三元组,在其他地方分配更大的对象),您应该采用相反的方法:使用ASLR和munmap(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)
您可以在程序集中编写程序,在堆,堆栈,文本和数据段中存储一些值,然后获取这些值的地址并打印地址。
但是,这仅对该单个程序有效,并且可能在程序的不同运行中不一致。如果地址位于第一个和最后一个堆栈项的地址之间,则它应该是合法的,与第一个和最后一个文本项,第一个和最后一个数据项之间相同,等等。