2

The problem involves relatively fragmented code, here I give the main code.

Full code: syscall.c

static uint64
argraw(int n)
{
  struct proc *p = myproc();
  switch (n) {
  case 0:
    return p->tf->a0;
  case 1:
    return p->tf->a1;
  case 2:
    return p->tf->a2;
  case 3:
    return p->tf->a3;
  case 4:
    return p->tf->a4;
  case 5:
    return p->tf->a5;
  }
  panic("argraw");
  return -1;
}

// Fetch the nth 32-bit system call argument.
int
argint(int n, int *ip)
{
  *ip = argraw(n);
  return 0;
}

....
....

static uint64 (*syscalls[])(void) = {
[SYS_fork]    sys_fork,
[SYS_exit]    sys_exit,
[SYS_wait]    sys_wait,
[SYS_pipe]    sys_pipe,
[SYS_read]    sys_read,
[SYS_kill]    sys_kill,
[SYS_exec]    sys_exec,
[SYS_fstat]   sys_fstat,
[SYS_chdir]   sys_chdir,
[SYS_dup]     sys_dup,
[SYS_getpid]  sys_getpid,
[SYS_sbrk]    sys_sbrk,
[SYS_sleep]   sys_sleep,
[SYS_uptime]  sys_uptime,
[SYS_open]    sys_open,
[SYS_write]   sys_write,
[SYS_mknod]   sys_mknod,
[SYS_unlink]  sys_unlink,
[SYS_link]    sys_link,
[SYS_mkdir]   sys_mkdir,
[SYS_close]   sys_close,
[SYS_ntas]    sys_ntas,
};

....
....

void
syscall(void)
{
  int num;
  struct proc *p = myproc();

  num = p->tf->a7;
  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
    p->tf->a0 = syscalls[num]();              // question here
  } else {
    printf("%d %s: unknown sys call %d\n",
            p->pid, p->name, num);
    p->tf->a0 = -1;
  }
}

Full code: sysproc.c

uint64
sys_exit(void)
{
  int n;
  if(argint(0, &n) < 0)
    return -1;
  exit(n);
  return 0;  // not reached
}

uint64
sys_kill(void)
{
  int pid;

  if(argint(0, &pid) < 0)
    return -1;
  return kill(pid);
}

Full code: proc.c

int
kill(int pid)
{
  struct proc *p;

  for(p = proc; p < &proc[NPROC]; p++){
    acquire(&p->lock);
    if(p->pid == pid){
      p->killed = 1;
      if(p->state == SLEEPING){
        // Wake process from sleep().
        p->state = RUNNABLE;
      }
      release(&p->lock);
      return 0;
    }
    release(&p->lock);
  }
  return -1;
}

For p->tf->a0 = syscalls[num]();(in syscall.c), after this line of code is called, the value of p->tf->a0 will change, As you can see, what sys_exit() return is 0 or -1, what sys_fork() may return pid or -1 (fork() in function sys_fork()). So that the value it stores may be no longer pid, but the return value of other functions.

my question: According to the above, when sys_kill() is called, the value obtained by argint() in the function may not be the pid of the process, so the parameter of kill() may not be the pid of the process. In this case, isn't the process always unable to be killed?

RecharBao
  • 371
  • 2
  • 10
  • 1
    For `kill()` and `exit()` it seems relatively irrelevant what is returned - the process has been signalled to end already (as the syscall is done first). Important is whether any other of the "normal" syscalls (taht you didn't show) that keep the process running modify `p->tf->a0` in a way that disturbs this mechanism. – tofro Jun 16 '21 at 07:44

1 Answers1

0

As you pointed it, the problematic line is: p->tf->a0 = syscalls[num]();

When the compiler see this line, what happens? You can decompose it in two steps:

uint64 ret;

ret = syscalls[num]();

p->tf->a0 = ret;

In other words, the p->tf->a0 is updated after having being used by sys_kill

Mathieu
  • 8,840
  • 7
  • 32
  • 45