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,
strlenrepetido 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
strncpyse 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 “strcpyseguro”.- 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.