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