Language | Unsigned integer | Signed integer |
---|---|---|
Ada | modulo il modulo del tipo | raise Constraint_Error |
C/C++ | modulo potenza di due | comportamento non definito |
C# | modulo potenza di 2 in contesto non controllato; System.OverflowException viene sollevato nel contesto controllato |
|
Java | N/A | modulo potenza di due |
JavaScript | tutti i numeri sono in doppiaprecisione in virgola mobile eccetto il nuovo BigInt | |
MATLAB | Saturazione dei numeri interi. Fisso -punto fisso configurabile per avvolgere o saturare | |
Python 2 | N/A | convertire in tipo lungo (bigint) |
Seed7 | N/A | raise OVERFLOW_ERROR |
Schema | N/A | convertire in bigNum |
Simulink | configurabile per avvolgere o saturare | |
Smalltalk | N/A | convertire in LargeInteger |
Swift | Cause errore a meno che non si usino operatori speciali di overflow. |
DetectionEdit
L’implementazione del rilevamento di overflow in tempo reale UBSan
è disponibile per i compilatori C.
In Java 8, ci sono metodi sovraccaricati, per esempio come Math.addExact(int, int)
, che lanciano ArithmeticException
in caso di overflow.
Computer emergency response team (CERT) ha sviluppato il modello di interi As-if Infinitely Ranged (AIR), un meccanismo ampiamente automatizzato per eliminare l’overflow di interi e il troncamento in C/C++ utilizzando la gestione degli errori in fase di esecuzione.
AvoidanceEdit
Allocando variabili con tipi di dati abbastanza grandi da contenere tutti i valori che possono essere calcolati e memorizzati in esse, è sempre possibile evitare l’overflow. Anche quando lo spazio disponibile o i tipi di dati fissi forniti da un linguaggio di programmazione o da un ambiente sono troppo limitati per consentire l’allocazione difensiva di variabili con dimensioni generose, ordinando attentamente le operazioni e controllando gli operandi in anticipo, è spesso possibile garantire a priori che il risultato non sarà mai più grande di quanto possa essere memorizzato. Gli strumenti di analisi statica, la verifica formale e le tecniche di progettazione per contratto possono essere utilizzate per garantire in modo più sicuro e robusto che un overflow non possa risultare accidentalmente.
HandlingEdit
Se si prevede che possa verificarsi un overflow, allora si possono inserire dei test nel programma per rilevare quando accade, o sta per accadere, e fare altri trattamenti per mitigarlo. Per esempio, se un risultato importante calcolato dall’input dell’utente trabocca, il programma può fermarsi, rifiutare l’input, e forse chiedere all’utente un input diverso, piuttosto che il programma procedere con l’input non valido traboccato e probabilmente malfunzionare come conseguenza. Questo processo completo può essere automatizzato: è possibile sintetizzare automaticamente un gestore per un overflow intero, dove il gestore è per esempio un’uscita pulita.
Le CPU generalmente hanno un modo di rilevare questo per supportare l’aggiunta di numeri più grandi della loro dimensione di registro, tipicamente usando un bit di stato; la tecnica è chiamata aritmetica a precisione multipla.Così, è possibile aggiungere due numeri di due byte ciascuno usando solo un’addizione a passi: prima aggiungi i byte bassi poi aggiungi i byte alti, ma se è necessario portare fuori i byte bassi questo è un overflow aritmetico dell’addizione a byte e diventa necessario rilevare e incrementare la somma dei byte alti.
Gestire un possibile overflow di un calcolo può a volte presentare una scelta tra l’esecuzione di un controllo prima del calcolo effettivo (per determinare se l’overflow sta per verificarsi o meno), o dopo di esso (per considerare se probabilmente si è verificato in base al valore risultante). La cautela dovrebbe essere mostrata verso quest’ultima scelta. In primo luogo, perché potrebbe non essere un metodo di rilevamento affidabile (per esempio, un’addizione non può necessariamente avvolgere un valore inferiore). In secondo luogo, perché il verificarsi dell’overflow stesso può in alcuni casi essere un comportamento non definito. Nel linguaggio di programmazione C, l’overflow dei tipi interi senza segno risulta in un wrapping, tuttavia l’overflow dei tipi interi firmati è un comportamento non definito; di conseguenza un compilatore C è libero di assumere che il programmatore si sia assicurato che l’overflow firmato non possa verificarsi e quindi può ottimizzare silenziosamente qualsiasi controllo successivo al calcolo che implica la verifica del risultato per rilevarlo senza dare al programmatore alcun avviso che questo sia stato fatto. È quindi consigliabile preferire sempre implementare i controlli prima dei calcoli e non dopo di essi.
Propagazione esplicitaModifica
se un valore è troppo grande per essere memorizzato gli si può assegnare un valore speciale che indica che si è verificato un overflow e quindi far sì che tutte le operazioni successive restituiscano questo valore di flag. Tali valori sono talvolta indicati come NaN, per “non un numero”. Questo è utile in modo che il problema possa essere controllato una volta sola alla fine di un lungo calcolo piuttosto che dopo ogni passo. Questo è spesso supportato nell’hardware in virgola mobile chiamato FPU.
Supporto del linguaggio di programmazioneModifica
I linguaggi di programmazione implementano vari metodi di mitigazione contro un overflow accidentale: Ada, Seed7 (e alcune varianti di linguaggi funzionali), innescano una condizione di eccezione in caso di overflow, mentre Python (dalla 2.4) converte senza soluzione di continuità la rappresentazione interna del numero per adattarlo alla sua crescita, rappresentandolo infine come long
– la cui capacità è limitata solo dalla memoria disponibile.
Nei linguaggi con supporto nativo per l’aritmetica a precisione arbitraria e la sicurezza dei tipi (come Python, Smalltalk o Common Lisp), i numeri vengono promossi ad una dimensione maggiore automaticamente quando si verificano overflow, o vengono lanciate eccezioni (condizioni segnalate) quando esiste un vincolo di range. L’utilizzo di tali linguaggi può quindi essere utile per mitigare questo problema. Tuttavia, in alcuni di questi linguaggi, sono ancora possibili situazioni in cui un overflow di interi può verificarsi. Un esempio è l’ottimizzazione esplicita di un percorso di codice che è considerato un collo di bottiglia dal profiler. Nel caso di Common Lisp, questo è possibile utilizzando una dichiarazione esplicita per annotare il tipo di una variabile ad una parola di dimensione macchina (fixnum) e abbassare il livello di sicurezza del tipo a zero per un particolare blocco di codice.
In netto contrasto con i vecchi linguaggi come C, alcuni linguaggi più recenti, come Rust per esempio, forniscono funzionalità integrate che permettono una facile individuazione e la scelta dell’utente su come l’overflow dovrebbe essere gestito caso per caso. In Rust, mentre l’uso degli operatori matematici di base manca naturalmente di tale flessibilità, gli utenti possono in alternativa eseguire calcoli attraverso un insieme di metodi forniti da ciascuno dei tipi primitivi interi. Questi metodi danno agli utenti diverse scelte tra l’esecuzione di un’operazione “controllata” (o “traboccante”) (che indica se si è verificato o meno un traboccamento tramite il tipo di ritorno); un’operazione “non controllata”; un’operazione che esegue il wrapping, o un’operazione che esegue la saturazione ai limiti numerici.
Aritmetica saturaEdit
Nella grafica computerizzata o nell’elaborazione dei segnali, è tipico lavorare su dati che vanno da 0 a 1 o da -1 a 1. Per esempio, prendiamo un’immagine in scala di grigi dove 0 rappresenta il nero, 1 il bianco e i valori intermedi rappresentano le sfumature di grigio. Un’operazione che si potrebbe voler supportare è schiarire l’immagine moltiplicando ogni pixel per una costante. L’aritmetica saturata permette di moltiplicare alla cieca ogni pixel per quella costante senza preoccuparsi dell’overflow, semplicemente attenendosi ad un risultato ragionevole che tutti questi pixel più grandi di 1 (cioè, “più luminosi del bianco”) diventano bianchi e tutti i valori “più scuri del nero” diventano neri.