C++ Corrupt stack around Variable

554 Views Asked by At

I'm getting an error around a function that I'm using. The whole program is meant to print either a Roman Numeral or Integer when given a Roman Numeral or Integer by the user.

This function in particular is meant to calculate an Roman Numeral when given an integer. It's now sending me to a _fastfail (still new, I haven't seen this before). Fastfail's "copy details" gets this:

"Unhandled exception at 0x0137CFE9 in HughesProject9.0.exe: Stack cookie instrumentation code detected a stack-based buffer overrun. occurred".

When it was running, the integer at the top of the function threw the correct "integer" back, and same with counter. Here's the function:

string intToRoman(int integer)
{
    char romanArray[10];
    int M = 0;
    int D = 0;
    int C = 0;
    int L = 0;
    int X = 0;
    int V = 0;
    int I = 0;
    int counter = 0;
    int i = 0;

    M = integer / 1000;
    D = ((integer % 1000) / 500);
    C = ((integer % 500) / 100);
    L = ((integer % 100) / 50);
    X = ((integer % 50) / 10);
    V = ((integer % 10) / 5);
    I = (integer % 5);
    counter = M + D + C + L + X + V + I;
    cout << "Integer: " << integer;
    cout << "Counter: " << counter;

    while (counter > 0)
    {
        for (int j = 0; j < 10; j++)
        {
            if (M > 0)
            {
                romanArray[i] = 'M';
                i++;
                counter--;
            }
        }

        for (int j = 0; j < 3; j++)
        {
            if (D > 3)
            {
                romanArray[i] = 'C';
                i++;
                counter--;
            }
            else
            {
                romanArray[i] = 'D';
                i++;
                counter--;
            }
        }
        for (int j = 0; j < 3; j++)
        {
            if (C > 3)
            {
                romanArray[i] = 'L';
                i++;
                counter--;
            }
            else
            {
                romanArray[i] = 'C';
                i++;
                counter--;
            }
        }
        for (int j = 0; j < 3; j++)
        {
            if (L > 3)
            {
                romanArray[i] = 'X';
                i++;
                counter--;
            }
            else
            {
                romanArray[i] = 'L';
                i++;
                counter--;
            }
        }
        for (int j = 0; j < 3; j++)
        {
            if (X > 3)
            {
                romanArray[i] = 'V';
                i++;
                counter--;
            }
            else
            {
                romanArray[i] = 'X';
                i++;
                counter--;
            }
        }
        for (int j = 0; j < 3; j++)
        {
            if (V > 3)
            {
                romanArray[i] = 'I';
                i++;
                counter--;
            }
            else
            {
                romanArray[i] = 'V';
                i++;
                counter--;
            }
        }
        for (int j = 0; j < 3; j++)
        {
            if (I > 0)
            {
                romanArray[i] = 'I';
                i++;
                counter--;
            }
        }

        string calcRoman(romanArray);

        return calcRoman;
    }
}
2

There are 2 best solutions below

0
On BEST ANSWER

I don't think your algorithm for generating the Roman numeral equivalent is correct. I passed in 100, and this is the array it was constructing

i 0    ╠╠╠╠╠╠╠╠╠╠
i 3    DDD╠╠╠╠╠╠╠
i 6    DDDCCC╠╠╠╠
i 9    DDDCCCLLL╠
i 12    DDDCCCLLLX
i 15    DDDCCCLLLX
i 15    DDDCCCLLLX

Which is certainly not the roman numeral for 100. It looks like you need to recheck the else portions of your for loops, they are inserting chars when not needed

    for (int j = 0; j < 3; j++)
    {
        if (D > 3)
        {
            romanArray[i] = 'C';
            i++;
            counter--;
        } else
        {
            romanArray[i] = 'D';
            i++;
            counter--;
        }
    }

D was zero but this code still inserts 3 'DDD'. You likely need something like

} else if (D > 0) {
0
On

Here's how you can debug your code and see exactly what's going wrong. I think you'll find it easier to just think through your code (because it's wrong in more ways than just trashing the stack), but...Literally typing "run" into gdb takes you straight to the problem.

Go here, fix the code you posted so it compiles (add main, with a call to your function with say 50000, and headers, and using namespace std) https://www.onlinegdb.com/# Click debug, then

Reading symbols from /home/a.out...done.                                                                             
(gdb) run                                                                                                            
Starting program: /home/a.out                                                                                        
*** stack smashing detected ***: /home/a.out terminated                                                              
Integer: 50000Counter: 50                                                                                            
Program received signal SIGABRT, Aborted.                                                                            
0x00007ffff7520f79 in __GI_raise (sig=sig@entry=6)                                                                   
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56                                                                    
56      ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.                                          
(gdb) #examine the call stack                                                                                        
(gdb) bt                                                                                                             
#0  0x00007ffff7520f79 in __GI_raise (sig=sig@entry=6)                                                               
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56                                                                    
#1  0x00007ffff7524388 in __GI_abort () at abort.c:89                                                                
#2  0x00007ffff755e1d4 in __libc_message (do_abort=do_abort@entry=1,                                                 
    fmt=fmt@entry=0x7ffff766a415 "*** %s ***: %s terminated\n")                                                      
    at ../sysdeps/posix/libc_fatal.c:175                                                                             
#3  0x00007ffff75f5b2c in __GI___fortify_fail (msg=<optimized out>,                                                  
    msg@entry=0x7ffff766a3fd "stack smashing detected") at fortify_fail.c:37                                         
#4  0x00007ffff75f5ad0 in __stack_chk_fail () at stack_chk_fail.c:28                                                 
#5  0x0000000000400ff3 in intToRoman (integer=50000) at main.cpp:139                                                 
#6  0x0000000000401017 in main () at main.cpp:144                                                                    
(gdb) #go to the code we recognize                                                                                   
(gdb) f 5                                                                                                            
#5  0x0000000000400ff3 in intToRoman (integer=50000) at main.cpp:139                                                 
139     }                                                                                                            
(gdb) #examine our index variable                                                                                    
(gdb) p i                                                                                                            
$1 = 25                                                                                                              
(gdb)    

Now...

(gdb) #restart so we can watch code execute                                                                          
(gdb) b main                                                                                                         
Breakpoint 1 at 0x401006: file main.cpp, line 144.                                                                   
(gdb) run                                                                                                            
The program being debugged has been started already.                                                                 
Start it from the beginning? (y or n) y                                                                              
Starting program: /home/a.out                                                                                        

Breakpoint 1, main () at main.cpp:144                                                                                
144       printf ("%s", intToRoman (50000).c_str ());                                                                
(gdb) #step into function                                                                                            
(gdb) s                                                                                                              
intToRoman (integer=50000) at main.cpp:15                                                                            
15      {                                                                                                            
(gdb) #run next line                                                                                                 
(gdb) n                                                                                                              
17        int M = 0;                                                                                                 
(gdb) #etc...                                                                                                        
(gdb) n                            

The other thing you can do here is once i is in scope (once you've stepped into intToRoman()), you can set a watch on i, like so:

rwatch i if i >=10 Then c (continue). This'll just let the program run until code reads i while i is >= 10.