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 186Potete disabilitare temporaneamente l'hashing di "%p" nel caso in cui questa 187funzionalità vi sia d'ostacolo durante una sessione di debug. Per farlo 188aggiungete l'opzione di debug "`no_hash_pointers 189<https://git.kernel.org/linus/5ead723a20e0447bc7db33dc3070b420e5f80aa6>`_" alla 190riga di comando del kernel. 191 192Vettori a dimensione variabile (VLA) 193------------------------------------ 194 195Usare VLA sullo stack produce codice molto peggiore rispetto a quando si usano 196vettori a dimensione fissa. Questi `problemi di prestazioni <https://git.kernel.org/linus/02361bc77888>`_, 197tutt'altro che banali, sono già un motivo valido per eliminare i VLA; in 198aggiunta sono anche un problema per la sicurezza. La crescita dinamica di un 199vettore nello stack potrebbe eccedere la memoria rimanente in tale segmento. 200Questo può portare a dei malfunzionamenti, potrebbe sovrascrivere 201dati importanti alla fine dello stack (quando il kernel è compilato senza 202`CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente 203allo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`). 204 205Salto implicito nell'istruzione switch-case 206------------------------------------------- 207 208Il linguaggio C permette ai casi di un'istruzione `switch` di saltare al 209prossimo caso quando l'istruzione "break" viene omessa alla fine del caso 210corrente. Tuttavia questo rende il codice ambiguo perché non è sempre ovvio se 211l'istruzione "break" viene omessa intenzionalmente o è un baco. Per esempio, 212osservando il seguente pezzo di codice non è chiaro se lo stato 213`STATE_ONE` è stato progettato apposta per eseguire anche `STATE_TWO`:: 214 215 switch (value) { 216 case STATE_ONE: 217 do_something(); 218 case STATE_TWO: 219 do_other(); 220 break; 221 default: 222 WARN("unknown state"); 223 } 224 225Dato che c'è stata una lunga lista di problemi `dovuti alla mancanza dell'istruzione 226"break" <https://cwe.mitre.org/data/definitions/484.html>`_, oggigiorno non 227permettiamo più che vi sia un "salto implicito" (*fall-through*). Per 228identificare un salto implicito intenzionale abbiamo adottato la pseudo 229parola chiave 'fallthrough' che viene espansa nell'estensione di gcc 230`__attribute__((fallthrough))` `Statement Attributes 231<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_. 232(Quando la sintassi C17/C18 `[[fallthrough]]` sarà più comunemente 233supportata dai compilatori C, analizzatori statici, e dagli IDE, 234allora potremo usare quella sintassi per la pseudo parola chiave) 235 236Quando la sintassi [[fallthrough]] sarà più comunemente supportata dai 237compilatori, analizzatori statici, e ambienti di sviluppo IDE, 238allora potremo usarla anche noi. 239 240Ne consegue che tutti i blocchi switch/case devono finire in uno dei seguenti 241modi: 242 243* ``break;`` 244* `fallthrough;`` 245* ``continue;`` 246* ``goto <label>;`` 247* ``return [expression];`` 248 249Array di lunghezza zero o con un solo elemento 250---------------------------------------------- 251All'interno del kernel ricorre spesso la necessita di avere membri 252di dimensione variabile all'interno di una struttura dati. In questi 253casi il codice del kernel dovrebbe usare sempre i `"flexible array 254member" <https://en.wikipedia.org/wiki/Flexible_array_member>`_. La 255tecnica degli array a lunghezza nulla o di un solo elemento non 256dovrebbe essere più usata. 257 258Nel codice C più vecchio, la dichiarazione di un membro di dimensione 259variabile in coda ad una struttura dati veniva fatto dichiarando un 260array di un solo elemento posizionato alla fine della struttura dati:: 261 262 struct something { 263 size_t count; 264 struct foo items[1]; 265 }; 266 267Questo ha portato ad un calcolo di sizeof() traballante (dovrebbe 268rimuovere la dimensione del singolo elemento in coda per calcolare la 269dimensione esatta dell' "intestazione"). Per evitare questi problemi è 270stata introdotta un' `estensione a GNU C 271<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_ che 272permettesse la dichiarazione di array a lungezza zero:: 273 274 struct something { 275 size_t count; 276 struct foo items[0]; 277 }; 278 279Ma questo ha portato nuovi problemi, e non ha risolto alcuni dei 280problemi che affliggono entrambe le tecniche: per esempio 281l'impossibilità di riconoscere se un array di quel tipo viene usato 282nel mezzo di una struttura dati e _non_ alla fine (potrebbe accadere 283sia direttamente, sia indirettamente quando si usano le unioni o le 284strutture di strutture). 285 286Lo standard C99 introduce i "flexible array members". Questi array non 287hanno una dimensione nella loro dichiarazione:: 288 289 struct something { 290 size_t count; 291 struct foo items[]; 292 }; 293 294Questo è il modo con cui ci si aspetta che vengano dichiarati gli 295elementi di lunghezza variabile in coda alle strutture dati. Permette 296al compilatore di produrre errori quando gli array flessibili non si 297trovano alla fine della struttura dati, il che permette di prevenire 298alcuni tipi di bachi dovuti a `comportamenti inaspettati 299<https://git.kernel.org/linus/76497732932f15e7323dc805e8ea8dc11bb587cf>`_. 300Inoltre, permette al compilatore di analizzare correttamente le 301dimensioni degli array (attraverso sizeof(), `CONFIG_FORTIFY_SOURCE`, 302e `CONFIG_UBSAN_BOUNDS`). Per esempio, non esiste alcun meccanismo in 303grado di avvisarci che il seguente uso di sizeof() dia sempre come 304zero come risultato:: 305 306 struct something { 307 size_t count; 308 struct foo items[0]; 309 }; 310 311 struct something *instance; 312 313 instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL); 314 instance->count = count; 315 316 size = sizeof(instance->items) * instance->count; 317 memcpy(instance->items, source, size); 318 319Il valore di ``size`` nell'ultima riga sarà ``zero``, quando uno 320invece si aspetterebbe che il suo valore sia la dimensione totale in 321byte dell'allocazione dynamica che abbiamo appena fatto per l'array 322``items``. Qui un paio di esempi reali del problema: `collegamento 1 323<https://git.kernel.org/linus/f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_, 324`collegamento 2 325<https://git.kernel.org/linus/ab91c2a89f86be2898cee208d492816ec238b2cf>`_. 326Invece, `i flexible array members hanno un tipo incompleto, e quindi 327sizeof() non può essere applicato 328<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_; dunque ogni 329uso scorretto di questo operatore verrà identificato immediatamente 330durante la compilazione. 331 332Per quanto riguarda gli array di un solo elemento, bisogna essere 333consapevoli che `questi array occupano almeno quanto lo spazio di un 334singolo oggetti dello stesso tipo 335<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, e quindi 336contribuiscono al calcolo della dimensione della struttura che li 337contiene. In questo caso è facile commettere errori quando si vuole 338calcolare la dimensione totale della memoria totale da allocare per 339una struttura dati:: 340 341 struct something { 342 size_t count; 343 struct foo items[1]; 344 }; 345 346 struct something *instance; 347 348 instance = kmalloc(struct_size(instance, items, count - 1), GFP_KERNEL); 349 instance->count = count; 350 351 size = sizeof(instance->items) * instance->count; 352 memcpy(instance->items, source, size); 353 354In questo esempio ci siamo dovuti ricordare di usare ``count - 1`` in 355struct_size(), altrimenti avremmo --inavvertitamente-- allocato 356memoria per un oggetti ``items`` in più. Il modo più pulito e meno 357propenso agli errori è quello di usare i `flexible array member`, in 358combinazione con struct_size() e flex_array_size():: 359 360 struct something { 361 size_t count; 362 struct foo items[]; 363 }; 364 365 struct something *instance; 366 367 instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL); 368 instance->count = count; 369 370 memcpy(instance->items, source, flex_array_size(instance, items, instance->count)); 371