NASM调用_malloc后内存越界写入未触发段错误的原因咨询
问题:macOS下NASM调用C库_malloc越界写入未触发段错误
我在macOS系统下使用NASM编写汇编代码,尝试调用C库的_malloc进行动态内存分配,目标是分配10字节内存,但发现向分配块外写入数据时,程序并未触发segfault(段错误)。
我最初尝试按Christopher Swenson的方式将大小压入栈中传参,之后参考较新资料将大小存入rdi寄存器,最终采用了后者的方式。以下是测试代码:
extern _malloc ;; malloc from the C library section .text global _start _start: xor rdi, rdi mov rdi, 10 ;; 尝试分配10字节 call _malloc ;; 返回的地址存在rax中 mov qword [rax], 1 ;; 向合法区域写入数据 add rax, 11 ;; 偏移到分配块外 mov qword [rax], 1 ;; 向非法区域写入数据,但未触发错误 mov rax, 0x2000001 mov rdi, 0 syscall
为简化操作,我未对返回值rax是否为NULL进行校验。编译命令如下:
$ nasm -f macho64 -o test.o test.asm $ gcc -e _start test.o -lc -m64 -o a.out -Wl,-no_pie
恳请解释我是否正确使用了_malloc,或是为何越界写入未触发段错误?
回答
1. 你对_malloc的调用是正确的
macOS的64位环境采用System V AMD64调用约定,第一个参数通过rdi寄存器传递,所以你将分配大小10存入rdi后调用_malloc的写法完全符合规范。之前压栈传参的方式属于32位或者旧的调用约定,不适用于64位macOS,你改用寄存器传参的选择是对的。
2. 越界写入未触发段错误的原因
这是malloc内存分配机制的正常现象,核心原因有两点:
- 内存块的额外分配与对齐:macOS的
malloc实现(底层是libmalloc)不会严格只分配你请求的字节数。为了满足内存对齐要求(通常是16字节或更大粒度)、维护内存块的管理元数据(比如块大小、分配状态等头部信息),以及减少频繁分配的开销,它会分配比你请求更大的内存块。你这里偏移11字节后写入,大概率还在这些额外分配的、属于当前进程的内存空间内,没有触及虚拟内存的页边界。 - 段错误的触发条件:段错误只有当进程访问了不属于自己的虚拟内存页时才会触发。malloc分配的内存块周围的额外空间仍然属于当前进程的地址空间,所以写入时不会立刻触发错误,但这种行为属于未定义行为——后续可能会破坏其他内存块的元数据或者覆盖其他变量,导致程序在后续操作中崩溃,只是没在你写入的瞬间显现。
如果想验证,可以尝试更大的偏移量,比如add rax, 1024后再写入,此时大概率会触发段错误,因为已经超出了malloc为该块额外分配的空间范围。
内容的提问来源于stack exchange,提问作者wartonbega
相关产品推荐
相关产品推荐

