Skip to content

Fix FD leaks and add missing CLOEXEC flags#500

Open
xroche wants to merge 1 commit intoDataDog:mainfrom
algolia:fix/fd-leaks-and-cloexec
Open

Fix FD leaks and add missing CLOEXEC flags#500
xroche wants to merge 1 commit intoDataDog:mainfrom
algolia:fix/fd-leaks-and-cloexec

Conversation

@xroche
Copy link

@xroche xroche commented Feb 27, 2026

What does this PR do?

Fix file descriptor leaks on error paths and add missing CLOEXEC flags across several files. In library mode, ddprof_start_profiling() fork+execs the daemon — every FD without CLOEXEC in the parent service leaks into the child process.

Changes

File Fix
src/create_elf.cc Use UniqueFd for RAII cleanup (fixes FD leak on error paths), add O_CLOEXEC, fix "prox" typo
src/ringbuffer_utils.cc Close mapfd on ftruncate/eventfd error paths, add EFD_CLOEXEC to eventfd()
src/ipc.cc Use accept4() with SOCK_CLOEXEC (parent socket uses it but accepted connections didn't inherit it), add SFD_CLOEXEC to signalfd()
src/daemonize.cc Add O_CLOEXEC to pipe2()
src/ddprof_module_lib.cc Add O_CLOEXEC to open() calls (already uses UniqueFd)

Motivation

For long-running services using ddprof in library mode (e.g., Algolia's 7 production services), leaked FDs accumulate across profiler restarts. The missing CLOEXEC flags cause FDs to leak into the fork+exec'd daemon child on every profiler start.

How to test the change?

  • create_elf.cc: trigger an error path (e.g., corrupt ELF) and verify no FD leak with /proc/self/fd count
  • ringbuffer_utils.cc: trigger ftruncate failure (e.g., ENOSPC on memfd) and verify mapfd is closed
  • ipc.cc: verify accepted connections have CLOEXEC set via /proc/<pid>/fdinfo/<fd>
  • daemonize.cc, ddprof_module_lib.cc: verify CLOEXEC flag on opened FDs

Classification

  • CWE-775: Missing Release of File Descriptor or Handle after Effective Lifetime
  • CWE-403: Exposure of File Descriptor to Unintended Control Sphere

Fixes #497

In library mode, ddprof_start_profiling() fork+execs the daemon.
Every FD without CLOEXEC in the parent leaks into the child process.

Changes:
- create_elf.cc: use UniqueFd for RAII cleanup (fixes FD leak on error
  paths), add O_CLOEXEC, fix "prox" typo in log message
- ringbuffer_utils.cc: close mapfd on ftruncate/eventfd error paths,
  add EFD_CLOEXEC to eventfd()
- ipc.cc: use accept4() with SOCK_CLOEXEC (parent socket already uses
  SOCK_CLOEXEC but accepted connections didn't inherit it),
  add SFD_CLOEXEC to signalfd()
- daemonize.cc: add O_CLOEXEC to pipe2()
- ddprof_module_lib.cc: add O_CLOEXEC to open() calls (already uses
  UniqueFd for RAII)

Fixes DataDog#497
@xroche xroche marked this pull request as ready for review February 27, 2026 20:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FD leaks and missing CLOEXEC flags in library mode

1 participant