Krafton Jungle/5. PintOS

[PintOS 5주차] Day 1

munsik22 2025. 6. 5. 16:09

이번 5주차에서는 (지난 3주차와 마찬가지로) 4주차의 팀원들과 프로젝트가 그대로 진행된다.

Stack growth 구현

static bool
vm_stack_growth (void *addr UNUSED) {
	/* Increases the stack size by allocating one or more anonymous pages
	 * so that addr is no longer a faulted address. Make sure you round down
	 * the addr to PGSIZE when handling the allocation. */
	void *upage = pg_round_down(addr);
	if (vm_alloc_page_with_initializer(VM_ANON, upage, true, NULL, NULL))
		return vm_claim_page(upage);
}
bool
vm_try_handle_fault (struct intr_frame *f UNUSED, void *addr UNUSED, bool user UNUSED, bool write UNUSED, bool not_present UNUSED) {
	struct supplemental_page_table *spt UNUSED = &thread_current ()->spt;
    if (addr == NULL || is_kernel_vaddr(addr) || !not_present)
		return false;
	struct page *page = spt_find_page(spt, addr);
    if (page == NULL) {
		/* If you have confirmed that the fault can be handled with a stack growth,
		 * call vm_stack_growth with the faulted address. */
		if (f->rsp - PGSIZE < addr) {
			if (!vm_stack_growth(addr))
				return false;
			page = spt_find_page(spt, addr);
		} else
			return false;
	}
	if (write && !page->writable)
		return false;
    return vm_do_claim_page(page);
}

pt-write-code2 해결

$ make tests/vm/pt-write-code2.result
pintos -v -k -T 60 -m 20   --fs-disk=10 -p tests/vm/pt-write-code2:pt-write-code2 -p ../../tests/vm/sample.txt:sample.txt --swap-disk=4 -- -q   -f run pt-write-code2 < /dev/null 2> tests/vm/pt-write-code2.errors > tests/vm/pt-write-code2.output
perl -I../.. ../../tests/vm/pt-write-code2.ck tests/vm/pt-write-code2 tests/vm/pt-write-code2.result
FAIL tests/vm/pt-write-code2
run: survived reading data into code segment: FAILED

 

"Try to write to the code segment using a system call. The process must be terminated with -1 exit code."

해당 함수는 시스템 콜 내부에서 코드 세그먼트에 write를 시도하면 exit(-1)을 하는지 확인한다.

void
test_main (void)
{
  int handle;

  CHECK ((handle = open ("sample.txt")) > 1, "open \"sample.txt\"");
  read (handle, (void *) test_main, 1);
  fail ("survived reading data into code segment");
}

해당 테스트 코드는 실행 중인 test_main의 주소 ((void *) test_main)에 handle의 1바이트를 읽어들이려고 한다. 즉, read-only인 코드 세그먼트 (void *) test_main 입장에서는 write하려고 하는 것이기 때문에, read 시스템 콜에서 writable이 false인 경우에 exit(-1)을 하는 코드를 추가해야 한다.

int read (int fd, void *buffer, unsigned size) {
	if (size == 0) return 0;
	if (!check_address(buffer)) exit(-1);
#ifdef VM
    struct page *page = spt_find_page(&thread_current()->spt, buffer);
    if (page != NULL && !page->writable)
        exit(-1);
#endif
	…
}

pt-stack-stk-sc 해결

$ make tests/vm/pt-grow-stk-sc.result
pintos -v -k -T 60 -m 20   --fs-disk=10 -p tests/vm/pt-grow-stk-sc:pt-grow-stk-sc --swap-disk=4 -- -q   -f run pt-grow-stk-sc < /dev/null 2> tests/vm/pt-grow-stk-sc.errors > tests/vm/pt-grow-stk-sc.output
perl -I../.. ../../tests/vm/pt-grow-stk-sc.ck tests/vm/pt-grow-stk-sc tests/vm/pt-grow-stk-sc.result
FAIL tests/vm/pt-grow-stk-sc
Test output failed to match any acceptable form.

Acceptable output:
  (pt-grow-stk-sc) begin
  (pt-grow-stk-sc) create "sample.txt"
  (pt-grow-stk-sc) open "sample.txt"
  (pt-grow-stk-sc) write "sample.txt"
  (pt-grow-stk-sc) 2nd open "sample.txt"
  (pt-grow-stk-sc) read "sample.txt"
  (pt-grow-stk-sc) compare written data against read data
  (pt-grow-stk-sc) end
Differences in 'diff -u' format:
  (pt-grow-stk-sc) begin
  (pt-grow-stk-sc) create "sample.txt"
  (pt-grow-stk-sc) open "sample.txt"
  (pt-grow-stk-sc) write "sample.txt"
  (pt-grow-stk-sc) 2nd open "sample.txt"
  (pt-grow-stk-sc) read "sample.txt"
- (pt-grow-stk-sc) compare written data against read data
- (pt-grow-stk-sc) end
+ pt-grow-stk-sc: exit(-1) # make check에서는 생략됨
"This test checks that the stack is properly extended even if the first access to a stack location occurs inside a system   call."

해당 테스트는 시스템 콜에서 처음으로 스택 주소에 접근하더라도 스택이 적절히 확장되는지 확인한다. 테스트 중 프로그램이 read까지는 정상적으로 동작했지만, 그 이후 비교(compare) 및 정상 종료(end) 단계에 도달하지 못했다.

int read (int fd, void *buffer, unsigned size) {
	if (size == 0) return 0;
	struct thread *curr = thread_current();
#ifndef VM
	if (!check_address(buffer)) exit(-1);
#else
	if (buffer == NULL || !is_user_vaddr(buffer))
		exit(-1);
    struct page *page = spt_find_page(&curr->spt, buffer);
	if (page == NULL) {
		if (buffer < USER_STACK) {
			int cnt = 0;
			while (curr->stack_pointer - cnt * PGSIZE >= buffer)
				cnt++;
			if (curr->stack_pointer - cnt * PGSIZE < STACK_LIMIT) exit(-1);
			for (int i = 0; i < cnt; i++) {
				if (!vm_stack_growth(buffer + i * PGSIZE))
					exit(-1);
			}
			page = spt_find_page(&curr->spt, buffer);
		} else 
			exit(-1);
	}
    if (!page->writable)
        exit(-1);
#endif
	…
}

pt-stack-stk-sc는 pass되었지만, 기존에 통과했던 pt-bad-read가 fail되었다.