C에서 Seg fault를 생성하는 가장 간단한 표준 적합 방법은 무엇입니까?
질문이 모든 걸 말해주는 것 같아요.C89부터 C11까지의 대부분의 표준을 다루는 예가 도움이 될 것이다.이런 것도 생각했지만, 그건 그냥 정의되지 않은 행동일 뿐인 것 같아요.
#include <stdio.h>
int main( int argc, char* argv[] )
{
const char *s = NULL;
printf( "%c\n", s[0] );
return 0;
}
편집:
일부 투표가 해명을 요구함에 따라:통상적인 프로그래밍 에러(세그 폴트라고 생각할 수 있는 가장 간단한 프로그램)가 중단되는 것을 보증하고 싶었다.이것은 이 보험에 관심이 없는 최소한의 세그먼트 폴트 질문과는 조금 다릅니다.
raise()
fault: seg fault는 seg fault를 발생시키기 위해 사용할 수 있습니다.
raise(SIGSEGV);
세그멘테이션 장애는 구현 정의 동작입니다.이 표준에서는 구현이 정의되지 않은 동작을 처리하는 방법을 정의하지 않습니다.실제로 구현은 정의되지 않은 동작을 최적화하면서 규정을 준수할 수 있습니다.명확하게 말하면, 실장 정의 동작은 표준에서 규정되어 있지 않지만 실장에서는 문서화해야 하는 동작입니다.정의되지 않은 동작은 비포터블 또는 오류이며 동작이 예측 불가능하기 때문에 신뢰할 수 없는 코드입니다.
제1항의 용어, 정의 및 기호 섹션 아래에 있는 C99 초안 표준 §3.4.3의 정의되지 않은 행동을 보면 (강조광산)이라고 되어 있다.
본 국제표준이 요건을 부과하지 않는, 포터블하지 않거나 잘못된 프로그램 구성 또는 잘못된 데이터 사용 시 행동
제2항에는 다음과 같이 기술되어 있다.
주 가능한 정의되지 않은 동작은 상황을 완전히 무시하고 예측할 수 없는 결과를 발생시키는 것부터 번역 또는 프로그램 실행 중에 환경 특유의 문서화된 방식으로 동작하는 것(진단 메시지 발행 여부에 관계없이), 번역 또는 실행을 종료하는 것(진단 메시지 발행 시)까지 다양하다.에시지)
한편, 표준으로 정의되어 대부분의 Unix 유사 시스템에서 세그멘테이션 장애를 일으키는 방법을 원할 경우,raise(SIGSEGV)
그 목표를 달성해야 합니다.엄밀히 말하면SIGSEGV
는 다음과
SIGSEGV가 스토리지에 대한 잘못된 액세스입니다.
및 § 7.14 신호처리는 다음과 같이 말한다.
실장에서는, 레이즈 함수에의 명시적인 콜의 결과를 제외하고, 이러한 신호를 생성할 필요는 없습니다.매크로 정의가 각각 문자 SIG 및 대문자 또는 문자 SIG_ 및 대문자, 219)로 시작되는 언클래어블 함수에 대한 추가 신호 및 포인터도 구현에 의해 지정될 수 있다.신호의 전체 세트, 그 의미론 및 기본 처리는 구현 정의되며, 모든 신호 번호는 양수여야 합니다.
표준에서는 정의되지 않은 동작만 언급하고 있습니다.메모리 분할에 대해서는 아무것도 모릅니다.또, 에러를 발생시키는 코드는 표준 규격에 준거하고 있지 않습니다.코드는 정의되지 않은 동작을 호출하는 동시에 표준 적합성을 가질 수 없습니다.
그럼에도 불구하고 이러한 장애를 생성하는 아키텍처에서 분할 장애를 생성하는 가장 빠른 방법은 다음과 같습니다.
int main()
{
*(int*)0 = 0;
}
이것이 seg fault를 발생시키는 것이 확실한 이유는 무엇입니까?메모리 주소0 에의 액세스는 항상 시스템에 의해서 트랩 되기 때문에, 유효한 액세스일 수 없습니다(최소한 유저 스페이스 코드에 의해서만 액세스 할 수 없습니다.
물론 모든 아키텍처가 동일한 방식으로 작동하는 것은 아닙니다.이들 중 일부에서는 위의 오류가 전혀 발생하지 않고 오히려 다른 종류의 오류가 발생할 수 있습니다.또는 이 문장은 완전히 양호할 수 있으며 메모리 위치 0은 정상적으로 액세스 할 수 있습니다.그 기준이 실제로 무슨 일이 일어나는지 정의하지 않는 이유 중 하나입니다.
올바른 프로그램을 사용해도 segfault가 생성되지 않습니다.그리고 당신은 잘못된 프로그램의 결정론적 행동을 설명할 수 없습니다.
"세그멘테이션 장애"는 x86 CPU에서 발생하는 장애입니다.잘못된 방법으로 메모리를 참조하려고 하면 얻을 수 있습니다.또, 메모리 액세스에 의해서 페이지 장해가 발생해(페이지 테이블에 로드되어 있지 않은 메모리에 액세스 하려고 하는 경우), OS 로부터 그 메모리를 요구할 권리가 없다고 판단되는 상황을 가리킬 수도 있습니다.이러한 상황을 발생시키려면 OS와 하드웨어에 대해 직접 프로그래밍해야 합니다.C언어로 지정되어 있는 것은 없습니다.
raise
세그멘테이션 장애는 정의되지 않은 동작에서 발생할 수 있습니다.정의되지 않은 동작은 정의되지 않았으며 컴파일러는 번역을 거부할 수 있으므로 정의되지 않은 응답은 모든 구현에서 실패할 수 없습니다.게다가 정의되지 않은 동작을 호출하는 프로그램은 잘못된 프로그램입니다.
그러나 이것이 시스템상의 세그먼트 폴트를 취득할 수 있는 가장 짧은 방법입니다.
main(){main();}
(는 (컴파대대)와 함께 gcc
★★★★★★★★★★★★★★★★★」-std=c89 -O0
를 참조해 주세요.
그나저나, 이 프로그램이 정말 정의되지 않은 베바히어를 불러내나요?
main;
바로 그겁니다.
정말로.
이것은 '', '이것', '이것', '이것', '이것', '이것', '이것',main
변수로써.C에서 변수와 함수는 모두 기호입니다.메모리의 포인터이기 때문에 컴파일러는 그것들을 구별하지 않고, 이 코드는 에러를 발생시키지 않습니다.
그러나 문제는 시스템에서 실행 파일을 실행하는 방식에 있습니다.한마디로 C표준은 모든 C실행파일에 환경준비 엔트리 포인트가 내장되어 있어야 하며 이는 기본적으로 "call"로 요약됩니다.main
이 에는 " " " 입니다.main
변수이기 때문에 메모리 내의 "non-templacable" 섹션에 배치됩니다..bss
).text
★★★★★★★★★★★★★★★★★★★★★」..bss
특정 분할을 위반하므로 시스템이 분할 오류를 발생시킵니다.
를 들면, 여기 예 to, to, '일부'가 요.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!
PS: 플랫 실행 파일로 컴파일하면 동작하지 않습니다.대신 정의되지 않은 동작이 발생합니다.
플랫폼에 따라서는 표준 준거의 C 프로그램이 시스템으로부터 너무 많은 자원을 요구하면 세그멘테이션 장애와 함께 장애가 발생할 수 있습니다.를 들어 큰 에 ""를 malloc
성공한 것처럼 보일 수 있지만 나중에 개체에 액세스하면 개체가 충돌합니다.
이러한 프로그램은 엄밀하게 준거하고 있지 않습니다.이 정의에 부합하는 프로그램은 각각의 최소 구현 제한 범위 내에 있어야 합니다.
다른 방법은 정의되지 않은 동작을 통해서만 가능하기 때문에 표준 준거 C 프로그램은 그렇지 않으면 분할 장애를 생성할 수 없습니다.
SIGSEGV
은 명시적으로 수 만, 「」는 .SIGSEGV
【C】【C】【C】【C】【C】【C】【C】▼】
(이 답변에서 '표준 적합'이란 다음과 같은 의미를 갖습니다.ISO C 표준의 일부 버전에서 기술된 기능만을 사용하여 지정되지 않은 동작, 구현 정의되지 않은 동작 또는 정의되지 않은 동작을 방지합니다.단, 반드시 최소 구현 제한에만 국한되는 것은 아닙니다.")
최소 글자 수를 고려하는 가장 간단한 형식은 다음과 같습니다.
++*(int*)0;
이 질문에 대한 대부분의 답변은 다음과 같은 핵심 사항에 대해 이야기하고 있습니다.C 표준에는 세그멘테이션 장애의 개념은 포함되어 있지 않습니다(C99이므로 신호 번호가 포함되어 있습니다). SIGSEGV
「」를 제외하고, 그 되어 있지 않습니다.raise(SIGSEGV)
(다른 답변에서 설명한 바와 같이 이는 반영되지 않습니다.)
따라서 세그먼트화 결함을 발생시킬 수 있는 "엄밀하게 일치하는" 프로그램(즉, C 표준에 의해 완전히 정의된 동작을 가진 구성 요소만 사용하는 프로그램)은 없습니다.
분할 결함은 다른 표준인 POSIX에 의해 정의됩니다.이 프로그램은 분할 결함 또는 기능적으로 동등한 "버스 오류"를 유발할 수 있습니다.SIGBUS
.1-2008 에의 이 POSIX.1-2008 에의 콜([메모리 보호(Memory Protection)])인 [ 보호(Memory Protection)] 및 [메모리 보호(옵션을 에 하고 있는 .【어드밴스드밴스드밴스드 리얼타임】옵션 포함)에 대해서는, 다음의 콜을 실시합니다.sysconf
,posix_memalign
★★★★★★★★★★★★★★★★★」mprotect
성공하다C99의 필자는 이 프로그램은 그 표준만을 고려하여 구현 정의(정의되지 않음!)된 동작을 가지고 있기 때문에 적합하지만 엄밀하게 적합하지는 않다고 생각합니다.
#define _XOPEN_SOURCE 700
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(void)
{
size_t pagesize = sysconf(_SC_PAGESIZE);
if (pagesize == (size_t)-1) {
fprintf(stderr, "sysconf: %s\n", strerror(errno));
return 1;
}
void *page;
int err = posix_memalign(&page, pagesize, pagesize);
if (err || !page) {
fprintf(stderr, "posix_memalign: %s\n", strerror(err));
return 1;
}
if (mprotect(page, pagesize, PROT_NONE)) {
fprintf(stderr, "mprotect: %s\n", strerror(errno));
return 1;
}
*(long *)page = 0xDEADBEEF;
return 0;
}
정의되지 않은 플랫폼에서 프로그램의 오류를 분할하는 방법을 정의하는 것은 어렵습니다.세그멘테이션 장애는 모든 플랫폼(단순한 소형 컴퓨터 등)에 대해 정의되지 않은 느슨한 용어입니다.
프로세스를 지원하는 운영 체제만 고려할 때 프로세스는 세그멘테이션 장애가 발생했음을 알릴 수 있습니다.
like으로, 높은 은, operating system의 「unix like」입니다.OS로 한정하는 것으로써, 프로세스가 SIGSEGV 신호를 수신하는 신뢰성 높은 방법은 다음과 같습니다.kill(getpid(),SIGSEGV)
대부분의 크로스 플랫폼 문제에서와 마찬가지로 각 플랫폼에서는 세그먼트 장애의 정의가 다를 수 있습니다.
그러나 현실적으로 현재 mac, lin 및 win OS는 segfault가 있습니다.
*(int*)0 = 0;
게다가 세그먼트 폴트를 발생시키는 것도 나쁘지 않습니다.「 」의 assert()
SIGSEGV는 SIGSEGV를 사용합니다.부검이 필요할 때 유용하게 쓰입니다.
seg fault를 일으키는 것보다 더 나쁜 것은 그것을 숨기는 것입니다.
try
{
anyfunc();
}
catch (...)
{
printf("?\n");
}
에러의 원인을 숨기고, 다음의 조작만 실시하면 됩니다.
?
.
언급URL : https://stackoverflow.com/questions/18986351/what-is-the-simplest-standard-conform-way-to-produce-a-segfault-in-c
'source' 카테고리의 다른 글
Vuex 개체를 비울 때 Vue 프로젝트에서 정의되지 않은 오류를 방지하려면 어떻게 해야 합니까? (0) | 2022.08.18 |
---|---|
C에서 복잡한 프로젝트를 어떻게 구조화하면 좋을까요? (0) | 2022.08.16 |
vue 인스턴스(app1)에 대한 가장 좋은 방법은 다른 vue 인스턴스(app2)를 호출하는 것입니다. (0) | 2022.08.16 |
Java에서의 범용 삭제의 개념은 무엇입니까? (0) | 2022.08.16 |
Windows OS용 OpenJDK 가용성 (0) | 2022.08.16 |