Linux elimina la API `strncpy` después de seis años de trabajo, 360 parches

Cadenas terminadas en NUL vs. cadenas prefijadas por longitud / tipos de cadena “reales”

  • Muchos sostienen que las cadenas C terminadas en NUL son una de las peores decisiones de diseño de la informática: fáciles de desbordar, difíciles de razonar y trampas de rendimiento (por ejemplo, strlen repetido convirtiendo O(N) en O(N²)).
  • Otros señalan que fueron un compromiso pragmático en máquinas diminutas de los años 70; las secuencias terminadas por centinela (cadenas, arreglos de punteros, listas enlazadas) eran baratas y encajaban con la práctica en ensamblador.
  • Las cadenas al estilo Pascal o prefijadas por longitud evitan errores por terminadores ausentes, pero traen problemas: campos de longitud de tamaño fijo (históricamente 255 caracteres), confusión entre bytes/puntos de código/glifos, y dificultad para hacer subcadenas sin copiar salvo que se pase a “fat pointers” (puntero+longitud).
  • Variantes modernas comentadas: struct { size_t length; T* ptr; } de D, BSTRs y cabeceras de Pascal/Delphi/Free Pascal, codificaciones de longitud dinámica/de longitud variable, y tipos “span”/slice. Compromisos: sobrecarga de memoria frente a velocidad frente a slicing sin copia.

NULL, NUL y tipos opción

  • El hilo distingue repetidamente NUL (byte terminador 0) de NULL (puntero inválido).
  • Algunos ven NULL como algo correcto y necesario; el problema real es no poder declarar punteros no nulos.
  • Otros enfatizan los tipos modernos “option”/suma (por ejemplo, Option<T>) como la forma correcta de representar valores “sin establecer”, impuesto por el sistema de tipos en tiempo de compilación.
  • Debate sobre si los entornos de bajo nivel pueden o deben reemplazar NULL por tales construcciones, o usarlas como abstracción de nivel superior que se compila a representaciones con valor nulo.

Contexto histórico y de estándares

  • Varios comentarios subrayan los orígenes de C: RAM diminuta (decenas de KiB), compiladores de pasada única, límites de direccionamiento del PDP-11 y reutilización de idioms existentes. En ese contexto, las cadenas terminadas en NUL y la degradación puntero/arreglo se veían como compromisos ingeniosos, no como errores.
  • Propuestas posteriores como fat pointers/slices y APIs más seguras (por ejemplo, strlcpy) se citan como oportunidades perdidas; se critica a los comités por añadir funciones complejas (VLAs, _Generic) mientras dejaban esencialmente congelados el modelo central de cadenas de C y la stdlib.

strncpy, APIs del kernel y seguridad

  • strncpy se describe como ampliamente mal utilizado y contraintuitivo: rellena con ceros, puede no terminar en NUL al truncar, y se concibió originalmente para campos de tamaño fijo y rellenos (por ejemplo, antiguas entradas de directorio), no como un “strcpy seguro”.
  • Las funciones de reemplazo del kernel (strscpy, strscpy_pad, strtomem_pad, memcpy_and_pad, memcpy) codifican una intención más clara (terminada vs no terminada, relleno vs copia en bruto), a costa de más APIs pero con mejor seguridad y señales de rendimiento.
  • A algunos les parece esta proliferación “enrevesada”; otros argumentan que una sola navaja suiza sería más lenta y difuminaría la intención.

IA y refactorización automatizada

  • Una línea de discusión pregunta si codificadores basados en LLM podrían haber automatizado la mayor parte del trabajo de eliminación de strncpy.
  • Quienes la apoyan reportan buenas experiencias usando LLMs para refactorizar muchos programas en C y sostienen que seis años es demasiado para cambios esencialmente mecánicos.
  • Los escépticos responden que, en un proyecto a escala del kernel, los principales cuellos de botella son revisión, coordinación y pruebas, no solo editar; el comportamiento sutil aguas abajo y la dependencia de semánticas antiguas deben auditarse con cuidado.
  • Hay un cansancio visible con que la IA se inyecte en cada discusión de programación, junto con curiosidad por su potencial para refactorizaciones a gran escala.