Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Throwing an array local to a try block

From C++ Primer 18.1.1:

If the [thrown] expression has an array or function type, the expression is converted to its corresponding pointer type.

How is it that this program can produce correct output of 9876543210 (g++ 5.2.0)?

#include <iostream>
using namespace std;

int main(){

    try{
        int a[10] = {9,8,7,6,5,4,3,2,1,0};
        throw a;
    }
    catch(int* b) { for(int i = 0; i < 10; ++i) cout << *(b+i); }

}

From the quote, throw a would create an exception object of type int* which is a pointer to the first element of the array. But surely the array elements of a would be destroyed when we exit the try block and enter the catch clause since we change block scope? Am I getting a false positive or are the array elements "left alone" (not deleted) during the duration of the catch clause?

like image 312
SergeantPenguin Avatar asked Jan 13 '16 13:01

SergeantPenguin


3 Answers

Dereferencing a dangling pointer is Undefined Behaviour.

When a program encounters Undefined Behaviour, it is free to do anything. Which includes crashing and making daemons fly out of your nose, but it also includes doing whatever you expected.

In this case, there are no intervening operations that would overwrite that part of memory and access past the stack pointer (below it, because stack grows down on most platforms) is normally not checked.

So yes, this is a false positive. The memory is not guaranteed to contain the values any more and is not guaranteed to be accessible at all, but it still happens to contain them and be accessible.

Also note, that gcc optimizations are rather infamous for relying on the program not invoking undefined behaviour. Quite often if you have an undefined behaviour, the unoptimized version appears to work, but once you turn on optimizations, it starts doing something completely unexpected.

like image 183
Jan Hudec Avatar answered Nov 17 '22 13:11

Jan Hudec


But surely the array elements of a would be destroyed when we exit the try block and enter the catch clause since we change block scope?

Correct.

Am I getting a false positive or are the array elements "left alone" (not deleted) during the duration of the catch clause?

They're not "left alone". The array is destroyed as you correctly assumed. The program is accessing invalid memory. The behaviour is undefined.

How is it that this program can produce correct output of 9876543210 (g++ 5.2.0)?

There is no correct output when the behaviour is undefined. The program can produce what it did because it can produce any output when the behaviour is undefined.

Reasoning about UB is usually pointless, but in this case, the contents of the invalid memory could be identical if the part of the memory had not yet been overwritten by the program.

like image 39
eerorika Avatar answered Nov 17 '22 14:11

eerorika


You will find later in this chapter a Warning:

Throwing a pointer requires that the object to which the pointer points exist wherever the corresponding handler resides.

so your example would be valid if a array were static or global, otherwise its UB. Or (as Jan Hudec writes in comment) in the enclosing block of the try/catch statement.

like image 5
marcinj Avatar answered Nov 17 '22 15:11

marcinj