1.. SPDX-License-Identifier: GPL-2.0
2
3.. include:: ../disclaimer-ita.rst
4
5:Original: :ref:`Documentation/process/deprecated.rst <deprecated>`
6:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
7
8.. _it_deprecated:
9
10==============================================================================
11Interfacce deprecate, caratteristiche del linguaggio, attributi, e convenzioni
12==============================================================================
13
14In un mondo perfetto, sarebbe possibile prendere tutti gli usi di
15un'interfaccia deprecata e convertirli in quella nuova, e così sarebbe
16possibile rimuovere la vecchia interfaccia in un singolo ciclo di sviluppo.
17Tuttavia, per via delle dimensioni del kernel, la gerarchia dei manutentori e
18le tempistiche, non è sempre possibile fare questo tipo di conversione tutta
19in una volta. Questo significa che nuove istanze di una vecchia interfaccia
20potrebbero aggiungersi al kernel proprio quando si sta cercando di rimuoverle,
21aumentando così il carico di lavoro. Al fine di istruire gli sviluppatori su
22cosa è considerato deprecato (e perché), è stata create la seguente lista a cui
23fare riferimento quando qualcuno propone modifiche che usano cose deprecate.
24
25__deprecated
26------------
27Nonostante questo attributo marchi visibilmente un interfaccia come deprecata,
28`non produce più alcun avviso durante la compilazione
29<https://git.kernel.org/linus/771c035372a036f83353eef46dbb829780330234>`_
30perché uno degli obiettivi del kernel è quello di compilare senza avvisi;
31inoltre, nessuno stava agendo per rimuovere queste interfacce. Nonostante l'uso
32di `__deprecated` in un file d'intestazione sia opportuno per segnare una
33interfaccia come 'vecchia', questa non è una soluzione completa. L'interfaccia
34deve essere rimossa dal kernel, o aggiunta a questo documento per scoraggiarne
35l'uso.
36
37BUG() e BUG_ON()
38----------------
39Al loro posto usate WARN() e WARN_ON() per gestire le
40condizioni "impossibili" e gestitele come se fosse possibile farlo.
41Nonostante le funzioni della famiglia BUG() siano state progettate
42per asserire "situazioni impossibili" e interrompere in sicurezza un
43thread del kernel, queste si sono rivelate essere troppo rischiose
44(per esempio, in quale ordine rilasciare i *lock*? Ci sono stati che
45sono stati ripristinati?). Molto spesso l'uso di BUG()
46destabilizza il sistema o lo corrompe del tutto, il che rende
47impossibile un'attività di debug o anche solo leggere un rapporto
48circa l'errore.  Linus ha un'opinione molto critica al riguardo:
49`email 1
50<https://lore.kernel.org/lkml/CA+55aFy6jNLsywVYdGp83AMrXBo_P-pkjkphPGrO=82SPKCpLQ@mail.gmail.com/>`_,
51`email 2
52<https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_
53
54Tenete presente che la famiglia di funzioni WARN() dovrebbe essere
55usato solo per situazioni che si suppone siano "impossibili".  Se
56volete avvisare gli utenti riguardo a qualcosa di possibile anche se
57indesiderato, usare le funzioni della famiglia pr_warn().  Chi
58amministra il sistema potrebbe aver attivato l'opzione sysctl
59*panic_on_warn* per essere sicuri che il sistema smetta di funzionare
60in caso si verifichino delle condizioni "inaspettate". (per esempio,
61date un'occhiata al questo `commit
62<https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_)
63
64Calcoli codificati negli argomenti di un allocatore
65----------------------------------------------------
66Il calcolo dinamico delle dimensioni (specialmente le moltiplicazioni) non
67dovrebbero essere fatto negli argomenti di funzioni di allocazione di memoria
68(o simili) per via del rischio di overflow. Questo può portare a valori più
69piccoli di quelli che il chiamante si aspettava. L'uso di questo modo di
70allocare può portare ad un overflow della memoria di heap e altri
71malfunzionamenti. (Si fa eccezione per valori numerici per i quali il
72compilatore può generare avvisi circa un potenziale overflow. Tuttavia usare
73i valori numerici come suggerito di seguito è innocuo).
74
75Per esempio, non usate ``count * size`` come argomento::
76
77	foo = kmalloc(count * size, GFP_KERNEL);
78
79Al suo posto, si dovrebbe usare l'allocatore a due argomenti::
80
81	foo = kmalloc_array(count, size, GFP_KERNEL);
82
83Se questo tipo di allocatore non è disponibile, allora dovrebbero essere usate
84le funzioni del tipo *saturate-on-overflow*::
85
86	bar = vmalloc(array_size(count, size));
87
88Un altro tipico caso da evitare è quello di calcolare la dimensione di una
89struttura seguita da un vettore di altre strutture, come nel seguente caso::
90
91	header = kzalloc(sizeof(*header) + count * sizeof(*header->item),
92			 GFP_KERNEL);
93
94Invece, usate la seguente funzione::
95
96	header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
97
98Per maggiori dettagli fate riferimento a array_size(),
99array3_size(), e struct_size(), così come la famiglia di
100funzioni check_add_overflow() e check_mul_overflow().
101
102simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
103----------------------------------------------------------------------
104Le funzioni simple_strtol(), simple_strtoll(),
105simple_strtoul(), e simple_strtoull() ignorano volutamente
106i possibili overflow, e questo può portare il chiamante a generare risultati
107inaspettati. Le rispettive funzioni kstrtol(), kstrtoll(),
108kstrtoul(), e kstrtoull() sono da considerarsi le corrette
109sostitute; tuttavia va notato che queste richiedono che la stringa sia
110terminata con il carattere NUL o quello di nuova riga.
111
112strcpy()
113--------
114La funzione strcpy() non fa controlli agli estremi del buffer
115di destinazione. Questo può portare ad un overflow oltre i limiti del
116buffer e generare svariati tipi di malfunzionamenti. Nonostante l'opzione
117`CONFIG_FORTIFY_SOURCE=y` e svariate opzioni del compilatore aiutano
118a ridurne il rischio, non c'è alcuna buona ragione per continuare ad usare
119questa funzione. La versione sicura da usare è strscpy().
120
121strncpy() su stringe terminate con NUL
122--------------------------------------
123L'utilizzo di strncpy() non fornisce alcuna garanzia sul fatto che
124il buffer di destinazione verrà terminato con il carattere NUL. Questo
125potrebbe portare a diversi overflow di lettura o altri malfunzionamenti
126causati, appunto, dalla mancanza del terminatore. Questa estende la
127terminazione nel buffer di destinazione quando la stringa d'origine è più
128corta; questo potrebbe portare ad una penalizzazione delle prestazioni per
129chi usa solo stringe terminate. La versione sicura da usare è
130strscpy(). (chi usa strscpy() e necessita di estendere la
131terminazione con NUL deve aggiungere una chiamata a memset())
132
133Se il chiamate no usa stringhe terminate con NUL, allore strncpy()()
134può continuare ad essere usata, ma i buffer di destinazione devono essere
135marchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
136per evitare avvisi durante la compilazione.
137
138strlcpy()
139---------
140La funzione strlcpy(), per prima cosa, legge interamente il buffer di
141origine, magari leggendo più di quanto verrà effettivamente copiato. Questo
142è inefficiente e può portare a overflow di lettura quando la stringa non è
143terminata con NUL. La versione sicura da usare è strscpy().
144
145Segnaposto %p nella stringa di formato
146--------------------------------------
147
148Tradizionalmente, l'uso del segnaposto "%p" nella stringa di formato
149esponne un indirizzo di memoria in dmesg, proc, sysfs, eccetera.  Per
150evitare che questi indirizzi vengano sfruttati da malintenzionati,
151tutto gli usi di "%p" nel kernel rappresentano l'hash dell'indirizzo,
152rendendolo di fatto inutilizzabile.  Nuovi usi di "%p" non dovrebbero
153essere aggiunti al kernel.  Per una rappresentazione testuale di un
154indirizzo usate "%pS", l'output è migliore perché mostrerà il nome del
155simbolo.  Per tutto il resto, semplicemente non usate "%p".
156
157Parafrasando la `guida
158<https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_
159di Linus:
160
161- Se il valore hash di "%p" è inutile, chiediti se il puntatore stesso
162  è importante. Forse dovrebbe essere rimosso del tutto?
163- Se credi davvero che il vero valore del puntatore sia importante,
164  perché alcuni stati del sistema o i livelli di privilegi di un
165  utente sono considerati "special"? Se pensi di poterlo giustificare
166  (in un commento e nel messaggio del commit) abbastanza bene da
167  affrontare il giudizio di Linus, allora forse potrai usare "%px",
168  assicurandosi anche di averne il permesso.
169
170Infine, sappi che un cambio in favore di "%p" con hash `non verrà
171accettato
172<https://lore.kernel.org/lkml/CA+55aFwieC1-nAs+NFq9RTwaR8ef9hWa4MjNBWL41F-8wM49eA@mail.gmail.com/>`_.
173
174Vettori a dimensione variabile (VLA)
175------------------------------------
176
177Usare VLA sullo stack produce codice molto peggiore rispetto a quando si usano
178vettori a dimensione fissa. Questi `problemi di prestazioni <https://git.kernel.org/linus/02361bc77888>`_,
179tutt'altro che banali, sono già un motivo valido per eliminare i VLA; in
180aggiunta sono anche un problema per la sicurezza. La crescita dinamica di un
181vettore nello stack potrebbe eccedere la memoria rimanente in tale segmento.
182Questo può portare a dei malfunzionamenti, potrebbe sovrascrivere
183dati importanti alla fine dello stack (quando il kernel è compilato senza
184`CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente
185allo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`).
186
187Salto implicito nell'istruzione switch-case
188-------------------------------------------
189
190Il linguaggio C permette ai casi di un'istruzione `switch` di saltare al
191prossimo caso quando l'istruzione "break" viene omessa alla fine del caso
192corrente. Tuttavia questo rende il codice ambiguo perché non è sempre ovvio se
193l'istruzione "break" viene omessa intenzionalmente o è un baco. Per esempio,
194osservando il seguente pezzo di codice non è chiaro se lo stato
195`STATE_ONE` è stato progettato apposta per eseguire anche `STATE_TWO`::
196
197  switch (value) {
198  case STATE_ONE:
199          do_something();
200  case STATE_TWO:
201          do_other();
202          break;
203  default:
204          WARN("unknown state");
205  }
206
207Dato che c'è stata una lunga lista di problemi `dovuti alla mancanza dell'istruzione
208"break" <https://cwe.mitre.org/data/definitions/484.html>`_, oggigiorno non
209permettiamo più che vi sia un "salto implicito" (*fall-through*). Per
210identificare un salto implicito intenzionale abbiamo adottato la pseudo
211parola chiave 'fallthrough' che viene espansa nell'estensione di gcc
212`__attribute__((fallthrough))` `Statement Attributes
213<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_.
214(Quando la sintassi C17/C18 `[[fallthrough]]` sarà più comunemente
215supportata dai compilatori C, analizzatori statici, e dagli IDE,
216allora potremo usare quella sintassi per la pseudo parola chiave)
217
218Quando la sintassi [[fallthrough]] sarà più comunemente supportata dai
219compilatori, analizzatori statici, e ambienti di sviluppo IDE,
220allora potremo usarla anche noi.
221
222Ne consegue che tutti i blocchi switch/case devono finire in uno dei seguenti
223modi:
224
225* ``break;``
226* `fallthrough;``
227* ``continue;``
228* ``goto <label>;``
229* ``return [expression];``
230