xref: /linux/Documentation/translations/pt_BR/process/deprecated.rst (revision 72fdff1416e280e2baaa3cca69574defb998437e)
1.. SPDX-License-Identifier: GPL-2.0
2
3========================================================================
4Interfaces, recursos de linguagem, atributos e convenções obsoletos
5========================================================================
6
7Em um mundo perfeito, seria possível converter todas as instâncias de alguma
8API obsoleta para a nova API e remover completamente a API antiga em um único
9ciclo de desenvolvimento. No entanto, devido ao tamanho do kernel, à hierarquia
10de manutenção e ao cronograma, nem sempre é viável realizar esse tipo de
11conversão de uma só vez. Isso significa que novas instâncias podem acabar
12entrando no kernel enquanto as antigas estão sendo removidas, apenas aumentando
13o volume de trabalho para remover a API. A fim de instruir os desenvolvedores
14sobre o que se tornou obsoleto e o porquê, esta lista foi criada para servir de
15referência quando o uso de elementos obsoletos for proposto para inclusão no
16kernel.
17
18__deprecated
19------------
20Embora este atributo marque visualmente uma interface como obsoleta, ele `não
21gera mais avisos durante as compilações
22<https://git.kernel.org/linus/771c035372a036f83353eef46dbb829780330234>`_ porque
23um dos objetivos permanentes do kernel é compilar sem avisos (*warnings*), e
24ninguém estava de fato agindo para remover essas interfaces obsoletas. Embora o
25uso de `__deprecated` seja útil para sinalizar uma API antiga em um arquivo de
26cabeçalho (*header file*), não é a solução completa. Tais interfaces devem ser
27totalmente removidas do kernel ou adicionadas a este arquivo para desestimular
28outros desenvolvedores de usá-las no futuro.
29
30BBUG() e BUG_ON()
31-----------------
32Em vez disso, use WARN() e WARN_ON() e trate a condição de erro "impossível"
33da forma mais amigável possível. Embora a família de APIs BUG() tenha sido
34originalmente projetada para agir como uma asserção de "situação impossível" e
35eliminar uma thread do kernel de forma "segura", ela se mostrou arriscada
36demais. (Por exemplo: "Em que ordem os bloqueios precisam ser liberados? Os
37diversos estados foram restaurados?") Muito frequentemente, o uso de BUG() vai
38desestabilizar o sistema ou travá-lo por completo, o que torna impossível
39depurar ou até mesmo obter relatórios de travamento (*crash reports*) viáveis.
40Linus tem opiniões `muito fortes
41<https://lore.kernel.org/lkml/CA+55aFy6jNLsywVYdGp83AMrXBo_P-pkjkphPGrO=82SPKCpLQ@mail.gmail.com/>`_
42`sobre isso
43<https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_.
44
45Note que a família WARN() só deve ser usada para situações que "espera-se que
46sejam inacessíveis". Se você quiser alertar sobre situações que são
47"acessíveis, mas indesejáveis", use a família de funções pr_warn(). Os
48administradores do sistema podem ter configurado o sysctl *panic_on_warn* para
49garantir que seus sistemas não continuem executando diante de condições
50"inacessíveis". (Para exemplos, veja commits como `este aqui
51<https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_.)
52
53Aritmética explícita em argumentos do alocador
54----------------------------------------------
55Cálculos dinâmicos de tamanho (especialmente multiplicação) não devem ser
56realizados em argumentos de funções de alocação de memória (ou similares)
57devido ao risco de estouro de capacidade (*overflow*). Isso poderia fazer com
58que os valores dessem a volta (*wrap around*), resultando em uma alocação menor
59do que o esperado pelo chamador. O uso dessas alocações pode levar a estouros
60lineares na memória heap e a outros comportamentos incorretos. (Uma exceção a
61isso são valores literais onde o compilador pode emitir um aviso se houver
62risco de estouro. No entanto, a maneira preferível nesses casos é refatorar o
63código conforme sugerido abaixo para evitar a aritmética explícita.)
64
65Por exemplo, não use ``count * size`` como argumento, como em::
66
67        foo = kmalloc(count * size, GFP_KERNEL);
68
69Em vez disso, a forma de dois fatores do alocador deve ser utilizada::
70
71        foo = kmalloc_array(count, size, GFP_KERNEL);
72
73Especificamente, kmalloc() pode ser substituído por kmalloc_array(), e
74kzalloc() pode ser substituído por kcalloc().
75
76Se nenhuma forma de dois fatores estiver disponível, os auxiliares de
77saturação em estouro (*saturate-on-overflow*) devem ser usados::
78
79        bar = dma_alloc_coherent(dev, array_size(count, size), &dma, GFP_KERNEL);
80
81Outro caso comum a ser evitado é calcular o tamanho de uma estrutura com uma
82matriz final de outras estruturas, como em::
83
84        header = kzalloc(sizeof(*header) + count * sizeof(*header->item),
85                         GFP_KERNEL);
86
87Em vez disso, use o auxiliar::
88
89        header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
90
91.. note:: Se você estiver usando struct_size() em uma estrutura que contém uma
92        matriz de comprimento zero ou de um único elemento como membro final,
93        refatore o uso dessa matriz e mude para um `membro de matriz flexível
94        <#zero-length-and-one-element-arrays>`_ em seu lugar.
95
96Para outros cálculos, faça a composição usando os auxiliares size_mul(),
97size_add() e size_sub(). Por exemplo, no caso de::
98
99        foo = krealloc(current_size + chunk_size * (count - 3), GFP_KERNEL);
100
101Em vez disso, use os auxiliares::
102
103        foo = krealloc(size_add(current_size,
104                                size_mul(chunk_size,
105                                         size_sub(count, 3))), GFP_KERNEL);
106
107Para mais detalhes, veja também array3_size() e flex_array_size(), bem como as
108funções relacionadas das famílias check_mul_overflow(), check_add_overflow(),
109check_sub_overflow() e check_shl_overflow().\
110
111simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
112----------------------------------------------------------------------
113As funções simple_strtol(), simple_strtoll(), simple_strtoul() e
114simple_strtoull() ignoram explicitamente estouros de capacidade (*overflows*),
115o que pode levar a resultados inesperados nos chamadores. As respectivas
116funções kstrtol(), kstrtoll(), kstrtoul() e kstrtoull() tendem a ser as
117substitutas corretas, embora se deva notar que estas exigem que a string seja
118terminada em NUL ou em nova linha (*newline*).
119
120strcpy()
121--------
122A função strcpy() não realiza verificação de limites no buffer de destino.
123Isso pode resultar em estouros lineares além do final do buffer, levando a todo
124tipo de comportamentos incorretos. Embora ``CONFIG_FORTIFY_SOURCE=y`` e várias
125opções do compilador ajudem a reduzir o risco de usar esta função, não há uma
126boa razão para adicionar novos usos dela. A substituta segura é strscpy(),
127embora se deva ter cuidado nos casos em que o valor de retorno de strcpy() era
128utilizado, já que strscpy() não retorna um ponteiro para o destino, mas sim a
129quantidade de bytes não-NUL copiados (ou um código de erro errno negativo quando
130ocorre truncamento).
131
132strncpy()
133---------
134A função strncpy() foi removida do kernel. Todos os chamadores antigos foram
135migrados para alternativas mais seguras.
136
137A função strncpy() não garantia a terminação em NUL do buffer de destino,
138levando a estouros de leitura linear e outros comportamentos incorretos. Ela
139também preenchia incondicionalmente o destino com NUL, o que representava uma
140penalidade de desempenho desnecessária para chamadores que usavam apenas
141strings terminadas em NUL. Devido aos seus diversos comportamentos, ela era uma
142API ambígua para determinar qual era a real intenção do autor ao realizar a
143cópia.
144
145As substitutas para strncpy() são:
146
147- strscpy() quando o destino deve ser terminado em NUL.
148- strscpy_pad() quando o destino deve ser terminado em NUL e preenchido com
149  zeros (por exemplo, estruturas que cruzam fronteiras de privilégio).
150- memtostr() para destinos terminados em NUL a partir de origens de largura
151  fixa não terminadas em NUL (com o atributo ``__nonstring`` na origem).
152- memtostr_pad() para o mesmo caso anterior, mas com preenchimento de zeros.
153- strtomem() para destinos de largura fixa não terminados em NUL, com o
154  atributo ``__nonstring`` no destino.
155- strtomem_pad() para destinos não terminados em NUL que também precisam de
156  preenchimento com zeros.
157- memcpy_and_pad() para cópias limitadas a partir de origens potencialmente não
158  terminadas, onde o tamanho do destino é um valor definido em tempo de
159  execução (*runtime*).
160
161strlcpy()
162---------
163A função strlcpy() lê primeiro todo o buffer de origem (já que o valor de
164retorno deve corresponder ao de strlen()). Essa leitura pode exceder o limite
165de tamanho do destino. Isso é ineficiente e pode levar a estouros de leitura
166linear se a string de origem não for terminada em NUL. A substituta segura é
167strscpy(), embora se deva ter cuidado nos casos em que o valor de retorno de
168strlcpy() é utilizado, já que strscpy() retornará valores negativos de errno
169quando houver truncamento.
170
171Especificador de formato %p
172----------------------------
173Tradicionalmente, o uso de "%p" em strings de formatação causava falhas de
174exposição de endereços reais no dmesg, proc, sysfs, etc. Em vez de deixar esses
175endereços expostos a explorações, todos os usos de "%p" no kernel agora são
176exibidos como um valor hash, tornando-os inúteis para fins de endereçamento.
177Novos usos de "%p" não devem ser adicionados ao kernel. Para endereços de texto,
178usar "%pS" costuma ser melhor, pois exibe o nome do símbolo, que é muito mais
179útil. Para quase todo o restante, simplesmente não adicione "%p" de forma
180alguma.
181
182Parafraseando as diretrizes atuais do Linus `guidance
183<https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_:
184
185- Se o valor hash de "%p" é inútil, pergunte a si mesmo se o ponteiro em si é
186  importante. Talvez ele deva ser removido por completo?
187- Se você realmente acredita que o valor real do ponteiro é importante, por que
188  algum estado do sistema ou nível de privilégio do usuário seria considerado
189  "especial"? Se você acha que pode justificar isso (em comentários e no log de
190  commit) de forma sólida o suficiente para resistir ao escrutínio do Linus,
191  talvez possa usar "%px", certificando-se de aplicar permissões adequadas.
192
193Se você estiver depurando algo em que a geração de hash de "%p" esteja causando
194problemas, é possível inicializar o sistema temporariamente com a opção de
195depuração "`no_hash_pointers
196<https://git.kernel.org/linus/5ead723a20e0447bc7db33dc3070b420e5f80aa6>`_".
197
198Matrizes de Tamanho Variável (VLAs)
199-----------------------------------
200O uso de VLAs (Variable Length Arrays) na pilha de execução gera um código de
201máquina muito pior do que matrizes de tamanho estático na pilha. Embora esses
202problemas significativos de `desempenho
203<https://git.kernel.org/linus/02361bc77888>`_ sejam motivo suficiente para
204eliminar as VLAs, elas também representam um risco de segurança. O crescimento
205dinâmico de uma matriz na pilha pode exceder a memória restante no segmento da
206pilha. Isso pode levar a um travamento, à possível sobrescrita de dados
207sensíveis no final da pilha (quando compilado sem ``CONFIG_THREAD_INFO_IN_TASK=y``)
208ou à sobrescrita de posições de memória adjacentes à pilha (quando compilado sem
209``CONFIG_VMAP_STACK=y``).
210
211Passagem direta implícita no switch case (fall-through)
212-------------------------------------------------------
213A linguagem C permite que o fluxo de execução de um bloco switch passe
214diretamente para o próximo caso (fall-through) quando uma instrução "break"
215está ausente ao final de um caso. No entanto, isso introduz ambiguidade no
216código, pois nem sempre fica claro se o "break" ausente é intencional ou um bug.
217Por exemplo, não é óbvio apenas olhando para o código se o ``STATE_ONE`` foi
218intencionalmente projetado para passar diretamente para o ``STATE_TWO``::
219
220        switch (value) {
221        case STATE_ONE:
222                do_something();
223        case STATE_TWO:
224                do_other();
225                break;
226        default:
227                WARN("unknown state");
228        }
229
230Como há uma longa lista de falhas `causadas pela ausência de instruções "break"
231<https://cwe.mitre.org/data/definitions/484.html>`_, não permitimos mais a
232passagem direta implícita. Para identificar os casos de passagem direta
233intencionais, adotamos a macro pseudo-palavra-chave "fallthrough", que se
234expande para a extensão do gcc `__attribute__((__fallthrough__))
235<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_. (Quando a
236sintaxe ``[[fallthrough]]`` do C17/C18 for suportada de forma mais ampla por
237compiladores C, analisadores estáticos e IDEs, poderemos mudar para o uso dessa
238sintaxe para a pseudo-palavra-chave da macro.)
239
240Todos os blocos de switch/case devem terminar com um dos seguintes elementos:
241
242* break;
243* fallthrough;
244* continue;
245* goto <rótulo>;
246* return [expressão];
247
248Matrizes de comprimento zero e de um único elemento
249----------------------------------------------------
250Há uma necessidade frequente no kernel de fornecer uma maneira de declarar uma
251estrutura com um conjunto de elementos finais de tamanho dinâmico. O código do
252kernel deve sempre usar `"membros de matriz flexível"
253<https://en.wikipedia.org/wiki/Flexible_array_member>`_ para esses casos. O
254estilo antigo de matrizes de um único elemento ou de comprimento zero não deve
255mais ser utilizado.
256
257No código C mais antigo, elementos finais de tamanho dinâmico eram declarados
258especificando uma matriz de um elemento ao final de uma estrutura::
259
260        struct something {
261                size_t count;
262                struct foo items[1];
263        };
264
265Isso levava a cálculos de tamanho frágeis via sizeof() (que exigiam a subtração
266do tamanho do elemento final único para obter o tamanho correto do "cabeçalho").
267Uma `extensão GNU C <https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_ foi
268introduzida para permitir matrizes de comprimento zero, a fim de evitar esses
269problemas de cálculo de tamanho::
270
271        struct something {
272                size_t count;
273                struct foo items[0];
274        };
275
276No entanto, isso trouxe outros problemas e não resolveu algumas limitações de
277ambos os estilos, como a incapacidade de detectar quando tal matriz é usada
278acidentalmente *fora* do final de uma estrutura (o que poderia ocorrer
279diretamente, ou quando tal estrutura estava contida em unions, estruturas de
280estruturas, etc.).
281
282O padrão C99 introduziu os "membros de matriz flexível", nos quais a declaração
283da matriz simplesmente não possui um tamanho numérico::
284
285        struct something {
286                size_t count;
287                struct foo items[];
288        };
289
290Esta é a maneira como o kernel espera que elementos finais de tamanho dinâmico
291sejam declarados. Isso permite que o compilador gere erros quando a matriz
292flexível não for o último elemento da estrutura, o que ajuda a evitar que bugs
293de `comportamento indefinido
294<https://git.kernel.org/linus/76497732932f15e7323dc805e8ea8dc11bb587cf>`_ sejam
295introduzidos inadvertidamente na base de código. Também permite que o
296compilador analise corretamente os tamanhos das matrizes (via sizeof(),
297``CONFIG_FORTIFY_SOURCE`` e ``CONFIG_UBSAN_BOUNDS``). Por exemplo, não existe um
298mecanismo que nos alerte de que a seguinte aplicação do operador sizeof() a uma
299matriz de comprimento zero sempre resulta em zero::
300
301        struct something {
302                size_t count;
303                struct foo items[0];
304        };
305
306        struct something *instance;
307
308        instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
309        instance->count = count;
310
311        size = sizeof(instance->items) * instance->count;
312        memcpy(instance->items, source, size);
313
314Na última linha do código acima, ``size`` acaba sendo ``zero``, quando se
315poderia pensar que ele representaria o tamanho total em bytes da memória
316dinâmica recentemente alocada para a matriz final ``items``. Aqui estão alguns
317exemplos deste problema: `link 1
318<https://git.kernel.org/linus/f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_,
319`link 2
320<https://git.kernel.org/linus/ab91c2a89f86be2898cee208d492816ec238b2cf>`_.
321Em vez disso, `membros de matriz flexível têm tipo incompleto e, portanto, o
322operador sizeof() não pode ser aplicado
323<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, de modo que qualquer
324uso incorreto de tais operadores será imediatamente percebido em tempo de
325compilação.
326
327Em relação às matrizes de um único elemento, é preciso estar muito ciente de que
328`tais matrizes ocupam pelo menos o mesmo espaço que um único objeto daquele tipo
329<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_ e, portanto, contribuem
330para o tamanho da estrutura que as contém. Isso é propício a erros sempre que se
331deseja calcular o tamanho total da memória dinâmica a ser alocada para uma
332estrutura que contém uma matriz desse tipo como membro::
333
334        struct something {
335                size_t count;
336                struct foo items[1];
337        };
338
339        struct something *instance;
340
341        instance = kmalloc(struct_size(instance, items, count - 1), GFP_KERNEL);
342        instance->count = count;
343
344        size = sizeof(instance->items) * instance->count;
345        memcpy(instance->items, source, size);
346
347No exemplo acima, foi necessário lembrar de calcular ``count - 1`` ao usar o
348auxiliar struct_size(); caso contrário, teríamos alocado memória --de forma não
349intencional-- para um objeto ``items`` a mais. A maneira mais limpa e menos
350sujeita a erros de implementar isso é através do uso de um `membro de matriz
351flexível`, em conjunto com os auxiliares struct_size() e flex_array_size()::
352
353        struct something {
354                size_t count;
355                struct foo items[];
356        };
357
358        struct something *instance;
359
360        instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
361        instance->count = count;
362
363        memcpy(instance->items, source, flex_array_size(instance, items, instance->count));
364
365Existem dois casos especiais de substituição nos quais o auxiliar
366DECLARE_FLEX_ARRAY() precisa ser utilizado. (Note que ele é nomeado
367__DECLARE_FLEX_ARRAY() para uso em cabeçalhos de UAPI.) Esses casos ocorrem
368quando a matriz flexível está sozinha em uma estrutura ou faz parte de uma
369union. Isso não é permitido pela especificação C99, mas sem justificativa
370técnica (como pode ser visto tanto pelo uso existente de tais matrizes nesses
371locais quanto pela solução alternativa que DECLARE_FLEX_ARRAY() adota). Por
372exemplo, para converter isto::
373
374        struct something {
375                ...
376                union {
377                        struct type1 one[0];
378                        struct type2 two[0];
379                };
380        };
381
382O auxiliar deve ser utilizado::
383
384        struct something {
385                ...
386                union {
387                        DECLARE_FLEX_ARRAY(struct type1, one);
388                        DECLARE_FLEX_ARRAY(struct type2, two);
389                };
390        };
391
392Atribuições diretas de kmalloc para objetos struct
393--------------------------------------------------
394Realizar atribuições diretas (*open-coded*) de alocações da família kmalloc()
395impede que o kernel (e o compilador) consigam examinar o tipo da variável que
396está recebendo a atribuição, o que limita qualquer introspecção relacionada que
397possa ajudar com alinhamento, estouros de capacidade (*wrap-around*) ou
398proteções adicionais (*hardening*). A família de macros kmalloc_obj() fornece
399essa introspecção, que pode ser usada para os padrões de código comuns de
400alocações de objetos únicos, de matrizes ou de objetos flexíveis. Por exemplo,
401estas atribuições diretas::
402
403        ptr = kmalloc(sizeof(*ptr), gfp);
404        ptr = kzalloc(sizeof(*ptr), gfp);
405        ptr = kmalloc_array(count, sizeof(*ptr), gfp);
406        ptr = kcalloc(count, sizeof(*ptr), gfp);
407        ptr = kmalloc(struct_size(ptr, flex_member, count), gfp);
408        ptr = kmalloc(sizeof(struct foo), gfp);
409
410tornam-se, respectivamente::
411
412        ptr = kmalloc_obj(*ptr [, gfp] );
413        ptr = kzalloc_obj(*ptr [, gfp] );
414        ptr = kmalloc_objs(*ptr, count [, gfp] );
415        ptr = kzalloc_objs(*ptr, count [, gfp] );
416        ptr = kmalloc_flex(*ptr, flex_member, count [, gfp] );
417        __auto_type ptr = kmalloc_obj(struct foo [, gfp] );
418
419O argumento gfp é opcional, sendo o valor padrão GFP_KERNEL. Se
420``ptr->flex_member`` estiver anotado com __counted_by(), a alocação falhará
421automaticamente caso ``count`` seja maior do que o valor máximo representável
422que pode ser armazenado no membro contador associado a ``flex_member``.
423