2015-06-26 10 views
5

CBMC rileva un possibile trabocco senza segno Inoltre nelle seguenti righe:Bypassare un overflow addizione senza segno rilevata dal CBMC

l = (t + *b)&(0xffffffffL); 
c += (l < t); 

Sono d'accordo che c'è la possibilità di un overflow nella prima riga, ma sto prendendo cura del carry nella riga successiva che CBMC non è in grado di guardare. Se nel caso si verifica un overflow, sto impostando il carry 1. Quindi, poiché sono consapevole di questo e questo e questo è il modo in cui voglio che il mio codice funzioni, vorrei procedere con il processo di verifica. Quindi, come faccio a dire al CBMC di ignorare questo bug e andare avanti?

risposta

3

TL; DR Dipende da quali sono i tipi effettivi delle variabili. In tutti i casi, CBMC rileva un bug reale che potrebbe causare un comportamento indefinito. Ciò significa che è necessario correggere il codice anziché disattivare il messaggio in CBMC.

risposta completa:

generale: Al meglio delle mie conoscenze, CBMC non consente l'esclusione di determinate proprietà (d'altra parte, è possibile controllare solo una singola proprietà specifica utilizzando il --property bandiera). Se desideri una risposta/opinione ufficiale o una richiesta di funzionalità, ti consigliamo di postare nello CProver Support group.

