1.. include:: ../disclaimer-sp.rst 2 3:Original: :ref:`Documentation/process/deprecated.rst <deprecated>` 4:Translator: Sergio Gonzalez <sergio.collado@gmail.com> 5 6.. _sp_deprecated: 7 8============================================================================ 9Interfaces obsoletos, Características del lenguaje, Atributos y Convenciones 10============================================================================ 11 12En un mundo perfecto, sería posible convertir todas las instancias de 13alguna API obsoleta en una nueva API y quitar la API anterior en un 14único ciclo de desarrollo. Desafortunadamente, debido al tamaño del kernel, 15la jerarquía de mantenimiento, y el tiempo, no siempre es posible hacer 16estos cambios de una única vez. Esto significa que las nuevas instancias 17han de ir creándose en el kernel, mientras que las antiguas se quitan, 18haciendo que la cantidad de trabajo para limpiar las APIs crezca. Para 19informar a los desarrolladores sobre qué ha sido declarado obsoleto y por 20qué, ha sido creada esta lista como un lugar donde indicar cuando los usos 21obsoletos son propuestos para incluir en el kernel. 22 23__deprecated 24------------ 25Mientras que este atributo señala visualmente que un interface ha sido 26declarado obsoleto, este `no produce más avisos durante las compilaciones 27<https://git.kernel.org/linus/771c035372a036f83353eef46dbb829780330234>`_ 28porque uno de los objetivos del kernel es que compile sin avisos, y 29nadie ha hecho nada para quitar estos interfaces obsoletos. Mientras 30que usar `__deprecated` es sencillo para anotar una API obsoleta en 31un archivo de cabecera, no es la solución completa. Dichos interfaces 32deben o bien ser quitados por completo, o añadidos a este archivo para 33desanimar a otros a usarla en el futuro. 34 35BUG() y BUG_ON() 36---------------- 37Use WARN() y WARN_ON() en su lugar, y gestione las condiciones de error 38"imposibles" tan elegantemente como se pueda. Mientras que la familia de 39funciones BUG() fueron originalmente diseñadas para actuar como una 40"situación imposible", confirmar y disponer de un hilo del kernel de forma 41"segura", estas funciones han resultado ser demasiado arriesgadas. (e.g. 42"¿en qué orden se necesitan liberar los locks? ¿Se han restaurado sus 43estados?). La popular función BUG() desestabilizará el sistema o lo romperá 44totalmente, lo cual hace imposible depurarlo o incluso generar reportes de 45crash. Linus tiene una `opinión muy fuerte 46<https://lore.kernel.org/lkml/CA+55aFy6jNLsywVYdGp83AMrXBo_P-pkjkphPGrO=82SPKCpLQ@mail.gmail.com/>`_ 47y sentimientos `sobre esto 48<https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_. 49 50Nótese que la familia de funciones WARN() únicamente debería ser usada 51en situaciones que se "esperan no sean alcanzables". Si se quiere 52avisar sobre situaciones "alcanzables pero no deseadas", úsese la familia 53de funciones pr_warn(). Los responsables del sistema pueden haber definido 54*panic_on_warn* sysctl para asegurarse que sus sistemas no continúan 55ejecutándose en presencia del condiciones "no alcanzables". (Por ejemplo, 56véase commits como `este 57<https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_.) 58 59Operaciones aritméticas en los argumentos de reserva de memoria 60--------------------------------------------------------------- 61Los cálculos dinámicos de tamaño (especialmente multiplicaciones) no 62deberían realizarse en los argumentos de reserva de memoria (o similares) 63debido al riesgo de desbordamiento. Esto puede llevar a valores rotando y 64que se realicen reservas de memoria menores que las que se esperaban. El 65uso de esas reservas puede llevar a desbordamientos en el 'heap' de memoria 66y otros funcionamientos incorrectos. (Una excepción a esto son los valores 67literales donde el compilador si puede avisar si estos puede desbordarse. 68De todos modos, el método recomendado en estos caso es reescribir el código 69como se sugiere a continuación para evitar las operaciones aritméticas en 70la reserva de memoria.) 71 72Por ejemplo, no utilice `count * size`` como argumento, como en:: 73 74 foo = kmalloc(count * size, GFP_KERNEL); 75 76En vez de eso, utilice la reserva con dos argumentos:: 77 78 foo = kmalloc_array(count, size, GFP_KERNEL); 79 80Específicamente, kmalloc() puede ser sustituido con kmalloc_array(), 81kzalloc() puede ser sustituido con kcalloc(). 82 83Si no existen funciones con dos argumentos, utilice las funciones que se 84saturan, en caso de desbordamiento:: 85 86 bar = vmalloc(array_size(count, size)); 87 88Otro caso común a evitar es calcular el tamaño de una estructura com 89la suma de otras estructuras, como en:: 90 91 header = kzalloc(sizeof(*header) + count * sizeof(*header->item), 92 GFP_KERNEL); 93 94En vez de eso emplee:: 95 96 header = kzalloc(struct_size(header, item, count), GFP_KERNEL); 97 98.. note:: Si se usa struct_size() en una estructura que contiene un elemento 99 de longitud cero o un array de un único elemento como un array miembro, 100 por favor reescribir ese uso y cambiar a un `miembro array flexible 101 <#zero-length-and-one-element-arrays>`_ 102 103 104Para otros cálculos, por favor use las funciones de ayuda: size_mul(), 105size_add(), and size_sub(). Por ejemplo, en el caso de:: 106 107 foo = krealloc(current_size + chunk_size * (count - 3), GFP_KERNEL); 108 109Re-escríbase, como:: 110 111 foo = krealloc(size_add(current_size, 112 size_mul(chunk_size, 113 size_sub(count, 3))), GFP_KERNEL); 114 115Para más detalles, mire también array3_size() y flex_array_size(), 116como también la familia de funciones relacionadas check_mul_overflow(), 117check_add_overflow(), check_sub_overflow(), y check_shl_overflow(). 118 119 120simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull() 121---------------------------------------------------------------------- 122Las funciones: simple_strtol(), simple_strtoll(), simple_strtoul(), y 123simple_strtoull() explícitamente ignoran los desbordamientos, lo que puede 124llevar a resultados inesperados por las funciones que las llaman. Las 125funciones respectivas kstrtol(), kstrtoll(), kstrtoul(), y kstrtoull() 126tienden a ser reemplazos correctos, aunque nótese que necesitarán que la 127cadena de caracteres termine en NUL o en el carácter de línea nueva. 128 129 130strcpy() 131-------- 132strcpy() no realiza verificaciones de los límites del buffer de destino. 133Esto puede resultar en desbordamientos lineals más allá del fin del buffer, 134causando todo tipo de errores. Mientras `CONFIG_FORTIFY_SOURCE=y` otras 135varias opciones de compilación reducen el riesgo de usar esta función, no 136hay ninguna buena razón para añadir nuevos usos de esta. El remplazo seguro 137es la función strscpy(), aunque se ha de tener cuidado con cualquier caso 138en el el valor retornado por strcpy() sea usado, ya que strscpy() no 139devuelve un puntero a el destino, sino el número de caracteres no nulos 140compilados (o el valor negativo de errno cuando se trunca la cadena de 141caracteres). 142 143strncpy() en cadenas de caracteres terminadas en NUL 144---------------------------------------------------- 145El uso de strncpy() no garantiza que el buffer de destino esté terminado en 146NUL. Esto puede causar varios errores de desbordamiento en lectura y otros 147tipos de funcionamiento erróneo debido a que falta la terminación en NUL. 148Esta función también termina la cadena de caracteres en NUL en el buffer de 149destino si la cadena de origen es más corta que el buffer de destino, lo 150cual puede ser una penalización innecesaria para funciones usen esta 151función con cadenas de caracteres que sí están terminadas en NUL. 152 153Cuando se necesita que la cadena de destino sea terminada en NUL, 154el mejor reemplazo es usar la función strscpy(), aunque se ha de tener 155cuidado en los casos en los que el valor de strncpy() fuera usado, ya que 156strscpy() no devuelve un puntero al destino, sino el número de 157caracteres no nulos copiados (o el valor negativo de errno cuando se trunca 158la cadena de caracteres). Cualquier caso restante que necesitase todavía 159ser terminado en el caracter nulo, debería usar strscpy_pad(). 160 161Si una función usa cadenas de caracteres que no necesitan terminar en NUL, 162debería usarse strtomem(), y el destino debería señalarse con el atributo 163`__nonstring 164<https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_ 165para evitar avisos futuros en el compilador. Para casos que todavía 166necesitan cadenas de caracteres que se rellenen al final con el 167caracter NUL, usar strtomem_pad(). 168 169strlcpy() 170--------- 171strlcpy() primero lee por completo el buffer de origen (ya que el valor 172devuelto intenta ser el mismo que el de strlen()). Esta lectura puede 173sobrepasar el límite de tamaño del destino. Esto ineficiente y puede causar 174desbordamientos de lectura si la cadena de origen no está terminada en el 175carácter NUL. El reemplazo seguro de esta función es strscpy(), pero se ha 176de tener cuidado que en los casos en lso que se usase el valor devuelto de 177strlcpy(), ya que strscpy() devolverá valores negativos de erno cuando se 178produzcan truncados. 179 180Especificación de formato %p 181---------------------------- 182Tradicionalmente,el uso de "%p" en el formato de cadenas de caracteres 183resultaría en exponer esas direcciones en dmesg, proc, sysfs, etc. En vez 184de dejar que sean una vulnerabilidad, todos los "%p" que se usan en el 185kernel se imprimen como un hash, haciéndolos efectivamente inutilizables 186para usarlos como direcciones de memoria. Nuevos usos de "%p" no deberían 187ser añadidos al kernel. Para textos de direcciones, usar "%pS" es 188mejor, ya que resulta en el nombre del símbolo. Para prácticamente el 189resto de casos, mejor no usar "%p" en absoluto. 190 191Parafraseando las actuales `direcciones de Linus <https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_: 192 193- Si el valor "hasheado" "%p" no tienen ninguna finalidad, preguntarse si el 194 puntero es realmente importante. ¿Quizás se podría quitar totalmente? 195- Si realmente se piensa que el valor del puntero es importante, ¿porqué 196 algún estado del sistema o nivel de privilegio de usuario es considerado 197 "especial"? Si piensa que puede justificarse (en comentarios y mensajes 198 del commit), de forma suficiente como para pasar el escrutinio de Linux, 199 quizás pueda usar el "%p", a la vez que se asegura que tiene los permisos 200 correspondientes. 201 202Si está depurando algo donde el "%p" hasheado está causando problemas, 203se puede arrancar temporalmente con la opción de depuración "`no_hash_pointers 204<https://git.kernel.org/linus/5ead723a20e0447bc7db33dc3070b420e5f80aa6>`_". 205 206 207Arrays de longitud variable (VLAs) 208---------------------------------- 209Usando VLA en la pila (stack) produce un código mucho peor que los arrays 210de tamaño estático. Mientras que estos errores no triviales de `rendimiento 211<https://git.kernel.org/linus/02361bc77888>`_ son razón suficiente 212para no usar VLAs, esto además son un riesgo de seguridad. El crecimiento 213dinámico del array en la pila, puede exceder la memoria restante en 214el segmento de la pila. Esto podría llevara a un fallo, posible sobre-escritura 215de contenido al final de la pila (cuando se construye sin 216`CONFIG_THREAD_INFO_IN_TASK=y`), o sobre-escritura de la memoria adyacente 217a la pila (cuando se construye sin `CONFIG_VMAP_STACK=y`). 218 219 220Switch case fall-through implícito 221---------------------------------- 222El lenguaje C permite a las sentencias 'switch' saltar de un caso al 223siguiente caso cuando la sentencia de ruptura "break" no aparece al final 224del caso. Esto, introduce ambigüedad en el código, ya que no siempre está 225claro si el 'break' que falta es intencionado o un olvido. Por ejemplo, no 226es obvio solamente mirando al código si `STATE_ONE` está escrito para 227intencionadamente saltar en `STATE_TWO`:: 228 229 switch (value) { 230 case STATE_ONE: 231 do_something(); 232 case STATE_TWO: 233 do_other(); 234 break; 235 default: 236 WARN("unknown state"); 237 } 238 239Ya que ha habido una larga lista de defectos `debidos a declaraciones de "break" 240que faltan <https://cwe.mitre.org/data/definitions/484.html>`_, no se 241permiten 'fall-through' implícitos. Para identificar 'fall-through' 242intencionados, se ha adoptado la pseudo-palabra-clave macro "falltrhrough", 243que expande las extensiones de gcc `__attribute__((__fallthrough__)) 244<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_. 245(Cuando la sintaxis de C17/c18 `[[fallthrough]]` sea más comúnmente 246soportadas por los compiladores de C, analizadores estáticos, e IDEs, 247se puede cambiar a usar esa sintaxis para esa pseudo-palabra-clave. 248 249Todos los bloques switch/case deben acabar en uno de: 250 251* break; 252* fallthrough; 253* continue; 254* goto <label>; 255* return [expression]; 256 257 258Arrays de longitud cero y un elemento 259------------------------------------- 260Hay una necesidad habitual en el kernel de proveer una forma para declarar 261un grupo de elementos consecutivos de tamaño dinámico en una estructura. 262El código del kernel debería usar siempre `"miembros array flexible" <https://en.wikipedia.org/wiki/Flexible_array_member>`_ 263en estos casos. El estilo anterior de arrays de un elemento o de longitud 264cero, no deben usarse más. 265 266En el código C más antiguo, los elementos finales de tamaño dinámico se 267obtenían especificando un array de un elemento al final de una estructura:: 268 269 struct something { 270 size_t count; 271 struct foo items[1]; 272 }; 273 274En código C más antiguo, elementos seguidos de tamaño dinámico eran creados 275especificando una array de un único elemento al final de una estructura:: 276 277 struct something { 278 size_t count; 279 struct foo items[1]; 280 }; 281 282Esto llevó a resultados incorrectos en los cálculos de tamaño mediante 283sizeof() (el cual hubiera necesitado eliminar el tamaño del último elemento 284para tener un tamaño correcto de la "cabecera"). Una `extensión de GNU C 285<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_ se empezó a usar 286para permitir los arrays de longitud cero, para evitar estos tipos de 287problemas de tamaño:: 288 289 struct something { 290 size_t count; 291 struct foo items[0]; 292 }; 293 294Pero esto llevó a otros problemas, y no solucionó algunos otros problemas 295compartidos por ambos estilos, como no ser capaz de detectar cuando ese array 296accidentalmente _no_ es usado al final de la estructura (lo que podía pasar 297directamente, o cuando dicha estructura era usada en uniones, estructuras 298de estructuras, etc). 299 300C99 introdujo "los arrays miembros flexibles", los cuales carecen de un 301tamaño numérico en su declaración del array:: 302 303 struct something { 304 size_t count; 305 struct foo items[]; 306 }; 307 308Esta es la forma en la que el kernel espera que se declaren los elementos 309de tamaño dinámico concatenados. Esto permite al compilador generar 310errores, cuando el array flexible no es declarado en el último lugar de la 311estructura, lo que ayuda a prevenir errores en él código del tipo 312`comportamiento indefinido <https://git.kernel.org/linus/76497732932f15e7323dc805e8ea8dc11bb587cf>`_. 313Esto también permite al compilador analizar correctamente los tamaños de 314los arrays (via sizeof(), `CONFIG_FORTIFY_SOURCE`, y `CONFIG_UBSAN_BOUNDS`). 315Por ejemplo, si no hay un mecanismo que avise que el siguiente uso de 316sizeof() en un array de longitud cero, siempre resulta en cero:: 317 318 struct something { 319 size_t count; 320 struct foo items[0]; 321 }; 322 323 struct something *instance; 324 325 instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL); 326 instance->count = count; 327 328 size = sizeof(instance->items) * instance->count; 329 memcpy(instance->items, source, size); 330 331En la última línea del código anterior, ``zero`` vale ``cero``, cuando uno 332podría esperar que representa el tamaño total en bytes de la memoria dinámica 333reservada para el array consecutivo ``items``. Aquí hay un par de ejemplos 334más sobre este tema: `link 1 335<https://git.kernel.org/linus/f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_, 336`link 2 337<https://git.kernel.org/linus/ab91c2a89f86be2898cee208d492816ec238b2cf>`_. 338Sin embargo, los array de miembros flexibles tienen un type incompleto, y 339no se ha de aplicar el operador sizeof()<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, 340así cualquier mal uso de dichos operadores será detectado inmediatamente en 341el momento de compilación. 342 343Con respecto a los arrays de un único elemento, se ha de ser consciente de 344que dichos arrays ocupan al menos tanto espacio como un único objeto del 345tipo https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, de ahí que 346estos contribuyan al tamaño de la estructura que los contiene. Esto es 347proclive a errores cada vez que se quiere calcular el tamaño total de la 348memoria dinámica para reservar una estructura que contenga un array de este 349tipo como su miembro:: 350 351 struct something { 352 size_t count; 353 struct foo items[1]; 354 }; 355 356 struct something *instance; 357 358 instance = kmalloc(struct_size(instance, items, count - 1), GFP_KERNEL); 359 instance->count = count; 360 361 size = sizeof(instance->items) * instance->count; 362 memcpy(instance->items, source, size); 363 364En el ejemplo anterior, hemos de recordar calcular ``count - 1``, cuando se 365usa la función de ayuda struct_size(), de otro modo estaríamos 366--desintencionadamente--reservando memoria para un ``items`` de más. La 367forma más clara y menos proclive a errores es implementar esto mediante el 368uso de `array miembro flexible`, junto con las funciones de ayuda: 369struct_size() y flex_array_size():: 370 371 struct something { 372 size_t count; 373 struct foo items[]; 374 }; 375 376 struct something *instance; 377 378 instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL); 379 instance->count = count; 380 381 memcpy(instance->items, source, flex_array_size(instance, items, instance->count)); 382