{
  "slug": "close-on-exec",
  "term": "Close-on-exec",
  "aliases": [
    "FD_CLOEXEC",
    "O_CLOEXEC"
  ],
  "definition": "Close-on-exec is a per-file-descriptor flag that causes that descriptor to be closed when its process successfully replaces its program image with an exec-family operation.",
  "note": "Lifetime: FD_CLOEXEC does not close a descriptor at fork. The child initially retains its inherited reference; successful exec closes the child's descriptor when the flag is set. An exec failure that returns to the caller, such as ENOENT for a missing executable, leaves the descriptor open. The parent's reference remains separate. [fd-flags] [fork-api]\n\nCreation: open(..., O_CLOEXEC) sets the flag as part of descriptor creation. Opening first and setting FD_CLOEXEC later with fcntl leaves a window in which another thread can fork and exec with the descriptor still inheritable. O_CLOEXEC names the creation option, not an open-file-description status flag. [open-api]\n\nAliases: raw Linux dup clears close-on-exec on the new descriptor even when the original has it set. dup3(oldfd, newfd, O_CLOEXEC) sets it on a distinct target. Both descriptors still share the open file description and its offset. Closing one at exec does not close a surviving unmarked alias or undo earlier writes. [dup-api] [hesela-inheritance]\n\nFailure boundary: an execve failure after the old image has been torn down can terminate the process instead of returning to its caller. The ENOENT example covers a returned failure, not every possible exec failure. [exec-api]",
  "status": "shipping",
  "advantages": [],
  "limitations": [
    "Close-on-exec is inheritance control, not a data flush or a complete process-isolation mechanism."
  ],
  "related": [
    "file-descriptor",
    "open-file-description",
    "close",
    "file-offset"
  ],
  "supersedes": [],
  "supersededBy": [],
  "firstSeen": null,
  "lastSeen": null,
  "citations": [
    {
      "id": "fd-flags",
      "title": "Linux man-pages: F_GETFD(2const), descriptor flags and exec outcome",
      "url": "https://man7.org/linux/man-pages/man2/F_GETFD.2const.html",
      "accessed": "2026-11-05"
    },
    {
      "id": "open-api",
      "title": "Linux man-pages: open(2), O_CLOEXEC and atomic descriptor creation",
      "url": "https://man7.org/linux/man-pages/man2/open.2.html",
      "accessed": "2026-11-05"
    },
    {
      "id": "dup-api",
      "title": "Linux man-pages: dup(2), descriptor-local flags and dup3",
      "url": "https://man7.org/linux/man-pages/man2/dup.2.html",
      "accessed": "2026-11-05"
    },
    {
      "id": "fork-api",
      "title": "Linux man-pages: fork(2), inherited descriptors and shared open file descriptions",
      "url": "https://man7.org/linux/man-pages/man2/fork.2.html",
      "accessed": "2026-11-05"
    },
    {
      "id": "hesela-inheritance",
      "title": "Hesela: Descriptor inheritance across program replacement",
      "url": "https://hesela.com/analyses/fsync-failure-retry-durability/#close-on-exec",
      "accessed": "2026-11-05"
    },
    {
      "id": "exec-api",
      "title": "Linux man-pages: execve(2), failures past program-image teardown",
      "url": "https://man7.org/linux/man-pages/man2/execve.2.html",
      "accessed": "2026-11-05"
    }
  ],
  "updated": "2026-11-05",
  "provenance": [
    "API behavior is scoped to the cited Linux interfaces; high-level language runtimes may create non-inheritable descriptors by default."
  ]
}
