0001 .. SPDX-License-Identifier: GPL-2.0
0002
0003 .. include:: ../disclaimer-ita.rst
0004
0005 :Original: :ref:`Documentation/process/deprecated.rst <deprecated>`
0006 :Translator: Federico Vaga <federico.vaga@vaga.pv.it>
0007
0008 .. _it_deprecated:
0009
0010 ==============================================================================
0011 Interfacce deprecate, caratteristiche del linguaggio, attributi, e convenzioni
0012 ==============================================================================
0013
0014 In un mondo perfetto, sarebbe possibile prendere tutti gli usi di
0015 un'interfaccia deprecata e convertirli in quella nuova, e così sarebbe
0016 possibile rimuovere la vecchia interfaccia in un singolo ciclo di sviluppo.
0017 Tuttavia, per via delle dimensioni del kernel, la gerarchia dei manutentori e
0018 le tempistiche, non è sempre possibile fare questo tipo di conversione tutta
0019 in una volta. Questo significa che nuove istanze di una vecchia interfaccia
0020 potrebbero aggiungersi al kernel proprio quando si sta cercando di rimuoverle,
0021 aumentando così il carico di lavoro. Al fine di istruire gli sviluppatori su
0022 cosa è considerato deprecato (e perché), è stata create la seguente lista a cui
0023 fare riferimento quando qualcuno propone modifiche che usano cose deprecate.
0024
0025 __deprecated
0026 ------------
0027 Nonostante questo attributo marchi visibilmente un interfaccia come deprecata,
0028 `non produce più alcun avviso durante la compilazione
0029 <https://git.kernel.org/linus/771c035372a036f83353eef46dbb829780330234>`_
0030 perché uno degli obiettivi del kernel è quello di compilare senza avvisi;
0031 inoltre, nessuno stava agendo per rimuovere queste interfacce. Nonostante l'uso
0032 di `__deprecated` in un file d'intestazione sia opportuno per segnare una
0033 interfaccia come 'vecchia', questa non è una soluzione completa. L'interfaccia
0034 deve essere rimossa dal kernel, o aggiunta a questo documento per scoraggiarne
0035 l'uso.
0036
0037 BUG() e BUG_ON()
0038 ----------------
0039 Al loro posto usate WARN() e WARN_ON() per gestire le
0040 condizioni "impossibili" e gestitele come se fosse possibile farlo.
0041 Nonostante le funzioni della famiglia BUG() siano state progettate
0042 per asserire "situazioni impossibili" e interrompere in sicurezza un
0043 thread del kernel, queste si sono rivelate essere troppo rischiose
0044 (per esempio, in quale ordine rilasciare i *lock*? Ci sono stati che
0045 sono stati ripristinati?). Molto spesso l'uso di BUG()
0046 destabilizza il sistema o lo corrompe del tutto, il che rende
0047 impossibile un'attività di debug o anche solo leggere un rapporto
0048 circa l'errore. Linus ha un'opinione molto critica al riguardo:
0049 `email 1
0050 <https://lore.kernel.org/lkml/CA+55aFy6jNLsywVYdGp83AMrXBo_P-pkjkphPGrO=82SPKCpLQ@mail.gmail.com/>`_,
0051 `email 2
0052 <https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_
0053
0054 Tenete presente che la famiglia di funzioni WARN() dovrebbe essere
0055 usato solo per situazioni che si suppone siano "impossibili". Se
0056 volete avvisare gli utenti riguardo a qualcosa di possibile anche se
0057 indesiderato, usare le funzioni della famiglia pr_warn(). Chi
0058 amministra il sistema potrebbe aver attivato l'opzione sysctl
0059 *panic_on_warn* per essere sicuri che il sistema smetta di funzionare
0060 in caso si verifichino delle condizioni "inaspettate". (per esempio,
0061 date un'occhiata al questo `commit
0062 <https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_)
0063
0064 Calcoli codificati negli argomenti di un allocatore
0065 ----------------------------------------------------
0066 Il calcolo dinamico delle dimensioni (specialmente le moltiplicazioni) non
0067 dovrebbero essere fatto negli argomenti di funzioni di allocazione di memoria
0068 (o simili) per via del rischio di overflow. Questo può portare a valori più
0069 piccoli di quelli che il chiamante si aspettava. L'uso di questo modo di
0070 allocare può portare ad un overflow della memoria di heap e altri
0071 malfunzionamenti. (Si fa eccezione per valori numerici per i quali il
0072 compilatore può generare avvisi circa un potenziale overflow. Tuttavia, anche in
0073 questi casi è preferibile riscrivere il codice come suggerito di seguito).
0074
0075 Per esempio, non usate ``count * size`` come argomento::
0076
0077 foo = kmalloc(count * size, GFP_KERNEL);
0078
0079 Al suo posto, si dovrebbe usare l'allocatore a due argomenti::
0080
0081 foo = kmalloc_array(count, size, GFP_KERNEL);
0082
0083 Nello specifico, kmalloc() può essere sostituta da kmalloc_array(), e kzalloc()
0084 da kcalloc().
0085
0086 Se questo tipo di allocatore non è disponibile, allora dovrebbero essere usate
0087 le funzioni del tipo *saturate-on-overflow*::
0088
0089 bar = vmalloc(array_size(count, size));
0090
0091 Un altro tipico caso da evitare è quello di calcolare la dimensione di una
0092 struttura seguita da un vettore di altre strutture, come nel seguente caso::
0093
0094 header = kzalloc(sizeof(*header) + count * sizeof(*header->item),
0095 GFP_KERNEL);
0096
0097 Invece, usate la seguente funzione::
0098
0099 header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
0100
0101 .. note:: Se per caso state usando struct_size() su una struttura dati che
0102 in coda contiene un array di lunghezza zero o uno, allora siete
0103 invitati a riorganizzare il vostro codice usando il
0104 `flexible array member <#zero-length-and-one-element-arrays>`_.
0105
0106 Per altri calcoli, usate le funzioni size_mul(), size_add(), e size_sub(). Per
0107 esempio, al posto di::
0108
0109 foo = krealloc(current_size + chunk_size * (count - 3), GFP_KERNEL);
0110
0111 dovreste scrivere:
0112
0113 foo = krealloc(size_add(current_size,
0114 size_mul(chunk_size,
0115 size_sub(count, 3))), GFP_KERNEL);
0116
0117 Per maggiori dettagli fate riferimento a array3_size() e flex_array_size(), ma
0118 anche le funzioni della famiglia check_mul_overflow(), check_add_overflow(),
0119 check_sub_overflow(), e check_shl_overflow().
0120
0121 simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
0122 ----------------------------------------------------------------------
0123 Le funzioni simple_strtol(), simple_strtoll(),
0124 simple_strtoul(), e simple_strtoull() ignorano volutamente
0125 i possibili overflow, e questo può portare il chiamante a generare risultati
0126 inaspettati. Le rispettive funzioni kstrtol(), kstrtoll(),
0127 kstrtoul(), e kstrtoull() sono da considerarsi le corrette
0128 sostitute; tuttavia va notato che queste richiedono che la stringa sia
0129 terminata con il carattere NUL o quello di nuova riga.
0130
0131 strcpy()
0132 --------
0133 La funzione strcpy() non fa controlli agli estremi del buffer
0134 di destinazione. Questo può portare ad un overflow oltre i limiti del
0135 buffer e generare svariati tipi di malfunzionamenti. Nonostante l'opzione
0136 `CONFIG_FORTIFY_SOURCE=y` e svariate opzioni del compilatore aiutano
0137 a ridurne il rischio, non c'è alcuna buona ragione per continuare ad usare
0138 questa funzione. La versione sicura da usare è strscpy(), tuttavia va
0139 prestata attenzione a tutti quei casi dove viene usato il valore di
0140 ritorno di strcpy(). La funzione strscpy() non ritorna un puntatore
0141 alla destinazione, ma un contatore dei byte non NUL copiati (oppure
0142 un errno negativo se la stringa è stata troncata).
0143
0144 strncpy() su stringe terminate con NUL
0145 --------------------------------------
0146 L'utilizzo di strncpy() non fornisce alcuna garanzia sul fatto che
0147 il buffer di destinazione verrà terminato con il carattere NUL. Questo
0148 potrebbe portare a diversi overflow di lettura o altri malfunzionamenti
0149 causati, appunto, dalla mancanza del terminatore. Questa estende la
0150 terminazione nel buffer di destinazione quando la stringa d'origine è più
0151 corta; questo potrebbe portare ad una penalizzazione delle prestazioni per
0152 chi usa solo stringe terminate. La versione sicura da usare è
0153 strscpy(), tuttavia va prestata attenzione a tutti quei casi dove
0154 viene usato il valore di ritorno di strncpy(). La funzione strscpy()
0155 non ritorna un puntatore alla destinazione, ma un contatore dei byte
0156 non NUL copiati (oppure un errno negativo se la stringa è stata
0157 troncata). Tutti i casi che necessitano di estendere la
0158 terminazione con NUL dovrebbero usare strscpy_pad().
0159
0160 Se il chiamate no usa stringhe terminate con NUL, allore strncpy()
0161 può continuare ad essere usata, ma i buffer di destinazione devono essere
0162 marchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
0163 per evitare avvisi durante la compilazione.
0164
0165 strlcpy()
0166 ---------
0167 La funzione strlcpy(), per prima cosa, legge interamente il buffer di
0168 origine, magari leggendo più di quanto verrà effettivamente copiato. Questo
0169 è inefficiente e può portare a overflow di lettura quando la stringa non è
0170 terminata con NUL. La versione sicura da usare è strscpy(), tuttavia
0171 va prestata attenzione a tutti quei casi dove viene usato il valore di
0172 ritorno di strlcpy(), dato che strscpy() ritorna un valore di errno
0173 negativo quanto la stringa viene troncata.
0174
0175 Segnaposto %p nella stringa di formato
0176 --------------------------------------
0177
0178 Tradizionalmente, l'uso del segnaposto "%p" nella stringa di formato
0179 esponne un indirizzo di memoria in dmesg, proc, sysfs, eccetera. Per
0180 evitare che questi indirizzi vengano sfruttati da malintenzionati,
0181 tutto gli usi di "%p" nel kernel rappresentano l'hash dell'indirizzo,
0182 rendendolo di fatto inutilizzabile. Nuovi usi di "%p" non dovrebbero
0183 essere aggiunti al kernel. Per una rappresentazione testuale di un
0184 indirizzo usate "%pS", l'output è migliore perché mostrerà il nome del
0185 simbolo. Per tutto il resto, semplicemente non usate "%p".
0186
0187 Parafrasando la `guida
0188 <https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_
0189 di Linus:
0190
0191 - Se il valore hash di "%p" è inutile, chiediti se il puntatore stesso
0192 è importante. Forse dovrebbe essere rimosso del tutto?
0193 - Se credi davvero che il vero valore del puntatore sia importante,
0194 perché alcuni stati del sistema o i livelli di privilegi di un
0195 utente sono considerati "special"? Se pensi di poterlo giustificare
0196 (in un commento e nel messaggio del commit) abbastanza bene da
0197 affrontare il giudizio di Linus, allora forse potrai usare "%px",
0198 assicurandosi anche di averne il permesso.
0199
0200 Potete disabilitare temporaneamente l'hashing di "%p" nel caso in cui questa
0201 funzionalità vi sia d'ostacolo durante una sessione di debug. Per farlo
0202 aggiungete l'opzione di debug "`no_hash_pointers
0203 <https://git.kernel.org/linus/5ead723a20e0447bc7db33dc3070b420e5f80aa6>`_" alla
0204 riga di comando del kernel.
0205
0206 Vettori a dimensione variabile (VLA)
0207 ------------------------------------
0208
0209 Usare VLA sullo stack produce codice molto peggiore rispetto a quando si usano
0210 vettori a dimensione fissa. Questi `problemi di prestazioni <https://git.kernel.org/linus/02361bc77888>`_,
0211 tutt'altro che banali, sono già un motivo valido per eliminare i VLA; in
0212 aggiunta sono anche un problema per la sicurezza. La crescita dinamica di un
0213 vettore nello stack potrebbe eccedere la memoria rimanente in tale segmento.
0214 Questo può portare a dei malfunzionamenti, potrebbe sovrascrivere
0215 dati importanti alla fine dello stack (quando il kernel è compilato senza
0216 `CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente
0217 allo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`).
0218
0219 Salto implicito nell'istruzione switch-case
0220 -------------------------------------------
0221
0222 Il linguaggio C permette ai casi di un'istruzione `switch` di saltare al
0223 prossimo caso quando l'istruzione "break" viene omessa alla fine del caso
0224 corrente. Tuttavia questo rende il codice ambiguo perché non è sempre ovvio se
0225 l'istruzione "break" viene omessa intenzionalmente o è un baco. Per esempio,
0226 osservando il seguente pezzo di codice non è chiaro se lo stato
0227 `STATE_ONE` è stato progettato apposta per eseguire anche `STATE_TWO`::
0228
0229 switch (value) {
0230 case STATE_ONE:
0231 do_something();
0232 case STATE_TWO:
0233 do_other();
0234 break;
0235 default:
0236 WARN("unknown state");
0237 }
0238
0239 Dato che c'è stata una lunga lista di problemi `dovuti alla mancanza dell'istruzione
0240 "break" <https://cwe.mitre.org/data/definitions/484.html>`_, oggigiorno non
0241 permettiamo più che vi sia un "salto implicito" (*fall-through*). Per
0242 identificare un salto implicito intenzionale abbiamo adottato la pseudo
0243 parola chiave 'fallthrough' che viene espansa nell'estensione di gcc
0244 `__attribute__((fallthrough))` `Statement Attributes
0245 <https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_.
0246 (Quando la sintassi C17/C18 `[[fallthrough]]` sarà più comunemente
0247 supportata dai compilatori C, analizzatori statici, e dagli IDE,
0248 allora potremo usare quella sintassi per la pseudo parola chiave)
0249
0250 Quando la sintassi [[fallthrough]] sarà più comunemente supportata dai
0251 compilatori, analizzatori statici, e ambienti di sviluppo IDE,
0252 allora potremo usarla anche noi.
0253
0254 Ne consegue che tutti i blocchi switch/case devono finire in uno dei seguenti
0255 modi:
0256
0257 * ``break;``
0258 * `fallthrough;``
0259 * ``continue;``
0260 * ``goto <label>;``
0261 * ``return [expression];``
0262
0263 Array di lunghezza zero o con un solo elemento
0264 ----------------------------------------------
0265 All'interno del kernel ricorre spesso la necessita di avere membri
0266 di dimensione variabile all'interno di una struttura dati. In questi
0267 casi il codice del kernel dovrebbe usare sempre i `"flexible array
0268 member" <https://en.wikipedia.org/wiki/Flexible_array_member>`_. La
0269 tecnica degli array a lunghezza nulla o di un solo elemento non
0270 dovrebbe essere più usata.
0271
0272 Nel codice C più vecchio, la dichiarazione di un membro di dimensione
0273 variabile in coda ad una struttura dati veniva fatto dichiarando un
0274 array di un solo elemento posizionato alla fine della struttura dati::
0275
0276 struct something {
0277 size_t count;
0278 struct foo items[1];
0279 };
0280
0281 Questo ha portato ad un calcolo di sizeof() traballante (dovrebbe
0282 rimuovere la dimensione del singolo elemento in coda per calcolare la
0283 dimensione esatta dell' "intestazione"). Per evitare questi problemi è
0284 stata introdotta un' `estensione a GNU C
0285 <https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_ che
0286 permettesse la dichiarazione di array a lungezza zero::
0287
0288 struct something {
0289 size_t count;
0290 struct foo items[0];
0291 };
0292
0293 Ma questo ha portato nuovi problemi, e non ha risolto alcuni dei
0294 problemi che affliggono entrambe le tecniche: per esempio
0295 l'impossibilità di riconoscere se un array di quel tipo viene usato
0296 nel mezzo di una struttura dati e _non_ alla fine (potrebbe accadere
0297 sia direttamente, sia indirettamente quando si usano le unioni o le
0298 strutture di strutture).
0299
0300 Lo standard C99 introduce i "flexible array members". Questi array non
0301 hanno una dimensione nella loro dichiarazione::
0302
0303 struct something {
0304 size_t count;
0305 struct foo items[];
0306 };
0307
0308 Questo è il modo con cui ci si aspetta che vengano dichiarati gli
0309 elementi di lunghezza variabile in coda alle strutture dati. Permette
0310 al compilatore di produrre errori quando gli array flessibili non si
0311 trovano alla fine della struttura dati, il che permette di prevenire
0312 alcuni tipi di bachi dovuti a `comportamenti inaspettati
0313 <https://git.kernel.org/linus/76497732932f15e7323dc805e8ea8dc11bb587cf>`_.
0314 Inoltre, permette al compilatore di analizzare correttamente le
0315 dimensioni degli array (attraverso sizeof(), `CONFIG_FORTIFY_SOURCE`,
0316 e `CONFIG_UBSAN_BOUNDS`). Per esempio, non esiste alcun meccanismo in
0317 grado di avvisarci che il seguente uso di sizeof() dia sempre come
0318 zero come risultato::
0319
0320 struct something {
0321 size_t count;
0322 struct foo items[0];
0323 };
0324
0325 struct something *instance;
0326
0327 instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
0328 instance->count = count;
0329
0330 size = sizeof(instance->items) * instance->count;
0331 memcpy(instance->items, source, size);
0332
0333 Il valore di ``size`` nell'ultima riga sarà ``zero``, quando uno
0334 invece si aspetterebbe che il suo valore sia la dimensione totale in
0335 byte dell'allocazione dynamica che abbiamo appena fatto per l'array
0336 ``items``. Qui un paio di esempi reali del problema: `collegamento 1
0337 <https://git.kernel.org/linus/f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_,
0338 `collegamento 2
0339 <https://git.kernel.org/linus/ab91c2a89f86be2898cee208d492816ec238b2cf>`_.
0340 Invece, `i flexible array members hanno un tipo incompleto, e quindi
0341 sizeof() non può essere applicato
0342 <https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_; dunque ogni
0343 uso scorretto di questo operatore verrà identificato immediatamente
0344 durante la compilazione.
0345
0346 Per quanto riguarda gli array di un solo elemento, bisogna essere
0347 consapevoli che `questi array occupano almeno quanto lo spazio di un
0348 singolo oggetti dello stesso tipo
0349 <https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, e quindi
0350 contribuiscono al calcolo della dimensione della struttura che li
0351 contiene. In questo caso è facile commettere errori quando si vuole
0352 calcolare la dimensione totale della memoria totale da allocare per
0353 una struttura dati::
0354
0355 struct something {
0356 size_t count;
0357 struct foo items[1];
0358 };
0359
0360 struct something *instance;
0361
0362 instance = kmalloc(struct_size(instance, items, count - 1), GFP_KERNEL);
0363 instance->count = count;
0364
0365 size = sizeof(instance->items) * instance->count;
0366 memcpy(instance->items, source, size);
0367
0368 In questo esempio ci siamo dovuti ricordare di usare ``count - 1`` in
0369 struct_size(), altrimenti avremmo --inavvertitamente-- allocato
0370 memoria per un oggetti ``items`` in più. Il modo più pulito e meno
0371 propenso agli errori è quello di usare i `flexible array member`, in
0372 combinazione con struct_size() e flex_array_size()::
0373
0374 struct something {
0375 size_t count;
0376 struct foo items[];
0377 };
0378
0379 struct something *instance;
0380
0381 instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
0382 instance->count = count;
0383
0384 memcpy(instance->items, source, flex_array_size(instance, items, instance->count));