Program crashed for calling execvp to compile a program with error?

589 views Asked by At

I use execvp to compile a program with error. But then error message pop on my terminal screen which should not happen because if execvp fails, it will only let child return with exit status. I do not understand why my terminal will actually show the error message?

My command array: {gcc, studentcode.c, ourtest3.c, -o, ourtest3.x, NULL} and in ourtest3.c, I made several errors on purpose. My calling function is like this:

commands = {"gcc", "studentcode.c", "ourtest3.c", "-o", "ourtest3.x", NULL};
int compile_program(Char** commands) {
  pid_t pid;
  int status;

  pid = safe_fork();
    if (pid == 0) { /*Child*/
      if (execvp(commands[0], commands) < 0) {
    exit(0);
      }
    } else { /*Parent*/
      if (wait(&status) == -1) {
    return 0;
      }
      if (WIFEXITED(status)) {
    if (WEXITSTATUS(status) != 0) {
      return 1;
    }
      } else {
    return 0;
      }
    }
  return 1;
}

ourtest3.c is this:

#include <stdio.h>
#include <assert.h>
#include "studentcode.h"

int main(void) {
  assert(product(2, 16) == 32

  printf("The student code in public07.studentcode.c works on its ");
  printf("third test!\n");

  return 0;
}

My program should have ended normally with return value 0, but instead, on my terminal window, it shows that

ourtest3.c: In function 'main':
ourtest3.c:19:0: error: unterminated argument list invoking macro "assert"
ourtest3.c:13:3: error: 'assert' undeclared (first use in this function)
ourtest3.c:13:3: note: each undeclared identifier is reported only once for each function it appears in
ourtest3.c:13:3: error: expected ';' at end of input
ourtest3.c:13:3: error: expected declaration or statement at end of input
1

There are 1 answers

0
David Schwartz On BEST ANSWER

If you want to change the stdin, stout, and stderr of a process, you need to do that. Otherwise, it just inherits them from its parent. After fork and before execvp, you probably want to open /dev/null and dup it onto file descriptors 0 and 1.

Here's some ugly code with no error checking:

if (pid == 0) { /*Child*/

  /* Redirect stdin and stderr to /dev/null */
  int fd = open ("/dev/null", O_RDONLY);
  dup2(STDIN_FILENO, fd);
  dup2(STDERR_FILENO, fd);
  close(fd);

  if (execvp(commands[0], commands) < 0) {
_exit(0);
  }

You can also redirect them to files or pipes if you want the parent to have access to the child's output.

Note the call to _exit. Do not get in the habit of calling exit from failing children. That has caused bugs with serious security implications in the past. Imagine if your process has something it's going to do when it exits (such as flush a buffer to a terminal or network connection). By calling exit in the child, you do that thing twice. You might think that you know that you have no such thing, but you can't possibly know that (in general) because you have no idea what your libraries might be doing internally.