100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace

What Does the exec() Family of System Calls Do?

Learn what exec() does — replacing a process image, the fork-exec pattern, and file descriptor survival — with an OS interview example.

mediumQ81 of 224 in Operating Systems Est. time: 5 minsLast updated:
Open Code Lab
81 / 224

Expected Interview Answer

exec() replaces the calling process’s memory image — code, data, stack, and heap — with a new program loaded from disk, keeping the same process ID while completely discarding the old program’s contents, so it never returns on success.

Unlike fork(), exec() does not create a new process; it overwrites the current process in place, loading a new executable’s segments into the same PID and resetting the stack and heap for the new program’s entry point. Because the old program’s code and data are gone, exec() only returns to the caller if it fails — for example, if the target file does not exist or is not executable — otherwise control simply jumps into the new program’s main(). Open file descriptors survive an exec() by default unless explicitly marked close-on-exec, which is how shells implement input/output redirection before launching a command. The exec() family (execl, execv, execve, execvp, and friends) differs only in how arguments and the environment are supplied — as a variadic list versus an array, and whether PATH is searched — but they all perform the same underlying replacement.

  • Loads and runs a new program without the overhead of creating a new process
  • Combined with fork(), lets a process spawn and run an unrelated program (the fork-exec pattern)
  • Preserves the process ID and open file descriptors across the program change
  • Foundation for how shells launch commands

AI Mentor Explanation

exec() is like a stadium keeping the same match ticket and gate number but completely swapping out the sport being played on the field — the cricket pitch, players, and rules are entirely replaced by a football match under the same booking. Once the swap happens there is no going back to cricket under that booking; the venue simply now runs the new sport from kickoff. Fans holding tickets for concessions from before the swap can still use them if those stands were kept open, mirroring how open file descriptors can survive the exec() unless explicitly closed.

Step-by-Step Explanation

  1. Step 1

    exec() invoked

    The calling process specifies a new executable path, arguments, and (optionally) environment.

  2. Step 2

    Old image discarded

    The kernel unloads the current code, data, heap, and stack segments from the process.

  3. Step 3

    New image loaded

    The new executable's segments are loaded into the same process ID, and the stack is reset.

  4. Step 4

    Execution jumps in

    Control transfers to the new program's entry point; exec() never returns to the old code on success.

What Interviewer Expects

  • Understanding that exec() replaces the process image rather than creating a new process
  • Awareness that exec() only returns on failure
  • Knowledge that open file descriptors survive exec() unless marked close-on-exec
  • Ability to explain the fork-then-exec pattern used by shells

Common Mistakes

  • Confusing exec() with fork() and thinking it creates a new process ID
  • Assuming exec() returns normally after successfully launching the new program
  • Forgetting that file descriptors are inherited across exec() by default
  • Not knowing why shells call fork() before exec() instead of exec()-ing directly

Best Answer (HR Friendly)

exec() takes the currently running program and completely replaces its code and data with a different program, while keeping the same process ID. It does not create a new process — it transforms the existing one — and if it succeeds, the original code is simply gone and the new program is now running in its place.

Code Example

fork() then exec() pattern (how a shell launches a command)
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void) {
    pid_t pid = fork();

    if (pid == 0) {
        /* child: replace its image with /bin/ls */
        execl("/bin/ls", "ls", "-l", (char *)NULL);
        perror("execl failed");   /* only reached if exec() fails */
        _exit(1);
    } else if (pid > 0) {
        wait(NULL);               /* parent waits for the child to finish */
        printf("child finished, parent continues\n");
    }
    return 0;
}

Follow-up Questions

  • Why do shells call fork() before exec() instead of exec()-ing directly?
  • What is the close-on-exec flag and when would you set it?
  • What is the difference between execv() and execvp()?
  • What happens to signal handlers across an exec() call?

MCQ Practice

1. What does a successful exec() call do to the calling process?

exec() overwrites the current process's code, data, heap, and stack with a new program under the same process ID.

2. When does exec() return to the caller?

On success, control jumps directly into the new program; exec() only returns if the call itself failed.

3. Why do shells typically call fork() before exec()?

Calling exec() directly would replace the shell itself; forking first preserves the shell so it can supervise the child.

Flash Cards

What does exec() do?Replaces the calling process’s memory image with a new program, keeping the same PID.

When does exec() return?Only on failure — success means control jumps straight into the new program.

Do file descriptors survive exec()?Yes, by default, unless explicitly marked close-on-exec.

Why fork() then exec()?So the original process (like a shell) survives to supervise the new program running in the child.

1 / 4

Continue Learning