Pintos Project 3 — Stack Growth 구현 흐름 & page_fault 분석
2025. 6. 13. 16:38ㆍ개발
1. 왜 “자동 Stack Growth”가 필요한가?
- 동적 스택 확장 : 사용자 프로그램은
push,call, 재귀 등으로 스택을 예측 불가하게 사용. - 초기 스택 4 KiB 제한 만으로는 대부분 테스트/apps 불통 → fault 시 새 페이지를 할당해 스택을 확장해야 함.
- 보안 & 메모리 보호 : 임의 주소 fault 를 모두 허용하면 공격 벡터. “합당한 범위” 만 grow.
2. GitBook 기준 Stack Growth 조건
fault_addr가 User 영역(<USER_STACK).fault_addr >= rsp − 8(아래 §3 참고).- 최대 깊이 1 MiB :
USER_STACK − fault_addr ≤ 1 MiB. - 중복 예약 안 됐는지
spt_find_page()검사.
3. 왜 rsp − 8 Bytes 여유를 주나?
- x86‑64 System V ABI :
pushq X→rsp -= 8후[rsp]=X call q또한 리턴 주소 저장 전에rsp -= 8.- 따라서
rsp레지스터가 갱신되기 직전 메모리 접근이 먼저 일어나 fault 가능 → 최대 8바이트 범위 허용.
4. page_fault 핸들러 상세 플로(유저 fault)
// userprog/exception.c
static void page_fault(struct intr_frame *f) {
void *fault_addr = rcr2(); // HW 등록값
struct thread *t = thread_current();
uint64_t rsp = is_kernel_vaddr(f->rsp)? t->stack_pointer : f->rsp; // 유저 rsp 확보
bool not_present = (f->error_code & PF_P) == 0;
bool success = false;
if (not_present && is_user_vaddr(fault_addr)) {
success = vm_try_handle_fault(fault_addr, rsp, f->rip);
}
if (!success) process_exit(-1);
}
vm_try_handle_fault() 중 스택 growth 분기
if (p == NULL) {
/* Stack growth 조건 검사 */
if (fault_addr >= rsp - 8 && fault_addr < USER_STACK
&& USER_STACK - fault_addr <= (1<<20)) {
/* 1. 예약 */
bool ok = vm_alloc_page_with_initializer(VM_ANON,
pg_round_down(fault_addr), true,
anon_initializer, NULL);
/* 2. 즉시 claim (0‑fill) */
success = ok && vm_claim_page(pg_round_down(fault_addr));
}
}
5. 구현 단계 체크리스트
- setup_stack() : 최초 1 page 예약+claim 후
if_.rsp = USER_STACK. - page_fault() 에 유저
rsp전달(시스템콜 시 커널 rsp 보관). - vm_try_handle_fault() 에 위 3가지 조건 구현.
- vm_alloc_page_with_initializer() 로 UNINIT 페이지 저장 → anon_initializer.
- anon_swap_in() : PAL_USER|PAL_ZERO 프레임 할당 · PTE 매핑.
6. 핵심 테스트
tests/vm/stck- growth-1: fault 3 회, rsp –8 조건 검증.tests/vm/stck- growth-2: 1 MiB 초과 grow 시 kill 확인.- userprog 기존 테스트
args-n *: argv 푸시용 추가 grow 경로.
'개발' 카테고리의 다른 글
| Pintos VM Project - merge-mm / stk / pa 테스트 트러블슈팅 정리 (0) | 2025.06.15 |
|---|---|
| Pintos Project 3 — Memory‑Mapped Files 구현 흐름 (0) | 2025.06.14 |
| Pintos Project 3: Anonymous Page 구현 흐름 집중 해부 (1) | 2025.06.12 |
| Pintos VM Project - lazy_load_segment & fork-read 디버그 (0) | 2025.06.05 |
| [Pintos] 타이머 인터럽트 때문에 랜덤 커널 패닉이 터진 이유와 해결 방법 (0) | 2025.05.29 |