(Naturalmente, si potrebbe usare __CPROVER_assume al fine di rendere CBMC escludere le tracce che conducono all'errore, ma questo sarebbe un molto, molto, molto idea male, in quanto ciò potrebbe rendere altri problemi irraggiungibile.)

Variante 1: presumo il codice sia qualcosa di simile (relative a questo: per favore, si prega di inviare indipendenti esempi e spiegare con precisione qual è il problema, è difficile da indovinare queste cose)

long nondet_long(void); 

void main(void) { 
    long l = 0; 
    int c = 0; 
    long t = nondet_long(); 
    long s = nondet_long(); 
    long *b = &s; 

    l = (t + *b) & (0xffffffffL); 
    c += (l < t); 
} 

e si esegue

 
    cbmc --signed-overflow-check test.c 

dando un output simile a quello seguente?

 
    CBMC version 5.1 64-bit x86_64 macos 
    Parsing test.c 
    Converting 
    Type-checking test 
    Generating GOTO Program 
    Adding CPROVER library 
    Function Pointer Removal 
    Partial Inlining 
    Generic Property Instrumentation 
    Starting Bounded Model Checking 
    size of program expression: 41 steps 
    simple slicing removed 3 assignments 
    Generated 2 VCC(s), 2 remaining after simplification 
    Passing problem to propositional reduction 
    converting SSA 
    Running propositional reduction 
    Post-processing 
    Solving with MiniSAT 2.2.0 with simplifier 
    792 variables, 2302 clauses 
    SAT checker: negated claim is SATISFIABLE, i.e., does not hold 
    Runtime decision procedure: 0.006s 
    Building error trace 

    Counterexample: 

    State 17 file test.c line 4 function main thread 0 
    ---------------------------------------------------- 
     l=0 (0000000000000000000000000000000000000000000000000000000000000000) 

    State 18 file test.c line 4 function main thread 0 
    ---------------------------------------------------- 
     l=0 (0000000000000000000000000000000000000000000000000000000000000000) 

    State 19 file test.c line 5 function main thread 0 
    ---------------------------------------------------- 
     c=0 (00000000000000000000000000000000) 

    State 20 file test.c line 5 function main thread 0 
    ---------------------------------------------------- 
     c=0 (00000000000000000000000000000000) 

    State 21 file test.c line 6 function main thread 0 
    ---------------------------------------------------- 
     t=0 (0000000000000000000000000000000000000000000000000000000000000000) 

    State 22 file test.c line 6 function main thread 0 
    ---------------------------------------------------- 
     t=-9223372036854775808 (1000000000000000000000000000000000000000000000000000000000000000) 

    State 23 file test.c line 7 function main thread 0 
    ---------------------------------------------------- 
     s=0 (0000000000000000000000000000000000000000000000000000000000000000) 

    State 24 file test.c line 7 function main thread 0 
    ---------------------------------------------------- 
     s=-9223372036854775807 (1000000000000000000000000000000000000000000000000000000000000001) 

    State 25 file test.c line 8 function main thread 0 
    ---------------------------------------------------- 
     b=((long int *)NULL) (0000000000000000000000000000000000000000000000000000000000000000) 

    State 26 file test.c line 8 function main thread 0 
    ---------------------------------------------------- 
     [email protected] (0000001000000000000000000000000000000000000000000000000000000000) 

    Violated property: 
     file test.c line 10 function main 
     arithmetic overflow on signed + in t + *b 
     !overflow("+", signed long int, t, *b) 

    VERIFICATION FAILED 

Non penso che dovresti disabilitare questo controllo proprietà, anche se tu potessi. La ragione di questo è, come dici tu, che tale aggiunta può traboccare, e, integer overflow è un comportamento indefinito in C, o, come this answer alla domanda How to check integer overflow in C? bene lo mette:

[O] nce hai eseguito x + y, se è stato overflow, sei già in stato di hosed. È troppo tardi il per fare qualche controllo - il tuo programma potrebbe essersi già schiantato. Pensa allo che ti piace controllare la divisione per zero - se aspetti fino a quando la divisione è stata eseguita per controllare, è già troppo tardi.

Vedere anche Integer overflow and undefined behavior e How disastrous is integer overflow in C++?.

Quindi, questo è un bug reale e CBMC ha una buona ragione per dirlo a riguardo. Quello che dovresti fare è adattare il tuo codice in modo che non ci siano potenziali tracimazioni! La risposta di cui sopra suggerisce qualcosa di simile (ricordarsi di includere limits.h):

if ((*b > 0 && t > LONG_MAX - *b) 
    || (*b < 0 && LONG_MIN < *b && t < LONG_MIN - *b) 
    || (*b==LONG_MIN && t < 0)) 
{ 
    /* Overflow will occur, need to do maths in a more elaborate, but safe way! */ 
    /* ... */ 
} 
else 
{ 
    /* No overflow, addition is safe! */ 
    l = (t + *b) & (0xffffffffL); 
    /* ... */ 
} 

Variante 2: Qui, presumo, il codice sia qualcosa di simile:

unsigned int nondet_uint(void); 

void main(void) { 
    unsigned int l = 0; 
    unsigned int c = 0; 
    unsigned int t = nondet_uint(); 
    unsigned int s = nondet_uint(); 
    unsigned int *b = &s; 

    l = (t + *b) & (0xffffffffL); 
    c += (l < t); 
} 

e si esegue

 
    cbmc --unsigned-overflow-check test.c 

dando un'uscita simile alla seguente?

 
CBMC version 5.1 64-bit x86_64 macos 
Parsing test.c 
Converting 
Type-checking test 
Generating GOTO Program 
Adding CPROVER library 
Function Pointer Removal 
Partial Inlining 
Generic Property Instrumentation 
Starting Bounded Model Checking 
size of program expression: 42 steps 
simple slicing removed 3 assignments 
Generated 3 VCC(s), 3 remaining after simplification 
Passing problem to propositional reduction 
converting SSA 
Running propositional reduction 
Post-processing 
Solving with MiniSAT 2.2.0 with simplifier 
519 variables, 1306 clauses 
SAT checker: negated claim is SATISFIABLE, i.e., does not hold 
Runtime decision procedure: 0.01s 
Building error trace 

Counterexample: 

State 17 file test.c line 4 function main thread 0 
---------------------------------------------------- 
    l=0 (00000000000000000000000000000000) 

State 18 file test.c line 4 function main thread 0 
---------------------------------------------------- 
    l=0 (00000000000000000000000000000000) 

State 19 file test.c line 5 function main thread 0 
---------------------------------------------------- 
    c=0 (00000000000000000000000000000000) 

State 20 file test.c line 5 function main thread 0 
---------------------------------------------------- 
    c=0 (00000000000000000000000000000000) 

State 21 file test.c line 6 function main thread 0 
---------------------------------------------------- 
    t=0 (00000000000000000000000000000000) 

State 22 file test.c line 6 function main thread 0 
---------------------------------------------------- 
    t=4187126263 (11111001100100100111100111110111) 

State 23 file test.c line 7 function main thread 0 
---------------------------------------------------- 
    s=0 (00000000000000000000000000000000) 

State 24 file test.c line 7 function main thread 0 
---------------------------------------------------- 
    s=3329066504 (11000110011011011000011000001000) 

State 25 file test.c line 8 function main thread 0 
---------------------------------------------------- 
    b=((unsigned int *)NULL) (0000000000000000000000000000000000000000000000000000000000000000) 

State 26 file test.c line 8 function main thread 0 
---------------------------------------------------- 
    [email protected] (0000001000000000000000000000000000000000000000000000000000000000) 

Violated property: 
    file test.c line 10 function main 
    arithmetic overflow on unsigned + in t + *b 
    !overflow("+", unsigned int, t, *b) 

VERIFICATION FAILED 

Ancora, questo è un bug reale e CBMC ha una buona ragione per dirvi. Questo potrebbe essere fissato da

l = ((unsigned long)t + (unsigned long)*b) & (0xffffffffL); 
c += (l < t); 

che dà

 
CBMC version 5.1 64-bit x86_64 macos 
Parsing test.c 
Converting 
Type-checking test 
Generating GOTO Program 
Adding CPROVER library 
Function Pointer Removal 
Partial Inlining 
Generic Property Instrumentation 
Starting Bounded Model Checking 
size of program expression: 42 steps 
simple slicing removed 3 assignments 
Generated 3 VCC(s), 3 remaining after simplification 
Passing problem to propositional reduction 
converting SSA 
Running propositional reduction 
Post-processing 
Solving with MiniSAT 2.2.0 with simplifier 
542 variables, 1561 clauses 
SAT checker inconsistent: negated claim is UNSATISFIABLE, i.e., holds 
Runtime decision procedure: 0.002s 
VERIFICATION SUCCESSFUL 

Variante 3: Se le cose sono come la precedente, ma avete signed int invece di unsigned int, le cose si fanno un po 'più complicato. Qui, a patto di utilizzare (scritto in modo leggermente più elaborato per vedere meglio cosa sta succedendo)

int nondet_int(void); 

void main(void) { 
    int l = 0; 
    int c = 0; 
    int t = nondet_int(); 
    int s = nondet_int(); 

    long longt = (long)t; 
    long longs = (long)s; 
    long temp1 = longt + longs; 
    long temp2 = temp1 & (0xffffffffL); 

    l = temp2; 
    c += (l < t); 
} 

ed eseguire

 
    cbmc --signed-overflow-check test.c 

otterrete

 
CBMC version 5.1 64-bit x86_64 macos 
Parsing test.c 
Converting 
Type-checking test 
Generating GOTO Program 
Adding CPROVER library 
Function Pointer Removal 
Partial Inlining 
Generic Property Instrumentation 
Starting Bounded Model Checking 
size of program expression: 48 steps 
simple slicing removed 3 assignments 
Generated 3 VCC(s), 3 remaining after simplification 
Passing problem to propositional reduction 
converting SSA 
Running propositional reduction 
Post-processing 
Solving with MiniSAT 2.2.0 with simplifier 
872 variables, 2430 clauses 
SAT checker: negated claim is SATISFIABLE, i.e., does not hold 
Runtime decision procedure: 0.008s 
Building error trace 

Counterexample: 

State 17 file test.c line 4 function main thread 0 
---------------------------------------------------- 
    l=0 (00000000000000000000000000000000) 

State 18 file test.c line 4 function main thread 0 
---------------------------------------------------- 
    l=0 (00000000000000000000000000000000) 

State 19 file test.c line 5 function main thread 0 
---------------------------------------------------- 
    c=0 (00000000000000000000000000000000) 

State 20 file test.c line 5 function main thread 0 
---------------------------------------------------- 
    c=0 (00000000000000000000000000000000) 

State 21 file test.c line 6 function main thread 0 
---------------------------------------------------- 
    t=0 (00000000000000000000000000000000) 

State 22 file test.c line 6 function main thread 0 
---------------------------------------------------- 
    t=-2147483648 (10000000000000000000000000000000) 

State 23 file test.c line 7 function main thread 0 
---------------------------------------------------- 
    s=0 (00000000000000000000000000000000) 

State 24 file test.c line 7 function main thread 0 
---------------------------------------------------- 
    s=1 (00000000000000000000000000000001) 

State 25 file test.c line 9 function main thread 0 
---------------------------------------------------- 
    longt=0 (0000000000000000000000000000000000000000000000000000000000000000) 

State 26 file test.c line 9 function main thread 0 
---------------------------------------------------- 
    longt=-2147483648 (1111111111111111111111111111111110000000000000000000000000000000) 

State 27 file test.c line 10 function main thread 0 
---------------------------------------------------- 
    longs=0 (0000000000000000000000000000000000000000000000000000000000000000) 

State 28 file test.c line 10 function main thread 0 
---------------------------------------------------- 
    longs=1 (0000000000000000000000000000000000000000000000000000000000000001) 

State 29 file test.c line 11 function main thread 0 
---------------------------------------------------- 
    temp1=0 (0000000000000000000000000000000000000000000000000000000000000000) 

State 31 file test.c line 11 function main thread 0 
---------------------------------------------------- 
    temp1=-2147483647 (1111111111111111111111111111111110000000000000000000000000000001) 

State 32 file test.c line 12 function main thread 0 
---------------------------------------------------- 
    temp2=0 (0000000000000000000000000000000000000000000000000000000000000000) 

State 33 file test.c line 12 function main thread 0 
---------------------------------------------------- 
    temp2=2147483649 (0000000000000000000000000000000010000000000000000000000000000001) 

Violated property: 
    file test.c line 14 function main 
    arithmetic overflow on signed type conversion in (signed int)temp2 
    temp2 = -2147483648l 

VERIFICATION FAILED 

Oppure, scritte più concisamente, se si dispone di

t == -2147483648 (0b10000000000000000000000000000000) 
s == 1   (0b00000000000000000000000000000001) 

poi

temp2 == 2147483649 (0b0000000000000000000000000000000010000000000000000000000000000001) 

e un tentativo di convertirlo in un signed int è problemi, perché è fuori intervallo (vedi anche Does cast between signed and unsigned int maintain exact bit pattern of variable in memory?).

Come si può vedere, questo controesempio è anche un bug reale e, di nuovo, CBMC ha ragione nel dirvi di questo. Ciò significa in particolare che il mascheramento/matematica non funziona come previsto (il mascheramento trasforma un numero negativo in un numero positivo che è fuori limite) ed è necessario correggere il codice, in modo che il risultato rientri nell'intervallo necessario. (Probabilmente vale la pena riflettere attentamente su ciò che effettivamente si vuole fare per assicurarsi di ottenere i risultati corretti.)