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
98.. note:: Se per caso state usando struct_size() su una struttura dati che
99	  in coda contiene un array di lunghezza zero o uno, allora siete
100	  invitati a riorganizzare il vostro codice usando il
101	  `flexible array member <#zero-length-and-one-element-arrays>`_.
102
103Per maggiori dettagli fate riferimento a array_size(),
104array3_size(), e struct_size(), così come la famiglia di
105funzioni check_add_overflow() e check_mul_overflow().
106
107simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
108----------------------------------------------------------------------
109Le funzioni simple_strtol(), simple_strtoll(),
110simple_strtoul(), e simple_strtoull() ignorano volutamente
111i possibili overflow, e questo può portare il chiamante a generare risultati
112inaspettati. Le rispettive funzioni kstrtol(), kstrtoll(),
113kstrtoul(), e kstrtoull() sono da considerarsi le corrette
114sostitute; tuttavia va notato che queste richiedono che la stringa sia
115terminata con il carattere NUL o quello di nuova riga.
116
117strcpy()
118--------
119La funzione strcpy() non fa controlli agli estremi del buffer
120di destinazione. Questo può portare ad un overflow oltre i limiti del
121buffer e generare svariati tipi di malfunzionamenti. Nonostante l'opzione
122`CONFIG_FORTIFY_SOURCE=y` e svariate opzioni del compilatore aiutano
123a ridurne il rischio, non c'è alcuna buona ragione per continuare ad usare
124questa funzione. La versione sicura da usare è strscpy(), tuttavia va
125prestata attenzione a tutti quei casi dove viene usato il valore di
126ritorno di strcpy().  La funzione strscpy() non ritorna un puntatore
127alla destinazione, ma un contatore dei byte non NUL copiati (oppure
128un errno negativo se la stringa è stata troncata).
129
130strncpy() su stringe terminate con NUL
131--------------------------------------
132L'utilizzo di strncpy() non fornisce alcuna garanzia sul fatto che
133il buffer di destinazione verrà terminato con il carattere NUL. Questo
134potrebbe portare a diversi overflow di lettura o altri malfunzionamenti
135causati, appunto, dalla mancanza del terminatore. Questa estende la
136terminazione nel buffer di destinazione quando la stringa d'origine è più
137corta; questo potrebbe portare ad una penalizzazione delle prestazioni per
138chi usa solo stringe terminate. La versione sicura da usare è
139strscpy(), tuttavia va prestata attenzione a tutti quei casi dove
140viene usato il valore di ritorno di strncpy().  La funzione strscpy()
141non ritorna un puntatore alla destinazione, ma un contatore dei byte
142non NUL copiati (oppure un errno negativo se la stringa è stata
143troncata). Tutti i casi che necessitano di estendere la
144terminazione con NUL dovrebbero usare strscpy_pad().
145
146Se il chiamate no usa stringhe terminate con NUL, allore strncpy()
147può continuare ad essere usata, ma i buffer di destinazione devono essere
148marchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
149per evitare avvisi durante la compilazione.
150
151strlcpy()
152---------
153La funzione strlcpy(), per prima cosa, legge interamente il buffer di
154origine, magari leggendo più di quanto verrà effettivamente copiato. Questo
155è inefficiente e può portare a overflow di lettura quando la stringa non è
156terminata con NUL. La versione sicura da usare è strscpy(), tuttavia
157va prestata attenzione a tutti quei casi dove viene usato il valore di
158ritorno di strlcpy(), dato che strscpy() ritorna un valore di errno
159negativo quanto la stringa viene troncata.
160
161Segnaposto %p nella stringa di formato
162--------------------------------------
163
164Tradizionalmente, l'uso del segnaposto "%p" nella stringa di formato
165esponne un indirizzo di memoria in dmesg, proc, sysfs, eccetera.  Per
166evitare che questi indirizzi vengano sfruttati da malintenzionati,
167tutto gli usi di "%p" nel kernel rappresentano l'hash dell'indirizzo,
168rendendolo di fatto inutilizzabile.  Nuovi usi di "%p" non dovrebbero
169essere aggiunti al kernel.  Per una rappresentazione testuale di un
170indirizzo usate "%pS", l'output è migliore perché mostrerà il nome del
171simbolo.  Per tutto il resto, semplicemente non usate "%p".
172
173Parafrasando la `guida
174<https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_
175di Linus:
176
177- Se il valore hash di "%p" è inutile, chiediti se il puntatore stesso
178  è importante. Forse dovrebbe essere rimosso del tutto?
179- Se credi davvero che il vero valore del puntatore sia importante,
180  perché alcuni stati del sistema o i livelli di privilegi di un
181  utente sono considerati "special"? Se pensi di poterlo giustificare
182  (in un commento e nel messaggio del commit) abbastanza bene da
183  affrontare il giudizio di Linus, allora forse potrai usare "%px",
184  assicurandosi anche di averne il permesso.
185
186Infine, sappi che un cambio in favore di "%p" con hash `non verrà
187accettato
188<https://lore.kernel.org/lkml/CA+55aFwieC1-nAs+NFq9RTwaR8ef9hWa4MjNBWL41F-8wM49eA@mail.gmail.com/>`_.
189
190Vettori a dimensione variabile (VLA)
191------------------------------------
192
193Usare VLA sullo stack produce codice molto peggiore rispetto a quando si usano
194vettori a dimensione fissa. Questi `problemi di prestazioni <https://git.kernel.org/linus/02361bc77888>`_,
195tutt'altro che banali, sono già un motivo valido per eliminare i VLA; in
196aggiunta sono anche un problema per la sicurezza. La crescita dinamica di un
197vettore nello stack potrebbe eccedere la memoria rimanente in tale segmento.
198Questo può portare a dei malfunzionamenti, potrebbe sovrascrivere
199dati importanti alla fine dello stack (quando il kernel è compilato senza
200`CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente
201allo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`).
202
203Salto implicito nell'istruzione switch-case
204-------------------------------------------
205
206Il linguaggio C permette ai casi di un'istruzione `switch` di saltare al
207prossimo caso quando l'istruzione "break" viene omessa alla fine del caso
208corrente. Tuttavia questo rende il codice ambiguo perché non è sempre ovvio se
209l'istruzione "break" viene omessa intenzionalmente o è un baco. Per esempio,
210osservando il seguente pezzo di codice non è chiaro se lo stato
211`STATE_ONE` è stato progettato apposta per eseguire anche `STATE_TWO`::
212
213  switch (value) {
214  case STATE_ONE:
215          do_something();
216  case STATE_TWO:
217          do_other();
218          break;
219  default:
220          WARN("unknown state");
221  }
222
223Dato che c'è stata una lunga lista di problemi `dovuti alla mancanza dell'istruzione
224"break" <https://cwe.mitre.org/data/definitions/484.html>`_, oggigiorno non
225permettiamo più che vi sia un "salto implicito" (*fall-through*). Per
226identificare un salto implicito intenzionale abbiamo adottato la pseudo
227parola chiave 'fallthrough' che viene espansa nell'estensione di gcc
228`__attribute__((fallthrough))` `Statement Attributes
229<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_.
230(Quando la sintassi C17/C18 `[[fallthrough]]` sarà più comunemente
231supportata dai compilatori C, analizzatori statici, e dagli IDE,
232allora potremo usare quella sintassi per la pseudo parola chiave)
233
234Quando la sintassi [[fallthrough]] sarà più comunemente supportata dai
235compilatori, analizzatori statici, e ambienti di sviluppo IDE,
236allora potremo usarla anche noi.
237
238Ne consegue che tutti i blocchi switch/case devono finire in uno dei seguenti
239modi:
240
241* ``break;``
242* `fallthrough;``
243* ``continue;``
244* ``goto <label>;``
245* ``return [expression];``
246
247Array di lunghezza zero o con un solo elemento
248----------------------------------------------
249All'interno del kernel ricorre spesso la necessita di avere membri
250di dimensione variabile all'interno di una struttura dati. In questi
251casi il codice del kernel dovrebbe usare sempre i `"flexible array
252member" <https://en.wikipedia.org/wiki/Flexible_array_member>`_. La
253tecnica degli array a lunghezza nulla o di un solo elemento non
254dovrebbe essere più usata.
255
256Nel codice C più vecchio, la dichiarazione di un membro di dimensione
257variabile in coda ad una struttura dati veniva fatto dichiarando un
258array di un solo elemento posizionato alla fine della struttura dati::
259
260        struct something {
261                size_t count;
262                struct foo items[1];
263        };
264
265Questo ha portato ad un calcolo di sizeof() traballante (dovrebbe
266rimuovere la dimensione del singolo elemento in coda per calcolare la
267dimensione esatta dell' "intestazione"). Per evitare questi problemi è
268stata introdotta un' `estensione a GNU C
269<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_ che
270permettesse la dichiarazione di array a lungezza zero::
271
272        struct something {
273                size_t count;
274                struct foo items[0];
275        };
276
277Ma questo ha portato nuovi problemi, e non ha risolto alcuni dei
278problemi che affliggono entrambe le tecniche: per esempio
279l'impossibilità di riconoscere se un array di quel tipo viene usato
280nel mezzo di una struttura dati e _non_ alla fine (potrebbe accadere
281sia direttamente, sia indirettamente quando si usano le unioni o le
282strutture di strutture).
283
284Lo standard C99 introduce i "flexible array members". Questi array non
285hanno una dimensione nella loro dichiarazione::
286
287        struct something {
288                size_t count;
289                struct foo items[];
290        };
291
292Questo è il modo con cui ci si aspetta che vengano dichiarati gli
293elementi di lunghezza variabile in coda alle strutture dati.  Permette
294al compilatore di produrre errori quando gli array flessibili non si
295trovano alla fine della struttura dati, il che permette di prevenire
296alcuni tipi di bachi dovuti a `comportamenti inaspettati
297<https://git.kernel.org/linus/76497732932f15e7323dc805e8ea8dc11bb587cf>`_.
298Inoltre, permette al compilatore di analizzare correttamente le
299dimensioni degli array (attraverso sizeof(), `CONFIG_FORTIFY_SOURCE`,
300e `CONFIG_UBSAN_BOUNDS`). Per esempio, non esiste alcun meccanismo in
301grado di avvisarci che il seguente uso di sizeof() dia sempre come
302zero come risultato::
303
304        struct something {
305                size_t count;
306                struct foo items[0];
307        };
308
309        struct something *instance;
310
311        instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
312        instance->count = count;
313
314        size = sizeof(instance->items) * instance->count;
315        memcpy(instance->items, source, size);
316
317Il valore di ``size`` nell'ultima riga sarà ``zero``, quando uno
318invece si aspetterebbe che il suo valore sia la dimensione totale in
319byte dell'allocazione dynamica che abbiamo appena fatto per l'array
320``items``. Qui un paio di esempi reali del problema: `collegamento 1
321<https://git.kernel.org/linus/f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_,
322`collegamento 2
323<https://git.kernel.org/linus/ab91c2a89f86be2898cee208d492816ec238b2cf>`_.
324Invece, `i flexible array members hanno un tipo incompleto, e quindi
325sizeof() non può essere applicato
326<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_; dunque ogni
327uso scorretto di questo operatore verrà identificato immediatamente
328durante la compilazione.
329
330Per quanto riguarda gli array di un solo elemento, bisogna essere
331consapevoli che `questi array occupano almeno quanto lo spazio di un
332singolo oggetti dello stesso tipo
333<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, e quindi
334contribuiscono al calcolo della dimensione della struttura che li
335contiene. In questo caso è facile commettere errori quando si vuole
336calcolare la dimensione totale della memoria totale da allocare per
337una struttura dati::
338
339        struct something {
340                size_t count;
341                struct foo items[1];
342        };
343
344        struct something *instance;
345
346        instance = kmalloc(struct_size(instance, items, count - 1), GFP_KERNEL);
347        instance->count = count;
348
349        size = sizeof(instance->items) * instance->count;
350        memcpy(instance->items, source, size);
351
352In questo esempio ci siamo dovuti ricordare di usare ``count - 1`` in
353struct_size(), altrimenti avremmo --inavvertitamente-- allocato
354memoria per un oggetti ``items`` in più. Il modo più pulito e meno
355propenso agli errori è quello di usare i `flexible array member`, in
356combinazione con struct_size() e flex_array_size()::
357
358        struct something {
359                size_t count;
360                struct foo items[];
361        };
362
363        struct something *instance;
364
365        instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
366        instance->count = count;
367
368	memcpy(instance->items, source, flex_array_size(instance, items, instance->count));
369