xref: /linux/Documentation/translations/sp_SP/process/deprecated.rst (revision fd7d598270724cc787982ea48bbe17ad383a8b7f)
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