Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

fork() succeeds with a descriptor missing when its pin cannot be allocated

Abierto Apto para principiantes
#414 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 2 días

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
75/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
c

Línea de trabajo

Empieza en src/runtime/fork-state.c en fork_ipc_send_fd_table() para ver cómo maneja el retorno NULL de fd_lifetime_pin_locked(). Luego revisa src/syscall/fdtable.c para fd_lifetime_pin_spare() para entender los casos de fallo de asignación. El fix debe hacer que fork() devuelva -1 con ENOMEM cuando no se puede asignar un pin, y puedes verificarlo usando la reproducción por inyección de fallos descrita.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

bug

fork_ipc_send_fd_table() (src/runtime/fork-state.c) skips a slot when fd_lifetime_pin_locked() returns NULL:

pin = fd_lifetime_pin_locked(i);
if (!pin)
    continue;

fd_lifetime_pin_spare() returns NULL for a closed slot, for a slot with no host descriptor, and when malloc fails. The loop has already skipped FD_CLOSED under the same fd_lock hold, so on an open slot with a host descriptor NULL means the allocation failed. The slot is then left out of the table sent to the child, the send completes, and the parent's fork() returns the child pid. Nothing is logged.

Linux fork() either gives the child every descriptor or fails with ENOMEM.

Reproduction

The allocation cannot be made to fail from the guest, so this uses fault injection on b57f367. In fd_lifetime_pin_spare() (src/syscall/fdtable.c):

-            lifetime = malloc(sizeof(*lifetime));
+            lifetime = (fd == 5 && getenv("PINFAIL"))
+                           ? NULL
+                           : malloc(sizeof(*lifetime));

Guest:

for (int i = 0; i < 5; i++)
    open("/dev/null", O_RDONLY); /* fds 3..7 */
pid_t pid = fork();
printf("[%s] fork returned %d\n", pid ? "parent" : "child", (int) pid);
if (pid == 0) {
    for (int fd = 3; fd <= 7; fd++)
        printf("child fd %d: %s\n", fd,
               fcntl(fd, F_GETFD) >= 0 ? "open" : strerror(errno));
    _exit(0);
}
waitpid(pid, NULL, 0);

With PINFAIL=1:

[parent] fork returned 2
[child] fork returned 0
child fd 3: open
child fd 4: open
child fd 5: Bad file descriptor
child fd 6: open
child fd 7: open

Without the variable, fd 5 is open in the child.

Expected

fork() returns -1 with ENOMEM and no child is left running.

The skip is older than the pin. At 628181b, where this loop still calls dup(), a guest holding 1021 descriptors under ulimit -n 1280 gets a successful fork() and a child with descriptors missing.

Lenguaje dominante
C
Estrellas
271
Forks
28
Merge medio
2 d 18 h
PR fusionados (30 d)
19

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de sysprog21/elfuse

Todos los issues de sysprog21/elfuse

Issues similares

Más issues de C

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.