mat*_*ath 58 c iso segmentation-fault
我认为问题就是这么说的.涵盖从C89到C11的大多数标准的示例将是有帮助的.我虽然这个,但我猜它只是未定义的行为:
#include <stdio.h>
int main( int argc, char* argv[] )
{
const char *s = NULL;
printf( "%c\n", s[0] );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编辑:
正如一些投票要求澄清:我希望有一个程序通常有编程错误(我能想到的最简单的是段错误),这是保证(按标准)中止.这与最小的段错误问题有点不同,它不关心这种保险.
msa*_*sam 100
raise() 可用于引发段错误:
raise(SIGSEGV);
Run Code Online (Sandbox Code Playgroud)
Sha*_*our 68
分段错误是实现定义的行为.该标准没有定义实现应如何处理未定义的行为,实际上,实现可以优化未定义的行为并且仍然是合规的.需要明确的是,实现定义的行为是标准未指定但行为应该记录的行为.未定义的行为是不可移植或错误的代码,其行为是不可预测的,因此无法依赖.
如果我们看一下C99草案标准 §3.4.3 未定义的行为,它在第1段的条款,定义和符号部分中说明(强调我的未来):
使用不可移植或错误的程序结构或错误数据时的行为,本国际标准不对此要求
并在第2段中说:
注意可能的未定义行为包括完全忽略具有不可预测结果的情况,在转换或程序执行期间以环境特征(有或没有发出诊断消息)的特定文档执行,终止转换或执行(使用发布诊断消息).
另一方面,如果您只是想要在标准中定义的方法在大多数类Unix系统上导致分段错误,那么raise(SIGSEGV)应该实现该目标.严格来说,SIGSEGV虽然定义如下:
SIGSEGV无效访问存储
和§7.14 信号处理<signal.h>说:
实现不需要生成任何这些信号,除非显式调用raise函数.实现还可以指定附加信号和指向不可响应函数的指针,其中宏定义分别以字母SIG和大写字母或SIG_和大写字母219开始.完整的信号集,它们的语义和默认处理是实现定义的 ; 所有信号编号均为正数.
Nik*_* C. 17
该标准仅提及未定义的行为.它对内存分段一无所知.另请注意,产生错误的代码不符合标准.您的代码无法同时调用未定义的行为并且符合标准.
尽管如此,最短的方式,对我们的体系结构分割故障做产生这种故障是:
int main()
{
*(int*)0 = 0;
}
Run Code Online (Sandbox Code Playgroud)
为什么这肯定会产生段错误?因为对内存地址0的访问总是被系统捕获; 它永远不会是有效的访问(至少不是用户空间代码.)
当然,请注意并非所有体系结构都以相同的方式工作.在其中一些,上面根本不会崩溃,而是产生其他类型的错误.或者声明可以非常好,甚至,内存位置0可以访问得很好.这是标准实际上没有定义发生的事情的原因之一.
Ker*_* SB 12
正确的程序不会产生段错误.而且您无法描述错误程序的确定性行为.
"分段错误"是x86 CPU所做的事情.你通过尝试以不正确的方式引用内存来获得它.它还可以指内存访问导致页面错误(即尝试访问未加载到页表中的内存)的情况,并且操作系统决定您无权请求该内存.要触发这些条件,您需要直接为您的操作系统和硬件编程.它不是C语言指定的.
如果我们假设我们没有提出信号调用 raise,则分段错误可能来自未定义的行为.未定义的行为是未定义的,并且编译器可以自由拒绝转换,因此在所有实现上都不会保证未定义的答案都会失败.此外,调用未定义行为的程序是错误的程序.
但是,这一个是最短的,我可以得到在该段错误我的系统:
main(){main();}
Run Code Online (Sandbox Code Playgroud)
(我用gcc和编译-std=c89 -O0).
顺便说一下,这个程序真的引用了未定义的bevahior吗?
main;
Run Code Online (Sandbox Code Playgroud)
就是这样。
真的。
本质上,它的作用是将其定义main为变量。在C中,变量和函数都是符号——内存中的指针,因此编译器不会区分它们,并且这段代码不会抛出错误。
然而,问题在于系统如何运行可执行文件。简而言之,C 标准要求所有 C 可执行文件都内置一个环境准备入口点,这基本上可以归结为“调用main”。
然而,在这种特殊情况下,main是一个变量,因此它被放置在称为 的内存的不可执行.bss部分中,用于变量(而不是.text代码)。尝试执行代码.bss违反了其特定的分段,因此系统会抛出分段错误。
objdump为了说明这一点,这是结果文件的(部分) :
# (unimportant)
Disassembly of section .text:
0000000000001020 <_start>:
1020: f3 0f 1e fa endbr64
1024: 31 ed xor %ebp,%ebp
1026: 49 89 d1 mov %rdx,%r9
1029: 5e pop %rsi
102a: 48 89 e2 mov %rsp,%rdx
102d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
1031: 50 push %rax
1032: 54 push %rsp
1033: 4c 8d 05 56 01 00 00 lea 0x156(%rip),%r8 # 1190 <__libc_csu_fini>
103a: 48 8d 0d df 00 00 00 lea 0xdf(%rip),%rcx # 1120 <__libc_csu_init>
# This is where the program should call main
1041: 48 8d 3d e4 2f 00 00 lea 0x2fe4(%rip),%rdi # 402c <main>
1048: ff 15 92 2f 00 00 callq *0x2f92(%rip) # 3fe0 <__libc_start_main@GLIBC_2.2.5>
104e: f4 hlt
104f: 90 nop
# (nice things we still don't care about)
Disassembly of section .data:
0000000000004018 <__data_start>:
...
0000000000004020 <__dso_handle>:
4020: 20 40 00 and %al,0x0(%rax)
4023: 00 00 add %al,(%rax)
4025: 00 00 add %al,(%rax)
...
Disassembly of section .bss:
0000000000004028 <__bss_start>:
4028: 00 00 add %al,(%rax)
...
# main is in .bss (variables) instead of .text (code)
000000000000402c <main>:
402c: 00 00 add %al,(%rax)
...
# aaand that's it!
Run Code Online (Sandbox Code Playgroud)
PS:如果您编译为平面可执行文件,这将不起作用。相反,您将导致未定义的行为。
| 归档时间: |
|
| 查看次数: |
17127 次 |
| 最近记录: |