일단 테스트에서 겪었던 고충 중 하나 중에 read테스트들이 다 통과는 되는데 read-nomal이 통과가 되지 않더라구요
왜일까를 계속 알아보는데
테스트 결과가 원래는 373byte가 나와야하는데 378byte가 나오더라구요
(read-normal) size of sample.txt (378) differs from expected (373)
(read-normal) ... bytes differ from expected.
그래서 read-nomal에 쓰이는 sample.txt파일을 봤는데 이게 웬걸 줄바꿈이 딱 5번 일어나더라구요
혹시 개행문자일까싶어서 dos2명령어로 개행문자가 있나 확인해보았는데 역시나 개행문자가 포함되어있었습니다
- 윈도우에서 작성된 파일은 줄바꿈을 \r\n으로 저장하고 리눅스는 \n 하나만 씀
- 따라서 sample.txt에 \r\n이 섞여 있으면 실제 바이트 수가 더 커지고,
- 기대하는 sample[]과 byte-level 비교에서 틀림
이 문제였습니다
dos2unix tests/userprog/sample.txt
이 명령어를 사용하여 유닉스 개행으로 바꿨더니 개행문자가 사라지고 테스트도 통과되었답니다

자 아무튼간 이제 전에 포스팅한 시스템콜 까지 구현했다면!
args, halt, exit, create, open, close, read, write, fork, exec, wait..까지는 통과가 될 것 입니다
먼저 bad시리즈를 보면 일단 잘못된 주소(잘못된 포인터나 커널 영역을 읽으려할 때)에 대해 무언가를 요청 시 정상적으로 죽거나 -1을 반환해야하는 테스트이다! 결국 그냥 예외처리를 잘 해주면 되는 것인데..
어째서인지 통과가 안되더라
output을 보니 나와야하는 정보에다가 레지스터 정보까지 포함되어서 출력되는 것을 확인했다!
그래서 kill함수에서 수정이 필요했다
이렇게 원래 kill함수에서:
switch (f->cs) {
case SEL_UCSEG:
/* User's code segment, so it's a user exception, as we
expected. Kill the user process. */
printf ("%s: dying due to interrupt %#04llx (%s).\n",
thread_name (), f->vec_no, intr_name (f->vec_no));
intr_dump_frame (f);
thread_exit ();
case SEL_KCSEG:
주석처리를 해주고 exit(-1)출력문을 추가해주었다
static void
kill (struct intr_frame *f) {
/* This interrupt is one (probably) caused by a user process.
For example, the process might have tried to access unmapped
virtual memory (a page fault). For now, we simply kill the
user process. Later, we'll want to handle page faults in
the kernel. Real Unix-like operating systems pass most
exceptions back to the process via signals, but we don't
implement them. */
/* The interrupt frame's code segment value tells us where the
exception originated. */
switch (f->cs) {
case SEL_UCSEG:{
struct thread *t = thread_current(); //이 줄이 꼭 필요함
printf("%s: exit(-1)\n", t->name);
thread_exit ();
}
case SEL_KCSEG:
/* Kernel's code segment, which indicates a kernel bug.
Kernel code shouldn't throw exceptions. (Page faults
may cause kernel exceptions--but they shouldn't arrive
here.) Panic the kernel to make the point. */
intr_dump_frame (f);
PANIC ("Kernel bug - unexpected interrupt in kernel");
default:
/* Some other code segment? Shouldn't happen. Panic the
kernel. */
printf ("Interrupt %#04llx (%s) in unknown segment %04x\n",
f->vec_no, intr_name (f->vec_no), f->cs);
thread_exit ();
}
}
이 방법말고 page_falut함수에서 수정하는 방법도 있다더라
암튼간에 이거 하나 수정하면 bad시리즈 테스트들이 다 통과한다 ~.,~

rox테스트는 설명하자면
"현재 실행 중인 프로세스의 실행파일은 쓰기(수정)가 되면 안된다!"
라는 조건을 커널이 잘 지키는지 확인하는 것이랍니다
rox = Read-Only Executable
즉, 실행 중인 파일(executable)은 read-only여야 한다는 의미
예시로 rox-simple을 보자
/* 실행 중인 프로세스의 실행 파일이 수정될 수 없음을 보장하는 테스트입니다.
* 이 테스트는 PintOS가 실행 중인 파일에 대해 write를 막고 있는지를 확인합니다.
* 즉, 실행 중인 binary를 open하고 read는 가능하지만 write는 0 byte만큼만 수행되어야 합니다.
*/
#include <syscall.h> // 시스템 콜 정의 (open, read, write 등)
#include "tests/lib.h" // 테스트를 위한 체크 매크로, 출력 함수 등
#include "tests/main.h" // test_main() 정의를 위한 헤더
void
test_main(void)
{
int handle; // 파일 디스크립터를 저장할 변수
char buffer[16]; // 파일에서 읽어들일 데이터를 저장할 버퍼
// 현재 실행 중인 프로그램인 "rox-simple" 파일을 open한다.
// 성공적으로 열렸는지 확인 (2 이상의 fd를 얻어야 함: 0=stdin, 1=stdout)
CHECK((handle = open("rox-simple")) > 1, "open \"rox-simple\"");
// 파일에서 16바이트를 읽어서 buffer에 저장
// 읽기 자체는 가능해야 하므로, 정확히 16바이트 읽혀야 테스트 통과
CHECK(read(handle, buffer, sizeof buffer) == (int)sizeof buffer,
"read \"rox-simple\"");
// 실행 중인 프로그램인 rox-simple에 write를 시도한다.
// 성공하면 안 되며, write는 실패해야 하므로 0을 반환해야 함.
CHECK(write(handle, buffer, sizeof buffer) == 0,
"try to write \"rox-simple\"");
}
- process_exec() 이후 실행 파일을 thread_current()->running_file에 저장하고
- file_deny_write()를 호출하여 해당 파일이 write 불가하도록 설정해야 하며
- sys_write() 또는 내부 file_write()에서 이를 체크하고 막아야 테스트가 통과가 된답니다~
그럼 이제 저희가 해야할건
- thread 구조체 수정 : struct file *running_file 필드 추가
- process_exec 수정 : running_file에 로드된 실행 파일을 열어서 집어넣고 file_deny_write 사용하기
- process_exit 수정
자세한 내용은
https://gooch123.tistory.com/22
[pintOS] 과제 2 rox 테스트 구현
rox 테스트는 무엇일까?먼저 과제 설명서를 보자 친절하게 설명되어있지만, 잘 모르겠으면 테스트 파일을 까보면 된다.rox 테스트 알아보기rox-simple.c/* 실행 중인 프로세스의 실행 파일이 수정될
gooch123.tistory.com
케르베로스 1호 임구철씨의 블로그를 참고합시다!
syn테스트
이 테스트는 이름 그대로 synchronization (동기화) 관련 테스트들이다
10개의 자식 프로세스를 만들고 그 프로세스가들이 동일한 파일에 대해 read, write, remove하는 테스트다
그냥 파일마다 lock을 걸어서 일관성을 유지해야하는 테스트이다
기존 코드에서의 문제점은:
- 부모가 자식의 종료를 wait() 없이 list_remove()로만 정리함
- → 이로 인해 자식 스레드 구조체가 메모리에 남아 좀비 프로세스가 발생
- 자식의 exit_status를 부모가 읽기 전에 자식이 종료되어 리소스를 정리하면
- 동기화가 깨지고 예기치 않은 동작이 발생할 수 있음
int process_wait(tid_t child_tid UNUSED)
{
struct thread *cur = thread_current();
if (list_empty(&cur->children_list))
return -1;
struct thread *child = get_my_child(child_tid);
if (child == NULL)
return -1;
if (child->wait_flag == true)
return -1;
child->wait_flag = true;
/* 자식의 wait_sema를 대기합니다. process_exit에서 wait_sema를 up 해줍니다 */
sema_down(&child->wait_sema);
int status = child->exit_status;
list_remove(&child->child_elem);
if (status < 0)
return -1;
return status;
}
따라서 기존코드에서 우리가 해야할 것은
- thread 구조체 수정 : 기존 wait_flag대신 세마포어로 변경
- 이에 맞춰 process_wait & process_exit 수정
https://trash-in-trashcan.tistory.com/235
Pintos-Kaist 진행하기 (3): 사용자 프로그램(3)
이전에 썼던 글은 몇 가지 테스트 케이스를 통과하지 못했었다.통과하지 못했던 테스트 케이스들은 다음과 같다.FAIL tests/userprog/multi-child-fd FAIL tests/userprog/rox-simple FAIL tests/userprog/rox-child FAIL tests
trash-in-trashcan.tistory.com
자세한건 케르베로스 3호 이하린씨의 블로그를 참고합시다!
'크래프톤정글 > Pintos' 카테고리의 다른 글
| 누나랑 페이지폴트 흐름 따라갈래? (1) | 2025.05.30 |
|---|---|
| VM 시작 (0) | 2025.05.30 |
| User Program _System Call(exit, write, open, close, create, remove) (0) | 2025.05.21 |
| User Program _System Call(filesize, read, seek, tell) (0) | 2025.05.19 |
| User Program _ Argument Passing (1) | 2025.05.17 |