-2
#include <iostream>
#include <vector>

using namespace std;

void test_bad_alloc(unsigned char *start) {
    try {
        vector<int> v = vector<int>(start + 1, start - 13);
    }catch (bad_alloc) {
        std::cout<<"bad alloc"<<std::endl;
    }
}

int main() {
    unsigned char a[20] = {0};
    test_bad_alloc(a);
    return 0;
}

This code is similar to my real project, I found it will result in bad_alloc exception, Why? Is the constructor of this vector ambiguous?

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
Sichen Xu
  • 1
  • 2

3 Answers3

2

Your program has undefined behaviour the moment it tries to evaluate start - 13.

start points to the first element of the a array, so start - 13 creates an invalid pointer, because it's out of the array's bounds. You simply cannot do that, and it doesn't make sense either. What do you expect the pointer to point at, exactly?

Mind that this is undefined behaviour even if you do not dereference the pointer.

In any case, undefined behaviour means your program can do anything, and "anything" includes throwing random exceptions.

And in fact, I cannot reproduce the std::bad_alloc exception. For example, the latest Clang throws std::length_error instead, and the latest Visual C++ just crashes. It also depends on the compiler flags.

What probably happens in your case is that the compiler has produced binary code which simply goes on with the invalid pointer and passes it to the vector constructor, which then tries to create a huge integer range from it, which fails.

Perhaps you intended something like this instead?

void test_bad_alloc(unsigned char *start, unsigned char* end) {
    try {
        vector<int> v = vector<int>(start + 1, end - 13);
    }catch (bad_alloc) {
        std::cout<<"bad alloc"<<std::endl;
    }
}

// ...

test_bad_alloc(a, a + 20);

I also couldn't help but notice a Java-ism in the vector definition line. You can, and should, write it like this instead:

vector<int> v(start + 1, end - 13);
Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
1

Issue is in vector<int> v = vector<int>(start + 1, start - 13);

Range Constructor expects

vector (InputIterator first, InputIterator last,
          const allocator_type& alloc = allocator_type());

i.e. first element to last element. However in place of SecondIterator you are using start - 13 which is outside the memory space of allocated array.

In best case it may be also outside memory space of your process and can cause segmentation fault and in worst case it may get garbage values, overwrite files with bad data or sending wrong messages over sockets.

Dark Sorrow
  • 1,681
  • 14
  • 37
  • 1
    Why is that the worst case? It's the *best* case, because it terminates the program immediately instead of going with garbage values, overwriting files with bad data or sending wrong messages over sockets. It tells you that there's an error you have to fix instead of just being "unstable" and "strange". – Christian Hackl Mar 17 '18 at 09:56
  • 1
    Made necessary changes as per your suggestion. – Dark Sorrow Mar 17 '18 at 10:02
0

The constructor called by vector<int>(ptr1, ptr2) is the range constructor with two iterators. It tries to allocate memory for elements starting at ptr1 and ending before ptr2. But as your ptr2 is smaller than ptr1 you would have a negative number of elements allocated.

As ptr2=start-13 would reference outside of the array allocated, I guess you wanted ptr2=start+13.

milbrandt
  • 1,438
  • 2
  • 15
  • 20