Home > Software design >  std move bug? heap error with std vector assignment of a vector reference if nesting the assignment
std move bug? heap error with std vector assignment of a vector reference if nesting the assignment

Time:12-05

I got a heap runtime error. I suspect that it is a compiler bug when it use move too excessively. A simplified version of the code is

    vector<vector<int>>result{{1,2,3}};

    int size = result.size();
    for(auto jdx = size-1; jdx >= 0; --jdx){
        vector<int> &row = result[jdx];
        // vector<int> newrow(row);
        for(int idx = 2; idx >=1; --idx) {
            vector<int> newrow(row);
            result.push_back(newrow);
        }
    }

if I swap the newrow(row) line out of the inner most loop, it is then fine like below, vector<vector>result{{1,2,3}};

    int size = result.size();
    for(auto jdx = size-1; jdx >= 0; --jdx){
        vector<int> &row = result[jdx];
        vector<int> newrow(row);
        for(int idx = 2; idx >=1; --idx) {
            //vector<int> newrow(row);
            result.push_back(newrow);
        }
    }

the dump out error is like below

=================================================================
==31==ERROR: AddressSanitizer: heap-use-after-free on address 0x6040000000b0 at pc 0x00000034789d bp 0x7ffd3434d6b0 sp 0x7ffd3434d6a8
READ of size 8 at 0x6040000000b0 thread T0
    #4 0x7f9a26d790b2  (/lib/x86_64-linux-gnu/libc.so.6 0x270b2)
0x6040000000b0 is located 32 bytes inside of 48-byte region [0x604000000090,0x6040000000c0)
freed by thread T0 here:
    #5 0x7f9a26d790b2  (/lib/x86_64-linux-gnu/libc.so.6 0x270b2)
previously allocated by thread T0 here:
    #6 0x7f9a26d790b2  (/lib/x86_64-linux-gnu/libc.so.6 0x270b2)
Shadow bytes around the buggy address:
  0x0c087fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c087fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c087fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c087fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c087fff8000: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 00 06
=>0x0c087fff8010: fa fa fd fd fd fd[fd]fd fa fa fa fa fa fa fa fa
  0x0c087fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==31==ABORTING

CodePudding user response:

Here, the comment I made initially about your code:

you keep a reference on an element of the vector, then you extend this vector, which can lead to reallocation. This reference becomes invalid

Another comment gives the link that explains this behaviour.

Below is a minimal example to illustrate explicitly the same situation.

We can see that after extending the vector, the whole storage is elsewhere on the heap (elements have been moved) but the reference still refers to the previous address of the element at index 2.

/**
  g   -std=c  17 -o prog_cpp prog_cpp.cpp \
      -pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
      -g -O0 -UNDEBUG -fsanitize=address,undefined

  $ ./prog_cpp 
  v from 0x602000000010 to 0x602000000020
  elem at 0x602000000018 is 30
  v from 0x603000000010 to 0x603000000024
  elem at 0x602000000018=================================================================
  ==186890==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000018 at pc 0x55f3af7583e1 bp 0x7ffd22315d80 sp 0x7ffd22315d70
  READ of size 4 at 0x602000000018 thread T0
  ...
**/

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#include <iostream>
#include <vector>

int
main()
{
  auto v=std::vector<int>{10, 20, 30, 40};
  std::cout << "v from " << data(v) << " to " << data(v) size(v) << '\n';
  const auto &elem=v[2];
  std::cout << "elem at " << &elem << std::flush << " is " << elem << '\n';
  v.emplace_back(50);
  std::cout << "v from " << data(v) << " to " << data(v) size(v) << '\n';
  std::cout << "elem at " << &elem << std::flush << " is " << elem << '\n';
  return 0;
}
  • Related