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 ============================================================================== 11 Interfacce deprecate, caratteristiche del linguaggio, attributi, e convenzioni 12 ============================================================================== 13 14 In un mondo perfetto, sarebbe possibile prendere tutti gli usi di 15 un'interfaccia deprecata e convertirli in quella nuova, e così sarebbe 16 possibile rimuovere la vecchia interfaccia in un singolo ciclo di sviluppo. 17 Tuttavia, per via delle dimensioni del kernel, la gerarchia dei manutentori e 18 le tempistiche, non è sempre possibile fare questo tipo di conversione tutta 19 in una volta. Questo significa che nuove istanze di una vecchia interfaccia 20 potrebbero aggiungersi al kernel proprio quando si sta cercando di rimuoverle, 21 aumentando così il carico di lavoro. Al fine di istruire gli sviluppatori su 22 cosa è considerato deprecato (e perché), è stata create la seguente lista a cui 23 fare riferimento quando qualcuno propone modifiche che usano cose deprecate. 24 25 __deprecated 26 ------------ 27 Nonostante questo attributo marchi visibilmente un interfaccia come deprecata, 28 `non produce più alcun avviso durante la compilazione 29 <https://git.kernel.org/linus/771c035372a036f83353eef46dbb829780330234>`_ 30 perché uno degli obiettivi del kernel è quello di compilare senza avvisi; 31 inoltre, nessuno stava agendo per rimuovere queste interfacce. Nonostante l'uso 32 di `__deprecated` in un file d'intestazione sia opportuno per segnare una 33 interfaccia come 'vecchia', questa non è una soluzione completa. L'interfaccia 34 deve essere rimossa dal kernel, o aggiunta a questo documento per scoraggiarne 35 l'uso. 36 37 BUG() e BUG_ON() 38 ---------------- 39 Al loro posto usate WARN() e WARN_ON() per gestire le 40 condizioni "impossibili" e gestitele come se fosse possibile farlo. 41 Nonostante le funzioni della famiglia BUG() siano state progettate 42 per asserire "situazioni impossibili" e interrompere in sicurezza un 43 thread del kernel, queste si sono rivelate essere troppo rischiose 44 (per esempio, in quale ordine rilasciare i *lock*? Ci sono stati che 45 sono stati ripristinati?). Molto spesso l'uso di BUG() 46 destabilizza il sistema o lo corrompe del tutto, il che rende 47 impossibile un'attività di debug o anche solo leggere un rapporto 48 circa 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/">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/">https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_ 53 54 Tenete presente che la famiglia di funzioni WARN() dovrebbe essere 55 usato solo per situazioni che si suppone siano "impossibili". Se 56 volete avvisare gli utenti riguardo a qualcosa di possibile anche se 57 indesiderato, usare le funzioni della famiglia pr_warn(). Chi 58 amministra il sistema potrebbe aver attivato l'opzione sysctl 59 *panic_on_warn* per essere sicuri che il sistema smetta di funzionare 60 in caso si verifichino delle condizioni "inaspettate". (per esempio, 61 date un'occhiata al questo `commit 62 <https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_) 63 64 Calcoli codificati negli argomenti di un allocatore 65 ---------------------------------------------------- 66 Il calcolo dinamico delle dimensioni (specialmente le moltiplicazioni) non 67 dovrebbero 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ù 69 piccoli di quelli che il chiamante si aspettava. L'uso di questo modo di 70 allocare può portare ad un overflow della memoria di heap e altri 71 malfunzionamenti. (Si fa eccezione per valori numerici per i quali il 72 compilatore può generare avvisi circa un potenziale overflow. Tuttavia, anche in 73 questi casi è preferibile riscrivere il codice come suggerito di seguito). 74 75 Per esempio, non usate ``count * size`` come argomento:: 76 77 foo = kmalloc(count * size, GFP_KERNEL); 78 79 Al suo posto, si dovrebbe usare l'allocatore a due argomenti:: 80 81 foo = kmalloc_array(count, size, GFP_KERNEL); 82 83 Nello specifico, kmalloc() può essere sostituta da kmalloc_array(), e kzalloc() 84 da kcalloc(). 85 86 Se questo tipo di allocatore non è disponibile, allora dovrebbero essere usate 87 le funzioni del tipo *saturate-on-overflow*:: 88 89 bar = dma_alloc_coherent(dev, array_size(count, size), &dma, GFP_KERNEL); 90 91 Un altro tipico caso da evitare è quello di calcolare la dimensione di una 92 struttura seguita da un vettore di altre strutture, come nel seguente caso:: 93 94 header = kzalloc(sizeof(*header) + count * sizeof(*header->item), 95 GFP_KERNEL); 96 97 Invece, usate la seguente funzione:: 98 99 header = kzalloc(struct_size(header, item, count), GFP_KERNEL); 100 101 .. note:: Se per caso state usando struct_size() su una struttura dati che 102 in coda contiene un array di lunghezza zero o uno, allora siete 103 invitati a riorganizzare il vostro codice usando il 104 `flexible array member <#zero-length-and-one-element-arrays>`_. 105 106 Per altri calcoli, usate le funzioni size_mul(), size_add(), e size_sub(). Per 107 esempio, al posto di:: 108 109 foo = krealloc(current_size + chunk_size * (count - 3), GFP_KERNEL); 110 111 dovreste scrivere: 112 113 foo = krealloc(size_add(current_size, 114 size_mul(chunk_size, 115 size_sub(count, 3))), GFP_KERNEL); 116 117 Per maggiori dettagli fate riferimento a array3_size() e flex_array_size(), ma 118 anche le funzioni della famiglia check_mul_overflow(), check_add_overflow(), 119 check_sub_overflow(), e check_shl_overflow(). 120 121 simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull() 122 ---------------------------------------------------------------------- 123 Le funzioni simple_strtol(), simple_strtoll(), 124 simple_strtoul(), e simple_strtoull() ignorano volutamente 125 i possibili overflow, e questo può portare il chiamante a generare risultati 126 inaspettati. Le rispettive funzioni kstrtol(), kstrtoll(), 127 kstrtoul(), e kstrtoull() sono da considerarsi le corrette 128 sostitute; tuttavia va notato che queste richiedono che la stringa sia 129 terminata con il carattere NUL o quello di nuova riga. 130 131 strcpy() 132 -------- 133 La funzione strcpy() non fa controlli agli estremi del buffer 134 di destinazione. Questo può portare ad un overflow oltre i limiti del 135 buffer e generare svariati tipi di malfunzionamenti. Nonostante l'opzione 136 `CONFIG_FORTIFY_SOURCE=y` e svariate opzioni del compilatore aiutano 137 a ridurne il rischio, non c'è alcuna buona ragione per continuare ad usare 138 questa funzione. La versione sicura da usare è strscpy(), tuttavia va 139 prestata attenzione a tutti quei casi dove viene usato il valore di 140 ritorno di strcpy(). La funzione strscpy() non ritorna un puntatore 141 alla destinazione, ma un contatore dei byte non NUL copiati (oppure 142 un errno negativo se la stringa è stata troncata). 143 144 strncpy() su stringe terminate con NUL 145 -------------------------------------- 146 L'utilizzo di strncpy() non fornisce alcuna garanzia sul fatto che 147 il buffer di destinazione verrà terminato con il carattere NUL. Questo 148 potrebbe portare a diversi overflow di lettura o altri malfunzionamenti 149 causati, appunto, dalla mancanza del terminatore. Questa estende la 150 terminazione nel buffer di destinazione quando la stringa d'origine è più 151 corta; questo potrebbe portare ad una penalizzazione delle prestazioni per 152 chi usa solo stringe terminate. La versione sicura da usare è 153 strscpy(), tuttavia va prestata attenzione a tutti quei casi dove 154 viene usato il valore di ritorno di strncpy(). La funzione strscpy() 155 non ritorna un puntatore alla destinazione, ma un contatore dei byte 156 non NUL copiati (oppure un errno negativo se la stringa è stata 157 troncata). Tutti i casi che necessitano di estendere la 158 terminazione con NUL dovrebbero usare strscpy_pad(). 159 160 Se il chiamate no usa stringhe terminate con NUL, allore strncpy() 161 può continuare ad essere usata, ma i buffer di destinazione devono essere 162 marchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_ 163 per evitare avvisi durante la compilazione. 164 165 strlcpy() 166 --------- 167 La funzione strlcpy(), per prima cosa, legge interamente il buffer di 168 origine, magari leggendo più di quanto verrà effettivamente copiato. Questo 169 è inefficiente e può portare a overflow di lettura quando la stringa non è 170 terminata con NUL. La versione sicura da usare è strscpy(), tuttavia 171 va prestata attenzione a tutti quei casi dove viene usato il valore di 172 ritorno di strlcpy(), dato che strscpy() ritorna un valore di errno 173 negativo quanto la stringa viene troncata. 174 175 Segnaposto %p nella stringa di formato 176 -------------------------------------- 177 178 Tradizionalmente, l'uso del segnaposto "%p" nella stringa di formato 179 esponne un indirizzo di memoria in dmesg, proc, sysfs, eccetera. Per 180 evitare che questi indirizzi vengano sfruttati da malintenzionati, 181 tutto gli usi di "%p" nel kernel rappresentano l'hash dell'indirizzo, 182 rendendolo di fatto inutilizzabile. Nuovi usi di "%p" non dovrebbero 183 essere aggiunti al kernel. Per una rappresentazione testuale di un 184 indirizzo usate "%pS", l'output è migliore perché mostrerà il nome del 185 simbolo. Per tutto il resto, semplicemente non usate "%p". 186 187 Parafrasando la `guida 188 <https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/">https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_ 189 di Linus: 190 191 - Se il valore hash di "%p" è inutile, chiediti se il puntatore stesso 192 è importante. Forse dovrebbe essere rimosso del tutto? 193 - Se credi davvero che il vero valore del puntatore sia importante, 194 perché alcuni stati del sistema o i livelli di privilegi di un 195 utente sono considerati "special"? Se pensi di poterlo giustificare 196 (in un commento e nel messaggio del commit) abbastanza bene da 197 affrontare il giudizio di Linus, allora forse potrai usare "%px", 198 assicurandosi anche di averne il permesso. 199 200 Potete disabilitare temporaneamente l'hashing di "%p" nel caso in cui questa 201 funzionalità vi sia d'ostacolo durante una sessione di debug. Per farlo 202 aggiungete l'opzione di debug "`no_hash_pointers 203 <https://git.kernel.org/linus/5ead723a20e0447bc7db33dc3070b420e5f80aa6>`_" alla 204 riga di comando del kernel. 205 206 Vettori a dimensione variabile (VLA) 207 ------------------------------------ 208 209 Usare VLA sullo stack produce codice molto peggiore rispetto a quando si usano 210 vettori a dimensione fissa. Questi `problemi di prestazioni <https://git.kernel.org/linus/02361bc77888>`_, 211 tutt'altro che banali, sono già un motivo valido per eliminare i VLA; in 212 aggiunta sono anche un problema per la sicurezza. La crescita dinamica di un 213 vettore nello stack potrebbe eccedere la memoria rimanente in tale segmento. 214 Questo può portare a dei malfunzionamenti, potrebbe sovrascrivere 215 dati importanti alla fine dello stack (quando il kernel è compilato senza 216 `CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente 217 allo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`). 218 219 Salto implicito nell'istruzione switch-case 220 ------------------------------------------- 221 222 Il linguaggio C permette ai casi di un'istruzione `switch` di saltare al 223 prossimo caso quando l'istruzione "break" viene omessa alla fine del caso 224 corrente. Tuttavia questo rende il codice ambiguo perché non è sempre ovvio se 225 l'istruzione "break" viene omessa intenzionalmente o è un baco. Per esempio, 226 osservando il seguente pezzo di codice non è chiaro se lo stato 227 `STATE_ONE` è stato progettato apposta per eseguire anche `STATE_TWO`:: 228 229 switch (value) { 230 case STATE_ONE: 231 do_something(); 232 case STATE_TWO: 233 do_other(); 234 break; 235 default: 236 WARN("unknown state"); 237 } 238 239 Dato che c'è stata una lunga lista di problemi `dovuti alla mancanza dell'istruzione 240 "break" <https://cwe.mitre.org/data/definitions/484.html>`_, oggigiorno non 241 permettiamo più che vi sia un "salto implicito" (*fall-through*). Per 242 identificare un salto implicito intenzionale abbiamo adottato la pseudo 243 parola chiave 'fallthrough' che viene espansa nell'estensione di gcc 244 `__attribute__((fallthrough))` `Statement Attributes 245 <https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_. 246 (Quando la sintassi C17/C18 `[[fallthrough]]` sarà più comunemente 247 supportata dai compilatori C, analizzatori statici, e dagli IDE, 248 allora potremo usare quella sintassi per la pseudo parola chiave) 249 250 Quando la sintassi [[fallthrough]] sarà più comunemente supportata dai 251 compilatori, analizzatori statici, e ambienti di sviluppo IDE, 252 allora potremo usarla anche noi. 253 254 Ne consegue che tutti i blocchi switch/case devono finire in uno dei seguenti 255 modi: 256 257 * ``break;`` 258 * `fallthrough;`` 259 * ``continue;`` 260 * ``goto <label>;`` 261 * ``return [expression];`` 262 263 Array di lunghezza zero o con un solo elemento 264 ---------------------------------------------- 265 All'interno del kernel ricorre spesso la necessita di avere membri 266 di dimensione variabile all'interno di una struttura dati. In questi 267 casi il codice del kernel dovrebbe usare sempre i `"flexible array 268 member" <https://en.wikipedia.org/wiki/Flexible_array_member>`_. La 269 tecnica degli array a lunghezza nulla o di un solo elemento non 270 dovrebbe essere più usata. 271 272 Nel codice C più vecchio, la dichiarazione di un membro di dimensione 273 variabile in coda ad una struttura dati veniva fatto dichiarando un 274 array di un solo elemento posizionato alla fine della struttura dati:: 275 276 struct something { 277 size_t count; 278 struct foo items[1]; 279 }; 280 281 Questo ha portato ad un calcolo di sizeof() traballante (dovrebbe 282 rimuovere la dimensione del singolo elemento in coda per calcolare la 283 dimensione esatta dell' "intestazione"). Per evitare questi problemi è 284 stata introdotta un' `estensione a GNU C 285 <https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_ che 286 permettesse la dichiarazione di array a lungezza zero:: 287 288 struct something { 289 size_t count; 290 struct foo items[0]; 291 }; 292 293 Ma questo ha portato nuovi problemi, e non ha risolto alcuni dei 294 problemi che affliggono entrambe le tecniche: per esempio 295 l'impossibilità di riconoscere se un array di quel tipo viene usato 296 nel mezzo di una struttura dati e _non_ alla fine (potrebbe accadere 297 sia direttamente, sia indirettamente quando si usano le unioni o le 298 strutture di strutture). 299 300 Lo standard C99 introduce i "flexible array members". Questi array non 301 hanno una dimensione nella loro dichiarazione:: 302 303 struct something { 304 size_t count; 305 struct foo items[]; 306 }; 307 308 Questo è il modo con cui ci si aspetta che vengano dichiarati gli 309 elementi di lunghezza variabile in coda alle strutture dati. Permette 310 al compilatore di produrre errori quando gli array flessibili non si 311 trovano alla fine della struttura dati, il che permette di prevenire 312 alcuni tipi di bachi dovuti a `comportamenti inaspettati 313 <https://git.kernel.org/linus/76497732932f15e7323dc805e8ea8dc11bb587cf>`_. 314 Inoltre, permette al compilatore di analizzare correttamente le 315 dimensioni degli array (attraverso sizeof(), `CONFIG_FORTIFY_SOURCE`, 316 e `CONFIG_UBSAN_BOUNDS`). Per esempio, non esiste alcun meccanismo in 317 grado di avvisarci che il seguente uso di sizeof() dia sempre come 318 zero come risultato:: 319 320 struct something { 321 size_t count; 322 struct foo items[0]; 323 }; 324 325 struct something *instance; 326 327 instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL); 328 instance->count = count; 329 330 size = sizeof(instance->items) * instance->count; 331 memcpy(instance->items, source, size); 332 333 Il valore di ``size`` nell'ultima riga sarà ``zero``, quando uno 334 invece si aspetterebbe che il suo valore sia la dimensione totale in 335 byte dell'allocazione dinamica che abbiamo appena fatto per l'array 336 ``items``. Qui un paio di esempi reali del problema: `collegamento 1 337 <https://git.kernel.org/linus/f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_, 338 `collegamento 2 339 <https://git.kernel.org/linus/ab91c2a89f86be2898cee208d492816ec238b2cf>`_. 340 Invece, `i flexible array members hanno un tipo incompleto, e quindi 341 sizeof() non può essere applicato 342 <https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_; dunque ogni 343 uso scorretto di questo operatore verrà identificato immediatamente 344 durante la compilazione. 345 346 Per quanto riguarda gli array di un solo elemento, bisogna essere 347 consapevoli che `questi array occupano almeno quanto lo spazio di un 348 singolo oggetti dello stesso tipo 349 <https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, e quindi 350 contribuiscono al calcolo della dimensione della struttura che li 351 contiene. In questo caso è facile commettere errori quando si vuole 352 calcolare la dimensione totale della memoria totale da allocare per 353 una struttura dati:: 354 355 struct something { 356 size_t count; 357 struct foo items[1]; 358 }; 359 360 struct something *instance; 361 362 instance = kmalloc(struct_size(instance, items, count - 1), GFP_KERNEL); 363 instance->count = count; 364 365 size = sizeof(instance->items) * instance->count; 366 memcpy(instance->items, source, size); 367 368 In questo esempio ci siamo dovuti ricordare di usare ``count - 1`` in 369 struct_size(), altrimenti avremmo --inavvertitamente-- allocato 370 memoria per un oggetti ``items`` in più. Il modo più pulito e meno 371 propenso agli errori è quello di usare i `flexible array member`, in 372 combinazione con struct_size() e flex_array_size():: 373 374 struct something { 375 size_t count; 376 struct foo items[]; 377 }; 378 379 struct something *instance; 380 381 instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL); 382 instance->count = count; 383 384 memcpy(instance->items, source, flex_array_size(instance, items, instance->count)); 385 386 Ci sono due casi speciali dove è necessario usare la macro DECLARE_FLEX_ARRAY() 387 (da notare che la stessa macro è chiamata __DECLARE_FLEX_ARRAY() nei file di 388 intestazione UAPI). Uno è quando l'array flessibile è l'unico elemento di una 389 struttura, e l'altro quando è parte di un unione. Per motivi non tecnici, entrambi 390 i casi d'uso non sono permessi dalla specifica C99. Per esempio, per 391 convertire il seguente codice:: 392 393 struct something { 394 ... 395 union { 396 struct type1 one[0]; 397 struct type2 two[0]; 398 }; 399 }; 400 401 La macro di supporto dev'essere usata:: 402 403 struct something { 404 ... 405 union { 406 DECLARE_FLEX_ARRAY(struct type1, one); 407 DECLARE_FLEX_ARRAY(struct type2, two); 408 }; 409 };
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.