0

Something very weird happens when I control my code execution to fish out integer overflows. The control program checks the value of the overflow flag using inline assembly.

Code:

#include <stdio.h> 
#include <stdlib.h> 
#include <stdint.h> 

int add_u32(uint32_t a, uint32_t b, uint32_t* r) {
volatile int no_overflow = 1; 
volatile uint32_t result = a * b;
    __asm__ __volatile__ ( 
    "jno 1f ;"
    "movl $0, %[xo] ;" "1: ;"
    : [xo] "=m" (no_overflow) );
    if (r) 
        *r = result;
     printf("overflow flag:%d\n", no_overflow);
     return no_overflow; 
     }
int main(void) { 
    uint32_t quantity; 
    uint32_t price = 5;
    uint32_t total; 
    printf("Please enter desired quantity\n"); 
    scanf("%d", &quantity);
     if (add_u32(quantity, price, &total) == 0) { 
    printf("Wrong input, program shutting down...");
     return (1); 
    }
     else { 
    printf("Total price:%d\n", total); 
    } 
    return (0); }

This code detects payloads like

  123456789123

but payloads like:

//123456789123222900000 results in 836000
//123456789123222800000 results in 336000
//123456789123222733000 results in 1000
//123456789123222732801 results in 5

Why does this happen and how can I fix this?

Anders
  • 64,406
  • 24
  • 178
  • 215
AXANO
  • 899
  • 7
  • 23

1 Answers1

2

Your program will work only for x86 as uint32_t is the size of x86 registers. In x64 the registers are 8 bytes and do not consider overflow unless the overflow is above 8 bytes.

   0x40066e <add_u32+40>    mov    eax, dword ptr [rbp - 0x14]
   0x400671 <add_u32+43>    imul   eax, dword ptr [rbp - 0x18]
   0x400675 <add_u32+47>    mov    dword ptr [rbp - 0xc], eax
 ► 0x400678 <add_u32+50>  ✔ jno    add_u32+59                    <0x400681>

The overflow flag was not set in x64 even when my number was 0xffffffff(2**32-1). Also technically scanf("%d", &quantity); would not be the bestway to get input here.

sudhackar
  • 248
  • 1
  • 9
  • i have tested this program and it detects overflows that are between bigger than INT_MAX and it also detects overflows that are much greater than the above numbers. So I don't think that your explanation is the cause but +1 for the effort. – AXANO Jan 04 '18 at 01:17
  • INT_MAX is defined in C, however overflow detected by hardware is based on registers. When MSB is flipped on adding two operands then OF is set. Consider looking into the assembly generated and the size of registers of your machine. – sudhackar Jan 04 '18 at 05:34
  • have a look at this https://imgur.com/RO3qIJv. Same program yields different output for same output on different architectures. – sudhackar Jan 04 '18 at 05:39
  • Also consider that whatever arbitrary sized inputs you are giving to scanf are cut down to 32 bits. 123456789123(0x1cbe991a83) from stdin will be 3197704835(0xbe991a83) after scanf. – sudhackar Jan 04 '18 at 05:46
  • i marked your answer as correct but could you please incorporate the comments you made as well as the photo in the actual answer? – AXANO Jan 04 '18 at 06:47