162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci.. include:: ../disclaimer-ita.rst 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci:Original: :ref:`Documentation/process/deprecated.rst <deprecated>` 662306a36Sopenharmony_ci:Translator: Federico Vaga <federico.vaga@vaga.pv.it> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci.. _it_deprecated: 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci============================================================================== 1162306a36Sopenharmony_ciInterfacce deprecate, caratteristiche del linguaggio, attributi, e convenzioni 1262306a36Sopenharmony_ci============================================================================== 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ciIn un mondo perfetto, sarebbe possibile prendere tutti gli usi di 1562306a36Sopenharmony_ciun'interfaccia deprecata e convertirli in quella nuova, e così sarebbe 1662306a36Sopenharmony_cipossibile rimuovere la vecchia interfaccia in un singolo ciclo di sviluppo. 1762306a36Sopenharmony_ciTuttavia, per via delle dimensioni del kernel, la gerarchia dei manutentori e 1862306a36Sopenharmony_cile tempistiche, non è sempre possibile fare questo tipo di conversione tutta 1962306a36Sopenharmony_ciin una volta. Questo significa che nuove istanze di una vecchia interfaccia 2062306a36Sopenharmony_cipotrebbero aggiungersi al kernel proprio quando si sta cercando di rimuoverle, 2162306a36Sopenharmony_ciaumentando così il carico di lavoro. Al fine di istruire gli sviluppatori su 2262306a36Sopenharmony_cicosa è considerato deprecato (e perché), è stata create la seguente lista a cui 2362306a36Sopenharmony_cifare riferimento quando qualcuno propone modifiche che usano cose deprecate. 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci__deprecated 2662306a36Sopenharmony_ci------------ 2762306a36Sopenharmony_ciNonostante questo attributo marchi visibilmente un interfaccia come deprecata, 2862306a36Sopenharmony_ci`non produce più alcun avviso durante la compilazione 2962306a36Sopenharmony_ci<https://git.kernel.org/linus/771c035372a036f83353eef46dbb829780330234>`_ 3062306a36Sopenharmony_ciperché uno degli obiettivi del kernel è quello di compilare senza avvisi; 3162306a36Sopenharmony_ciinoltre, nessuno stava agendo per rimuovere queste interfacce. Nonostante l'uso 3262306a36Sopenharmony_cidi `__deprecated` in un file d'intestazione sia opportuno per segnare una 3362306a36Sopenharmony_ciinterfaccia come 'vecchia', questa non è una soluzione completa. L'interfaccia 3462306a36Sopenharmony_cideve essere rimossa dal kernel, o aggiunta a questo documento per scoraggiarne 3562306a36Sopenharmony_cil'uso. 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ciBUG() e BUG_ON() 3862306a36Sopenharmony_ci---------------- 3962306a36Sopenharmony_ciAl loro posto usate WARN() e WARN_ON() per gestire le 4062306a36Sopenharmony_cicondizioni "impossibili" e gestitele come se fosse possibile farlo. 4162306a36Sopenharmony_ciNonostante le funzioni della famiglia BUG() siano state progettate 4262306a36Sopenharmony_ciper asserire "situazioni impossibili" e interrompere in sicurezza un 4362306a36Sopenharmony_cithread del kernel, queste si sono rivelate essere troppo rischiose 4462306a36Sopenharmony_ci(per esempio, in quale ordine rilasciare i *lock*? Ci sono stati che 4562306a36Sopenharmony_cisono stati ripristinati?). Molto spesso l'uso di BUG() 4662306a36Sopenharmony_cidestabilizza il sistema o lo corrompe del tutto, il che rende 4762306a36Sopenharmony_ciimpossibile un'attività di debug o anche solo leggere un rapporto 4862306a36Sopenharmony_cicirca l'errore. Linus ha un'opinione molto critica al riguardo: 4962306a36Sopenharmony_ci`email 1 5062306a36Sopenharmony_ci<https://lore.kernel.org/lkml/CA+55aFy6jNLsywVYdGp83AMrXBo_P-pkjkphPGrO=82SPKCpLQ@mail.gmail.com/>`_, 5162306a36Sopenharmony_ci`email 2 5262306a36Sopenharmony_ci<https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciTenete presente che la famiglia di funzioni WARN() dovrebbe essere 5562306a36Sopenharmony_ciusato solo per situazioni che si suppone siano "impossibili". Se 5662306a36Sopenharmony_civolete avvisare gli utenti riguardo a qualcosa di possibile anche se 5762306a36Sopenharmony_ciindesiderato, usare le funzioni della famiglia pr_warn(). Chi 5862306a36Sopenharmony_ciamministra il sistema potrebbe aver attivato l'opzione sysctl 5962306a36Sopenharmony_ci*panic_on_warn* per essere sicuri che il sistema smetta di funzionare 6062306a36Sopenharmony_ciin caso si verifichino delle condizioni "inaspettate". (per esempio, 6162306a36Sopenharmony_cidate un'occhiata al questo `commit 6262306a36Sopenharmony_ci<https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ciCalcoli codificati negli argomenti di un allocatore 6562306a36Sopenharmony_ci---------------------------------------------------- 6662306a36Sopenharmony_ciIl calcolo dinamico delle dimensioni (specialmente le moltiplicazioni) non 6762306a36Sopenharmony_cidovrebbero essere fatto negli argomenti di funzioni di allocazione di memoria 6862306a36Sopenharmony_ci(o simili) per via del rischio di overflow. Questo può portare a valori più 6962306a36Sopenharmony_cipiccoli di quelli che il chiamante si aspettava. L'uso di questo modo di 7062306a36Sopenharmony_ciallocare può portare ad un overflow della memoria di heap e altri 7162306a36Sopenharmony_cimalfunzionamenti. (Si fa eccezione per valori numerici per i quali il 7262306a36Sopenharmony_cicompilatore può generare avvisi circa un potenziale overflow. Tuttavia, anche in 7362306a36Sopenharmony_ciquesti casi è preferibile riscrivere il codice come suggerito di seguito). 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciPer esempio, non usate ``count * size`` come argomento:: 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci foo = kmalloc(count * size, GFP_KERNEL); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciAl suo posto, si dovrebbe usare l'allocatore a due argomenti:: 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci foo = kmalloc_array(count, size, GFP_KERNEL); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ciNello specifico, kmalloc() può essere sostituta da kmalloc_array(), e kzalloc() 8462306a36Sopenharmony_cida kcalloc(). 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciSe questo tipo di allocatore non è disponibile, allora dovrebbero essere usate 8762306a36Sopenharmony_cile funzioni del tipo *saturate-on-overflow*:: 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci bar = vmalloc(array_size(count, size)); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciUn altro tipico caso da evitare è quello di calcolare la dimensione di una 9262306a36Sopenharmony_cistruttura seguita da un vettore di altre strutture, come nel seguente caso:: 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci header = kzalloc(sizeof(*header) + count * sizeof(*header->item), 9562306a36Sopenharmony_ci GFP_KERNEL); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciInvece, usate la seguente funzione:: 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci header = kzalloc(struct_size(header, item, count), GFP_KERNEL); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci.. note:: Se per caso state usando struct_size() su una struttura dati che 10262306a36Sopenharmony_ci in coda contiene un array di lunghezza zero o uno, allora siete 10362306a36Sopenharmony_ci invitati a riorganizzare il vostro codice usando il 10462306a36Sopenharmony_ci `flexible array member <#zero-length-and-one-element-arrays>`_. 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ciPer altri calcoli, usate le funzioni size_mul(), size_add(), e size_sub(). Per 10762306a36Sopenharmony_ciesempio, al posto di:: 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci foo = krealloc(current_size + chunk_size * (count - 3), GFP_KERNEL); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cidovreste scrivere: 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci foo = krealloc(size_add(current_size, 11462306a36Sopenharmony_ci size_mul(chunk_size, 11562306a36Sopenharmony_ci size_sub(count, 3))), GFP_KERNEL); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ciPer maggiori dettagli fate riferimento a array3_size() e flex_array_size(), ma 11862306a36Sopenharmony_cianche le funzioni della famiglia check_mul_overflow(), check_add_overflow(), 11962306a36Sopenharmony_cicheck_sub_overflow(), e check_shl_overflow(). 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cisimple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull() 12262306a36Sopenharmony_ci---------------------------------------------------------------------- 12362306a36Sopenharmony_ciLe funzioni simple_strtol(), simple_strtoll(), 12462306a36Sopenharmony_cisimple_strtoul(), e simple_strtoull() ignorano volutamente 12562306a36Sopenharmony_cii possibili overflow, e questo può portare il chiamante a generare risultati 12662306a36Sopenharmony_ciinaspettati. Le rispettive funzioni kstrtol(), kstrtoll(), 12762306a36Sopenharmony_cikstrtoul(), e kstrtoull() sono da considerarsi le corrette 12862306a36Sopenharmony_cisostitute; tuttavia va notato che queste richiedono che la stringa sia 12962306a36Sopenharmony_citerminata con il carattere NUL o quello di nuova riga. 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistrcpy() 13262306a36Sopenharmony_ci-------- 13362306a36Sopenharmony_ciLa funzione strcpy() non fa controlli agli estremi del buffer 13462306a36Sopenharmony_cidi destinazione. Questo può portare ad un overflow oltre i limiti del 13562306a36Sopenharmony_cibuffer e generare svariati tipi di malfunzionamenti. Nonostante l'opzione 13662306a36Sopenharmony_ci`CONFIG_FORTIFY_SOURCE=y` e svariate opzioni del compilatore aiutano 13762306a36Sopenharmony_cia ridurne il rischio, non c'è alcuna buona ragione per continuare ad usare 13862306a36Sopenharmony_ciquesta funzione. La versione sicura da usare è strscpy(), tuttavia va 13962306a36Sopenharmony_ciprestata attenzione a tutti quei casi dove viene usato il valore di 14062306a36Sopenharmony_ciritorno di strcpy(). La funzione strscpy() non ritorna un puntatore 14162306a36Sopenharmony_cialla destinazione, ma un contatore dei byte non NUL copiati (oppure 14262306a36Sopenharmony_ciun errno negativo se la stringa è stata troncata). 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistrncpy() su stringe terminate con NUL 14562306a36Sopenharmony_ci-------------------------------------- 14662306a36Sopenharmony_ciL'utilizzo di strncpy() non fornisce alcuna garanzia sul fatto che 14762306a36Sopenharmony_ciil buffer di destinazione verrà terminato con il carattere NUL. Questo 14862306a36Sopenharmony_cipotrebbe portare a diversi overflow di lettura o altri malfunzionamenti 14962306a36Sopenharmony_cicausati, appunto, dalla mancanza del terminatore. Questa estende la 15062306a36Sopenharmony_citerminazione nel buffer di destinazione quando la stringa d'origine è più 15162306a36Sopenharmony_cicorta; questo potrebbe portare ad una penalizzazione delle prestazioni per 15262306a36Sopenharmony_cichi usa solo stringe terminate. La versione sicura da usare è 15362306a36Sopenharmony_cistrscpy(), tuttavia va prestata attenzione a tutti quei casi dove 15462306a36Sopenharmony_civiene usato il valore di ritorno di strncpy(). La funzione strscpy() 15562306a36Sopenharmony_cinon ritorna un puntatore alla destinazione, ma un contatore dei byte 15662306a36Sopenharmony_cinon NUL copiati (oppure un errno negativo se la stringa è stata 15762306a36Sopenharmony_citroncata). Tutti i casi che necessitano di estendere la 15862306a36Sopenharmony_citerminazione con NUL dovrebbero usare strscpy_pad(). 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ciSe il chiamate no usa stringhe terminate con NUL, allore strncpy() 16162306a36Sopenharmony_cipuò continuare ad essere usata, ma i buffer di destinazione devono essere 16262306a36Sopenharmony_cimarchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_ 16362306a36Sopenharmony_ciper evitare avvisi durante la compilazione. 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistrlcpy() 16662306a36Sopenharmony_ci--------- 16762306a36Sopenharmony_ciLa funzione strlcpy(), per prima cosa, legge interamente il buffer di 16862306a36Sopenharmony_ciorigine, magari leggendo più di quanto verrà effettivamente copiato. Questo 16962306a36Sopenharmony_ciè inefficiente e può portare a overflow di lettura quando la stringa non è 17062306a36Sopenharmony_citerminata con NUL. La versione sicura da usare è strscpy(), tuttavia 17162306a36Sopenharmony_civa prestata attenzione a tutti quei casi dove viene usato il valore di 17262306a36Sopenharmony_ciritorno di strlcpy(), dato che strscpy() ritorna un valore di errno 17362306a36Sopenharmony_cinegativo quanto la stringa viene troncata. 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ciSegnaposto %p nella stringa di formato 17662306a36Sopenharmony_ci-------------------------------------- 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ciTradizionalmente, l'uso del segnaposto "%p" nella stringa di formato 17962306a36Sopenharmony_ciesponne un indirizzo di memoria in dmesg, proc, sysfs, eccetera. Per 18062306a36Sopenharmony_cievitare che questi indirizzi vengano sfruttati da malintenzionati, 18162306a36Sopenharmony_citutto gli usi di "%p" nel kernel rappresentano l'hash dell'indirizzo, 18262306a36Sopenharmony_cirendendolo di fatto inutilizzabile. Nuovi usi di "%p" non dovrebbero 18362306a36Sopenharmony_ciessere aggiunti al kernel. Per una rappresentazione testuale di un 18462306a36Sopenharmony_ciindirizzo usate "%pS", l'output è migliore perché mostrerà il nome del 18562306a36Sopenharmony_cisimbolo. Per tutto il resto, semplicemente non usate "%p". 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ciParafrasando la `guida 18862306a36Sopenharmony_ci<https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_ 18962306a36Sopenharmony_cidi Linus: 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci- Se il valore hash di "%p" è inutile, chiediti se il puntatore stesso 19262306a36Sopenharmony_ci è importante. Forse dovrebbe essere rimosso del tutto? 19362306a36Sopenharmony_ci- Se credi davvero che il vero valore del puntatore sia importante, 19462306a36Sopenharmony_ci perché alcuni stati del sistema o i livelli di privilegi di un 19562306a36Sopenharmony_ci utente sono considerati "special"? Se pensi di poterlo giustificare 19662306a36Sopenharmony_ci (in un commento e nel messaggio del commit) abbastanza bene da 19762306a36Sopenharmony_ci affrontare il giudizio di Linus, allora forse potrai usare "%px", 19862306a36Sopenharmony_ci assicurandosi anche di averne il permesso. 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ciPotete disabilitare temporaneamente l'hashing di "%p" nel caso in cui questa 20162306a36Sopenharmony_cifunzionalità vi sia d'ostacolo durante una sessione di debug. Per farlo 20262306a36Sopenharmony_ciaggiungete l'opzione di debug "`no_hash_pointers 20362306a36Sopenharmony_ci<https://git.kernel.org/linus/5ead723a20e0447bc7db33dc3070b420e5f80aa6>`_" alla 20462306a36Sopenharmony_ciriga di comando del kernel. 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ciVettori a dimensione variabile (VLA) 20762306a36Sopenharmony_ci------------------------------------ 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ciUsare VLA sullo stack produce codice molto peggiore rispetto a quando si usano 21062306a36Sopenharmony_civettori a dimensione fissa. Questi `problemi di prestazioni <https://git.kernel.org/linus/02361bc77888>`_, 21162306a36Sopenharmony_citutt'altro che banali, sono già un motivo valido per eliminare i VLA; in 21262306a36Sopenharmony_ciaggiunta sono anche un problema per la sicurezza. La crescita dinamica di un 21362306a36Sopenharmony_civettore nello stack potrebbe eccedere la memoria rimanente in tale segmento. 21462306a36Sopenharmony_ciQuesto può portare a dei malfunzionamenti, potrebbe sovrascrivere 21562306a36Sopenharmony_cidati importanti alla fine dello stack (quando il kernel è compilato senza 21662306a36Sopenharmony_ci`CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente 21762306a36Sopenharmony_ciallo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`). 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ciSalto implicito nell'istruzione switch-case 22062306a36Sopenharmony_ci------------------------------------------- 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ciIl linguaggio C permette ai casi di un'istruzione `switch` di saltare al 22362306a36Sopenharmony_ciprossimo caso quando l'istruzione "break" viene omessa alla fine del caso 22462306a36Sopenharmony_cicorrente. Tuttavia questo rende il codice ambiguo perché non è sempre ovvio se 22562306a36Sopenharmony_cil'istruzione "break" viene omessa intenzionalmente o è un baco. Per esempio, 22662306a36Sopenharmony_ciosservando il seguente pezzo di codice non è chiaro se lo stato 22762306a36Sopenharmony_ci`STATE_ONE` è stato progettato apposta per eseguire anche `STATE_TWO`:: 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci switch (value) { 23062306a36Sopenharmony_ci case STATE_ONE: 23162306a36Sopenharmony_ci do_something(); 23262306a36Sopenharmony_ci case STATE_TWO: 23362306a36Sopenharmony_ci do_other(); 23462306a36Sopenharmony_ci break; 23562306a36Sopenharmony_ci default: 23662306a36Sopenharmony_ci WARN("unknown state"); 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ciDato che c'è stata una lunga lista di problemi `dovuti alla mancanza dell'istruzione 24062306a36Sopenharmony_ci"break" <https://cwe.mitre.org/data/definitions/484.html>`_, oggigiorno non 24162306a36Sopenharmony_cipermettiamo più che vi sia un "salto implicito" (*fall-through*). Per 24262306a36Sopenharmony_ciidentificare un salto implicito intenzionale abbiamo adottato la pseudo 24362306a36Sopenharmony_ciparola chiave 'fallthrough' che viene espansa nell'estensione di gcc 24462306a36Sopenharmony_ci`__attribute__((fallthrough))` `Statement Attributes 24562306a36Sopenharmony_ci<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_. 24662306a36Sopenharmony_ci(Quando la sintassi C17/C18 `[[fallthrough]]` sarà più comunemente 24762306a36Sopenharmony_cisupportata dai compilatori C, analizzatori statici, e dagli IDE, 24862306a36Sopenharmony_ciallora potremo usare quella sintassi per la pseudo parola chiave) 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ciQuando la sintassi [[fallthrough]] sarà più comunemente supportata dai 25162306a36Sopenharmony_cicompilatori, analizzatori statici, e ambienti di sviluppo IDE, 25262306a36Sopenharmony_ciallora potremo usarla anche noi. 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ciNe consegue che tutti i blocchi switch/case devono finire in uno dei seguenti 25562306a36Sopenharmony_cimodi: 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci* ``break;`` 25862306a36Sopenharmony_ci* `fallthrough;`` 25962306a36Sopenharmony_ci* ``continue;`` 26062306a36Sopenharmony_ci* ``goto <label>;`` 26162306a36Sopenharmony_ci* ``return [expression];`` 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ciArray di lunghezza zero o con un solo elemento 26462306a36Sopenharmony_ci---------------------------------------------- 26562306a36Sopenharmony_ciAll'interno del kernel ricorre spesso la necessita di avere membri 26662306a36Sopenharmony_cidi dimensione variabile all'interno di una struttura dati. In questi 26762306a36Sopenharmony_cicasi il codice del kernel dovrebbe usare sempre i `"flexible array 26862306a36Sopenharmony_cimember" <https://en.wikipedia.org/wiki/Flexible_array_member>`_. La 26962306a36Sopenharmony_citecnica degli array a lunghezza nulla o di un solo elemento non 27062306a36Sopenharmony_cidovrebbe essere più usata. 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ciNel codice C più vecchio, la dichiarazione di un membro di dimensione 27362306a36Sopenharmony_civariabile in coda ad una struttura dati veniva fatto dichiarando un 27462306a36Sopenharmony_ciarray di un solo elemento posizionato alla fine della struttura dati:: 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci struct something { 27762306a36Sopenharmony_ci size_t count; 27862306a36Sopenharmony_ci struct foo items[1]; 27962306a36Sopenharmony_ci }; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ciQuesto ha portato ad un calcolo di sizeof() traballante (dovrebbe 28262306a36Sopenharmony_cirimuovere la dimensione del singolo elemento in coda per calcolare la 28362306a36Sopenharmony_cidimensione esatta dell' "intestazione"). Per evitare questi problemi è 28462306a36Sopenharmony_cistata introdotta un' `estensione a GNU C 28562306a36Sopenharmony_ci<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_ che 28662306a36Sopenharmony_cipermettesse la dichiarazione di array a lungezza zero:: 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci struct something { 28962306a36Sopenharmony_ci size_t count; 29062306a36Sopenharmony_ci struct foo items[0]; 29162306a36Sopenharmony_ci }; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ciMa questo ha portato nuovi problemi, e non ha risolto alcuni dei 29462306a36Sopenharmony_ciproblemi che affliggono entrambe le tecniche: per esempio 29562306a36Sopenharmony_cil'impossibilità di riconoscere se un array di quel tipo viene usato 29662306a36Sopenharmony_cinel mezzo di una struttura dati e _non_ alla fine (potrebbe accadere 29762306a36Sopenharmony_cisia direttamente, sia indirettamente quando si usano le unioni o le 29862306a36Sopenharmony_cistrutture di strutture). 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ciLo standard C99 introduce i "flexible array members". Questi array non 30162306a36Sopenharmony_cihanno una dimensione nella loro dichiarazione:: 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci struct something { 30462306a36Sopenharmony_ci size_t count; 30562306a36Sopenharmony_ci struct foo items[]; 30662306a36Sopenharmony_ci }; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ciQuesto è il modo con cui ci si aspetta che vengano dichiarati gli 30962306a36Sopenharmony_cielementi di lunghezza variabile in coda alle strutture dati. Permette 31062306a36Sopenharmony_cial compilatore di produrre errori quando gli array flessibili non si 31162306a36Sopenharmony_citrovano alla fine della struttura dati, il che permette di prevenire 31262306a36Sopenharmony_cialcuni tipi di bachi dovuti a `comportamenti inaspettati 31362306a36Sopenharmony_ci<https://git.kernel.org/linus/76497732932f15e7323dc805e8ea8dc11bb587cf>`_. 31462306a36Sopenharmony_ciInoltre, permette al compilatore di analizzare correttamente le 31562306a36Sopenharmony_cidimensioni degli array (attraverso sizeof(), `CONFIG_FORTIFY_SOURCE`, 31662306a36Sopenharmony_cie `CONFIG_UBSAN_BOUNDS`). Per esempio, non esiste alcun meccanismo in 31762306a36Sopenharmony_cigrado di avvisarci che il seguente uso di sizeof() dia sempre come 31862306a36Sopenharmony_cizero come risultato:: 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci struct something { 32162306a36Sopenharmony_ci size_t count; 32262306a36Sopenharmony_ci struct foo items[0]; 32362306a36Sopenharmony_ci }; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci struct something *instance; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL); 32862306a36Sopenharmony_ci instance->count = count; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci size = sizeof(instance->items) * instance->count; 33162306a36Sopenharmony_ci memcpy(instance->items, source, size); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ciIl valore di ``size`` nell'ultima riga sarà ``zero``, quando uno 33462306a36Sopenharmony_ciinvece si aspetterebbe che il suo valore sia la dimensione totale in 33562306a36Sopenharmony_cibyte dell'allocazione dinamica che abbiamo appena fatto per l'array 33662306a36Sopenharmony_ci``items``. Qui un paio di esempi reali del problema: `collegamento 1 33762306a36Sopenharmony_ci<https://git.kernel.org/linus/f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_, 33862306a36Sopenharmony_ci`collegamento 2 33962306a36Sopenharmony_ci<https://git.kernel.org/linus/ab91c2a89f86be2898cee208d492816ec238b2cf>`_. 34062306a36Sopenharmony_ciInvece, `i flexible array members hanno un tipo incompleto, e quindi 34162306a36Sopenharmony_cisizeof() non può essere applicato 34262306a36Sopenharmony_ci<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_; dunque ogni 34362306a36Sopenharmony_ciuso scorretto di questo operatore verrà identificato immediatamente 34462306a36Sopenharmony_cidurante la compilazione. 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ciPer quanto riguarda gli array di un solo elemento, bisogna essere 34762306a36Sopenharmony_ciconsapevoli che `questi array occupano almeno quanto lo spazio di un 34862306a36Sopenharmony_cisingolo oggetti dello stesso tipo 34962306a36Sopenharmony_ci<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, e quindi 35062306a36Sopenharmony_cicontribuiscono al calcolo della dimensione della struttura che li 35162306a36Sopenharmony_cicontiene. In questo caso è facile commettere errori quando si vuole 35262306a36Sopenharmony_cicalcolare la dimensione totale della memoria totale da allocare per 35362306a36Sopenharmony_ciuna struttura dati:: 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci struct something { 35662306a36Sopenharmony_ci size_t count; 35762306a36Sopenharmony_ci struct foo items[1]; 35862306a36Sopenharmony_ci }; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci struct something *instance; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci instance = kmalloc(struct_size(instance, items, count - 1), GFP_KERNEL); 36362306a36Sopenharmony_ci instance->count = count; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci size = sizeof(instance->items) * instance->count; 36662306a36Sopenharmony_ci memcpy(instance->items, source, size); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ciIn questo esempio ci siamo dovuti ricordare di usare ``count - 1`` in 36962306a36Sopenharmony_cistruct_size(), altrimenti avremmo --inavvertitamente-- allocato 37062306a36Sopenharmony_cimemoria per un oggetti ``items`` in più. Il modo più pulito e meno 37162306a36Sopenharmony_cipropenso agli errori è quello di usare i `flexible array member`, in 37262306a36Sopenharmony_cicombinazione con struct_size() e flex_array_size():: 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci struct something { 37562306a36Sopenharmony_ci size_t count; 37662306a36Sopenharmony_ci struct foo items[]; 37762306a36Sopenharmony_ci }; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci struct something *instance; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL); 38262306a36Sopenharmony_ci instance->count = count; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci memcpy(instance->items, source, flex_array_size(instance, items, instance->count)); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ciCi sono due casi speciali dove è necessario usare la macro DECLARE_FLEX_ARRAY() 38762306a36Sopenharmony_ci(da notare che la stessa macro è chiamata __DECLARE_FLEX_ARRAY() nei file di 38862306a36Sopenharmony_ciintestazione UAPI). Uno è quando l'array flessibile è l'unico elemento di una 38962306a36Sopenharmony_cistruttura, e l'altro quando è parte di un unione. Per motivi non tecnici, entrambi 39062306a36Sopenharmony_cii casi d'uso non sono permessi dalla specifica C99. Per esempio, per 39162306a36Sopenharmony_ciconvertire il seguente codice:: 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci struct something { 39462306a36Sopenharmony_ci ... 39562306a36Sopenharmony_ci union { 39662306a36Sopenharmony_ci struct type1 one[0]; 39762306a36Sopenharmony_ci struct type2 two[0]; 39862306a36Sopenharmony_ci }; 39962306a36Sopenharmony_ci }; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ciLa macro di supporto dev'essere usata:: 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci struct something { 40462306a36Sopenharmony_ci ... 40562306a36Sopenharmony_ci union { 40662306a36Sopenharmony_ci DECLARE_FLEX_ARRAY(struct type1, one); 40762306a36Sopenharmony_ci DECLARE_FLEX_ARRAY(struct type2, two); 40862306a36Sopenharmony_ci }; 40962306a36Sopenharmony_ci }; 410