# 내 세그멘테이션 오류는 어디로 사라졌나?

> Clean Markdown view of GeekNews topic #31359. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=31359](https://news.hada.io/topic?id=31359)
- GeekNews Markdown: [https://news.hada.io/topic/31359.md](https://news.hada.io/topic/31359.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2026-07-13T04:01:12+09:00
- Updated: 2026-07-13T04:01:12+09:00
- Original source: [rmpr.xyz](https://rmpr.xyz/Where-did-my-segfault-go/)
- Points: 1
- Comments: 1

## Topic Body

- `entr`로 C 프로그램을 반복 컴파일·실행하자 `hello`가 비정상 종료됐지만, 컴파일 출력 뒤에 **`Segmentation fault` 메시지가 나타나지 않음**
- 이 메시지는 충돌한 프로그램이 아니라, 자식 프로세스를 회수하며 `SIGSEGV` 종료를 확인한 **부모 셸**이 출력함
- `bash -c`를 명시해도 남은 명령이 사실상 하나뿐이면 Bash가 새 프로세스를 만들지 않고 **`execve`로 자신을 교체**할 수 있어 메시지를 출력할 부모 셸이 사라짐
- 별도 스크립트에서는 shebang으로 시작된 Bash가 `./hello`를 자식으로 실행하고 기다리므로, `SIGSEGV`를 확인해 **`Segmentation fault (core dumped)`** 를 출력함
- `./hello`를 **서브셸** `(./hello)`에서 실행하거나 뒤에 `; true`를 추가해 후속 작업을 남기면 `exec` 최적화를 막고 오류 메시지를 확인할 수 있음

---

### 메시지가 사라진 실행 경로
- 다음 [`entr`](https://eradman.com/entrproject/) 명령으로 `hello.c`가 바뀔 때마다 컴파일과 실행을 반복함
  ```sh
  ls hello.c | entr -s "gcc -o hello hello.c && ./hello"
  ```
- `hello`가 세그멘테이션 오류로 종료됐지만 `Segmentation fault` 메시지나 눈에 보이는 0이 아닌 종료 상태 없이 **아무 출력도 남지 않음**
- `bash -c`로 명령을 감싸도 결과는 같았음
  ```sh
  ls hello.c | entr -s "bash -c 'gcc -o hello hello.c && ./hello'"
  ```
- 반면 같은 명령을 `run.sh`로 옮겨 실행하면 오류가 표시됨
  ```sh
  #!/bin/bash
  gcc -o hello hello.c && ./hello
  ```
  ```sh
  ls hello.c | entr -s ./run.sh
  ./run.sh: line 2: 104465 Segmentation fault (core dumped) ./hello
  ```

- ## `Segmentation fault`를 출력하는 주체
  - 충돌한 프로그램은 이미 종료된 상태이며, **부모 셸이 자식 프로세스를 회수**하면서 `SIGSEGV`로 죽었다는 사실을 확인한 뒤 메시지를 출력함
  - 따라서 메시지를 출력할 부모 셸이 남아 있지 않으면 아무것도 나타나지 않음
  - Bash는 `bash -c "some_command"`에서 실행할 일이 사실상 해당 명령뿐이면 새 프로세스를 포크하지 않고 [`execve`로 자신을 교체](https://cgit.git.savannah.gnu.org/cgit/bash.git/tree/execute_cmd.c?id=ecb2456d6357bfd3b2965aafe2f2021d1ced5b72#n5827)할 수 있음
  - 이 최적화는 대부분의 실행에서는 외부로 드러나지 않음
  - 스크립트 방식에서는 `entr`가 `./run.sh`를 자식으로 실행하고, shebang이 새 Bash를 시작함
  - 새 Bash는 `gcc` 실행 후 `./hello`를 포크하고 기다리므로, 자식의 `SIGSEGV` 종료를 확인해 오류 메시지를 남길 수 있음

### 부모 셸을 남기는 두 가지 방법
- 충돌하는 명령을 **서브셸**에서 실행하면 메시지가 다시 나타남
  ```sh
  ls hello.c | entr -s "gcc -o hello hello.c && (./hello)"
  hello.c: line 1: 106595 Segmentation fault (core dumped) ( ./hello )
  ```
  - 괄호는 `./hello`가 포크된 서브셸에서 실행되도록 강제함
  - Bash가 부모 역할을 유지하므로 서브셸의 `SIGSEGV` 종료를 회수해 메시지를 출력할 수 있음
- 충돌 명령 뒤에 실행할 작업을 남겨도 **`exec` 최적화**를 막을 수 있음
  ```sh
  ls hello.c | entr -s "bash -c 'gcc -o hello hello.c && ./hello; true'"
  bash: line 1: 109516 Segmentation fault (core dumped) ./hello
  ```
  - `; true` 때문에 Bash는 `./hello`가 끝난 뒤에도 할 일이 남아 있어 자신을 해당 프로그램으로 교체하지 않음
  - 별도 래퍼 스크립트 없이도 세그멘테이션 오류 메시지를 확인할 수 있음

## Comments



### Comment 61672

- Author: neo
- Created: 2026-07-13T04:01:13+09:00
- Points: 1

###### [Lobste.rs 의견들](https://lobste.rs/s/tedtzz/where_did_my_segfault_go) 
- 최신 Linux 배포판은 기본적으로 **코어 덤프를 비활성화**해 둬서 곤란할 때가 많음  
  `ulimit -c unlimited`로 다시 활성화할 수 있지만, 코어 파일이 실행 파일과 같은 디렉터리에 생기지도 않는 듯하며 systemd가 어딘가로 옮기는 것 같음  
  OpenBSD처럼 코어 덤프를 기본으로 활성화하고 실행 파일과 같은 디렉터리에 두면 좋겠는데, 지금은 충돌이 발생하면 대개 실행 파일을 gdb 안에서 다시 실행해야 함
  - systemd에서는 **`coredumpctl`** 로 최근 코어 덤프를 나열하고 가져올 수 있음
  - 실행 파일이 있는 위치에 코어 덤프를 둔다는 건 꽤 이상한 선택으로 보임  
    `/usr/bin` 같은 곳에서 코어 덤프를 찾을 생각은 하지 않을뿐더러, 그런 위치는 종종 용량이 작거나 읽기 전용인 파일 시스템에 있음  
    기본 위치로는 **작업 디렉터리**가 훨씬 낫지 않을까
  - 코어 파일이 기본적으로 비활성화된 이유는 보안 전문가들이 사용자가 Linux를 안전하게 운영하지 못하며, 방치된 코어 파일이 악용될 수 있다고 보기 때문인 듯함  
    심지어 사용자가 코어 파일을 활성화해도 뭘 하는지 모른다고 간주해서, **root조차 찾기 어려운 곳**에 숨겨 두는 것처럼 느껴짐

- C나 D 등으로 프로그램을 작성하면서 종료 원인을 알고 싶다면 **`wait` 시스템 호출의 반환값**을 확인하면 되며, 프로그램이 시그널로 종료됐는지 알 수 있음  
  운영체제가 코어 덤프를 다른 곳으로 전달하면 필요할 때 바로 디버깅하거나 배포판에 오류 보고서를 보낼 수 있다는 장점도 있음  
  Linux 커널은 코어 덤프를 생성할 때 **`/proc/sys/kernel/core_pattern`** 이라는 특수 파일을 읽어 저장 위치를 결정함  
  파일로 쓰는 대신 프로그램에 파이프로 전달할 수도 있어서 GUI 대화상자 표시, 디버거 즉시 실행, 개발자에게 보고서 이메일 전송 같은 처리가 가능함  
  systemd는 커널의 `core_pattern`을 자신이 관리할 값으로 설정하지만, systemd를 사용하지 않아도 동일한 커널 기능을 쓸 수 있음  
  Windows XP 개발 당시 코어 덤프를 Microsoft로 전송해 존재조차 몰랐을 여러 버그를 수정했다는 이야기도 있으며, Windows에 개발 도구를 설치하면 자체 프로그램을 개발할 때 주문형 디버거가 꽤 유용함  
  이 기능은 2003년 Linux에 도입됐고 자세한 내용은 `man 5 core`에서 확인할 수 있음

- **코어 덤프**는 디버깅에는 훌륭하지만 무관해 보이는 파일 옆에 놓이면 일반 사용자에게 혼란을 주고, 진단 보고 체계로 쓰기에는 끔찍할 수 있음  
  제출된 Windows 충돌 보고서에 얼마나 많은 데이터가 들어가는지 처음 보고 경악했음  
  개인정보를 보호하는 충돌 보고 체계를 전제로 한다면, 제출된 충돌을 진단할 수 있도록 **스택과 레지스터 정보**만으로 원인을 추론하는 법을 익혀야 함

- Bash가 스크립트 안의 명령을 때때로 직접 **`exec`** 한다는 사실은 전혀 몰랐고 놀라운 기능임  
  Bash 프로세스 자체의 부하가 크지도 않고 필요한 곳에서는 습관적으로 `exec`를 사용하기 때문에 다소 잘못 설계된 기능처럼 느껴짐  
  다만 전체 실행 횟수를 합치면 예상보다 큰 차이를 만들 수도 있겠다는 생각이 듦
