Some hints aimed at avoiding time-consuming trouble # Use strtok_r correctly Correctly used it give simple straight-forward code. You need to be aware that id do modify the string it it set to work on by introducing '\0'-characters at end of words, and gives you a pointer to the start of each word as result. # Do not guess Read The Fantastic Manual (RTFM) or documentation or code and code comments FIRST. Follow what it say. # Keep It Simple and Stupid Try to start with the most straightforward simple code you can, even it if becomes stupid in some sense. You may limit yourself to a predetermined max size and you may write linear search loops. Keep it simple to sanity check and debug. You should know the code is correct at a glace. We will tell you if you need to do something more efficient. Include sanity checks when you can, you want to notice any weird data values as soon as they occur. Check return values for error codes, check pointers for NULL, check parameters for what they should be. # Write proper debug messages giving you clear and structured trace information with the most relevant data included An example for the function process_wait in userprog/process.c follow: int process_wait (int child_id) { int status = -1; struct thread *cur = thread_current (); printf("%s#%d: process_wait(%d) ENTERED\n", cur->name, cur->tid, child_id); ... printf("%s#%d: process_wait(%d) RETURNS %d\n", cur->name, cur->tid, child_id, status); return status; } # ALWAYS give all variables initial values, and ALWAYS set initial values for allocated memory If you do not know what you started with, you wont know if nor when it was messed up Clever choice of initial value may also simplify some logic (eg if you let a status variable assume failure from start you will only need to update it on success) # DO NOT tolerate and compiler warnings, fix them If you think them unimportant: then they are easy to fix and you can as well do it, else they will obscure other important warnings If you do not really know what they are about: you really need to find out and then fix them # Avoid malloc and free at all cost. A local variable often suffice and is vastly easier to manage, just make sure you know the scope (lifetime) is sufficient. If you do use malloc, plan for when to free from start, freeing the memory again is often much more tricky than allocating it. # Employ a debug strategy You will have bugs. Some will be really challenging to find. Use a strategy when you debug. A strategy is well thought out actions and responses that step by step lead you closer to VICTORY. Do not randomly change and test. Instead start at the point the bug become visible. Find out any variables involved. Find the variable with unexpected value. Trace how that variable is updated from init to place of bug. Or similar, make sure you learn actual new facts about the bug or code at each debugging step. # Use the language to make code more readable (not less readable) Assume you are to implement the system call accept (not included in Pintos, just an example) int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); On the user-mode stack this syscall would push all arguments and the syscall number for "accept". You can describe it like so: struct accept_stack_frame { int syscall; int sockfd; struct sockaddr *addr; socklen_t *addrlen; }; And initiate a custom stack pointer like so: struct accept_stack_frame* accept_sp = (struct accept_stack_frame*)f->esp; And then use that to read data off the stack with help from the language! accept_sp->sockfd NB: This is a slightly overworked example. You may achieve similar result in other ways, for example transforming f->esp to an array of 32-bit integer and then reading each argument using array syntax and storing it in a variable of proper type (or passing as argument to a function taking properly typed parameters). kernel_accept(esp[1], esp[2], esp[3]);