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