Occasional heap oveflow error while running a program that deals with struct pointers - c++

I've been doing a DSA course online and this is my attempt at a solution for one of the problems. I acknowledge that I know very little about C++ and I shouldn't be messing around with structs and pointers at all, but I've been trying this for a while in order to learn a bit on my own and I can't seem to figure out what is wrong.
Problem Statement: Given a set of n segments {[a 0 , b 0 ], [a 1 , b 1 ], . . . , [a n−1 , b n−1 ]} with integer coordinates on a line, find
the minimum number m of points such that each segment contains at least one point. That is, find a
set of integers X of the minimum size such that for any segment [a i , b i ] there is a point x ∈ X such
that a i ≤ x ≤ b i .
#include <iostream>
#include <algorithm>
#include <vector>
#include <climits>
#include <unistd.h>
std::vector<int> output;
struct linedata
{
int start;
int end;
bool covered = false;
struct linepoint* sloc = (struct linepoint*)malloc(sizeof(struct linepoint*));
struct linepoint* eloc = (struct linepoint*)malloc(sizeof(struct linepoint*));
};
struct linepoint
{
int coord;
bool start;
struct linedata* refer = (struct linedata*)malloc(sizeof(struct linedata*));
struct linepoint* selfrefer = (struct linepoint*)malloc(sizeof(struct linepoint*));
};
bool linesort(struct linepoint a, struct linepoint b)
{
struct linepoint* atemp = (struct linepoint*)malloc(sizeof(struct linepoint*));
atemp = a.selfrefer;
struct linepoint* btemp = (struct linepoint*)malloc(sizeof(struct linepoint*));
btemp = b.selfrefer;
std::cout << a.selfrefer << " " << b.selfrefer << "\n";
if(a.coord < b.coord)
{
if(a.start == true)
{
atemp -> refer -> sloc = btemp;
}
if(a.start == false)
{
atemp -> refer -> eloc = btemp;
}
if(b.start == true)
{
btemp -> refer -> sloc = atemp;
}
if(b.start == true)
{
btemp -> refer -> sloc = atemp;
}
std::swap(b.selfrefer -> coord, a.selfrefer -> coord);
std::swap(b.selfrefer -> start, a.selfrefer -> start);
std::swap(b.selfrefer -> refer, a.selfrefer -> refer);
std::swap(b.selfrefer -> selfrefer, a.selfrefer -> selfrefer);
return false;
}
if((a.coord == b.coord) && (a.start > b.start))
{
if(a.start == true)
{
a.selfrefer -> refer -> sloc = b.selfrefer;
}
if(a.start == false)
{
a.selfrefer -> refer -> eloc = b.selfrefer;
}
if(b.start == true)
{
b.selfrefer -> refer -> sloc = a.selfrefer;
}
if(b.start == true)
{
b.selfrefer -> refer -> sloc = a.selfrefer;
}
std::swap(b.selfrefer -> coord, a.selfrefer -> coord);
std::swap(b.selfrefer -> start, a.selfrefer -> start);
std::swap(b.selfrefer -> refer, a.selfrefer -> refer);
std::swap(b.selfrefer -> selfrefer, a.selfrefer -> selfrefer);
return false;
}
return false;
}
int rescan(int point, struct linedata lines[], struct linepoint points[], int scanlength, bool tosort)
{
output.push_back(point);
int removed = 0;
for(int i = 0; i < scanlength; i++)
{
if((lines[i].covered == false) && (lines[i].start <= point) && (lines[i].end >= point))
{
lines[i].covered = true;
lines[i].sloc -> coord = INT_MAX - lines[i].start;
lines[i].eloc -> coord = INT_MAX - lines[i].end;
removed = removed + 1;
}
}
if(tosort == true)
{
std::sort(points, points+2*scanlength, linesort);
}
return removed;
}
int main(void)
{
int num;
std::cin >> num;
int left = 0;
int track = 0;
struct linedata lines[num];
struct linepoint points[2*num];
struct linepoint* indexor[2*num];
for(int i = 0; i < num; i++)
{
std::cin >> lines[i].start >> lines[i].end;
points[2*i].coord = lines[i].start;
points[2*i].start = true;
points[2*i + 1].coord = lines[i].end;
points[2*i + 1].start = false;
lines[i].sloc = &points[2*i];
lines[i].eloc = &points[2*i + 1];
points[2*i].selfrefer = &points[2*i];
points[2*i + 1].selfrefer = &points[2*i + 1];
left = left + 1;
if(lines[i].start == lines[i].end)
{
left = left - rescan(lines[i].start, lines, points, i + 1, false);
}
}
for(int i = 0; i < 2*num; i++)
{
std::cout << i << " " << points[i].coord << " " << points[i].start << " " << sizeof(&points[i]) << " " << &points[i] << "\n";
}
std::sort(points, points+2*num, linesort);
while(left)
{
for(int i = 0; i < left; i++)
{
if(points[i].start == true)
{
std::cout << "loop part 1: " << left << " " << i << "\n";
for(int i = 0; i < 2*num; i++)
{
std::cout << i << " " << points[i].coord << " " << points[i].start << "\n";
}
sleep(1);
track = track + 1;
continue;
}
if((track != 0) && (points[i].start == false))
{
left = left - rescan(points[i].coord, lines, points, num, true);
std::cout << "loop part 2: " << left << " " << i << "\n";
for(int i = 0; i < 2*num; i++)
{
std::cout << i << " " << points[i].coord << " " << points[i].start << "\n";
}
sleep(1);
track = 0;
continue;
}
}
}
std::cout << output.size() << "\n";
for(int i = 0; i < output.size(); i++)
{
std::cout << output.at(i) << " ";
}
std::cout << "\n";
}
The code behaves unpredictably, to say the least. I'm pretty sure there's some undefined condition in my code and both libasan and valgrind complain about invalid writes in the linesort function. Seeing how the invalid writes are of size 8, I think the writes are pertaining to me exchanging memory addresses to cross-reference linepoint and linedata structs. But seeing how it errors out randomly, I don't know what is causing it to behave like this.
This is from a couple of libasan runs
4
4 7
1 3
2 5
5 6
0 4 1 8 0x7ffe0c863880
1 7 0 8 0x7ffe0c863898
2 1 1 8 0x7ffe0c8638b0
3 3 0 8 0x7ffe0c8638c8
4 2 1 8 0x7ffe0c8638e0
5 5 0 8 0x7ffe0c8638f8
6 5 1 8 0x7ffe0c863910
7 6 0 8 0x7ffe0c863928
0x7ffe0c863898 0x7ffe0c863880
0x7ffe0c863898 0x7ffe0c863880
0x7ffe0c8638b0 0x7ffe0c863880
=================================================================
==188113==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000001a0 at pc 0x562db1500d54 bp 0x7ffe0c8635e0 sp 0x7ffe0c8635d0
WRITE of size 8 at 0x6020000001a0 thread T0
#0 0x562db1500d53 in linesort(linepoint, linepoint) /home/kevin/Downloads/Week3_5.cpp:37
#1 0x562db1502ac0 in bool __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)>::operator()<linepoint*, linepoint*>(linepoint*, linepoint*) /usr/include/c++/10/bits/predefined_ops.h:156
#2 0x562db1502ac0 in void std::__insertion_sort<linepoint*, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)> >(linepoint*, linepoint*, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)>) /usr/include/c++/10/bits/stl_algo.h:1846
#3 0x562db1500341 in void std::__final_insertion_sort<linepoint*, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)> >(linepoint*, linepoint*, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)>) /usr/include/c++/10/bits/stl_algo.h:1891
#4 0x562db1500341 in void std::__sort<linepoint*, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)> >(linepoint*, linepoint*, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)>) /usr/include/c++/10/bits/stl_algo.h:1977
#5 0x562db1500341 in void std::sort<linepoint*, bool (*)(linepoint, linepoint)>(linepoint*, linepoint*, bool (*)(linepoint, linepoint)) /usr/include/c++/10/bits/stl_algo.h:4892
#6 0x562db1500341 in main /home/kevin/Downloads/Week3_5.cpp:137
#7 0x7febd76450b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
#8 0x562db150063d in _start (/home/kevin/Downloads/5+0x363d)
0x6020000001a0 is located 8 bytes to the right of 8-byte region [0x602000000190,0x602000000198)
allocated by thread T0 here:
#0 0x7febd7abc517 in malloc (/lib/x86_64-linux-gnu/libasan.so.6+0xb0517)
#1 0x562db14ff7e9 in linepoint::linepoint() /home/kevin/Downloads/Week3_5.cpp:18
#2 0x562db14ff7e9 in main /home/kevin/Downloads/Week3_5.cpp:112
#3 0x7febd76450b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/kevin/Downloads/Week3_5.cpp:37 in linesort(linepoint, linepoint)
Shadow bytes around the buggy address:
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff8000: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
0x0c047fff8010: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
0x0c047fff8020: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
=>0x0c047fff8030: fa fa 00 fa[fa]fa 00 fa fa fa 00 fa fa fa 00 fa
0x0c047fff8040: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
0x0c047fff8050: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
0x0c047fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8080: 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
==188113==ABORTING
5
2 6
8 19
2 5
1 2
56 981
0 2 1 8 0x7ffdc275be20
1 6 0 8 0x7ffdc275be38
2 8 1 8 0x7ffdc275be50
3 19 0 8 0x7ffdc275be68
4 2 1 8 0x7ffdc275be80
5 5 0 8 0x7ffdc275be98
6 1 1 8 0x7ffdc275beb0
7 2 0 8 0x7ffdc275bec8
8 56 1 8 0x7ffdc275bee0
9 981 0 8 0x7ffdc275bef8
0x7ffdc275be38 0x7ffdc275be20
0x7ffdc275be38 0x7ffdc275be20
0x7ffdc275be50 0x7ffdc275be20
0x7ffdc275be50 0x7ffdc275be38
0x7ffdc275be68 0x7ffdc275be20
0x7ffdc275be68 0x7ffdc275be50
0x7ffdc275be80 0x7ffdc275be20
0x7ffdc275be80 0x7ffdc275be68
=================================================================
==188263==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000260 at pc 0x558343333d54 bp 0x7ffdc275ba80 sp 0x7ffdc275ba70
WRITE of size 8 at 0x602000000260 thread T0
#0 0x558343333d53 in linesort(linepoint, linepoint) /home/kevin/Downloads/Week3_5.cpp:37
#1 0x55834333568d in bool __gnu_cxx::__ops::_Val_comp_iter<bool (*)(linepoint, linepoint)>::operator()<linepoint, linepoint*>(linepoint&, linepoint*) /usr/include/c++/10/bits/predefined_ops.h:238
#2 0x55834333568d in void std::__unguarded_linear_insert<linepoint*, __gnu_cxx::__ops::_Val_comp_iter<bool (*)(linepoint, linepoint)> >(linepoint*, __gnu_cxx::__ops::_Val_comp_iter<bool (*)(linepoint, linepoint)>) /usr/include/c++/10/bits/stl_algo.h:1826
#3 0x558343335af6 in void std::__insertion_sort<linepoint*, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)> >(linepoint*, linepoint*, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)>) /usr/include/c++/10/bits/stl_algo.h:1854
#4 0x558343333341 in void std::__final_insertion_sort<linepoint*, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)> >(linepoint*, linepoint*, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)>) /usr/include/c++/10/bits/stl_algo.h:1891
#5 0x558343333341 in void std::__sort<linepoint*, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)> >(linepoint*, linepoint*, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(linepoint, linepoint)>) /usr/include/c++/10/bits/stl_algo.h:1977
#6 0x558343333341 in void std::sort<linepoint*, bool (*)(linepoint, linepoint)>(linepoint*, linepoint*, bool (*)(linepoint, linepoint)) /usr/include/c++/10/bits/stl_algo.h:4892
#7 0x558343333341 in main /home/kevin/Downloads/Week3_5.cpp:137
#8 0x7f4b800a50b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
#9 0x55834333363d in _start (/home/kevin/Downloads/5+0x363d)
0x602000000260 is located 8 bytes to the right of 8-byte region [0x602000000250,0x602000000258)
allocated by thread T0 here:
#0 0x7f4b8051c517 in malloc (/lib/x86_64-linux-gnu/libasan.so.6+0xb0517)
#1 0x5583433327e9 in linepoint::linepoint() /home/kevin/Downloads/Week3_5.cpp:18
#2 0x5583433327e9 in main /home/kevin/Downloads/Week3_5.cpp:112
#3 0x7f4b800a50b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/kevin/Downloads/Week3_5.cpp:37 in linesort(linepoint, linepoint)
Shadow bytes around the buggy address:
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff8000: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
0x0c047fff8010: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
0x0c047fff8020: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
0x0c047fff8030: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
=>0x0c047fff8040: fa fa 00 fa fa fa 00 fa fa fa 00 fa[fa]fa 00 fa
0x0c047fff8050: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
0x0c047fff8060: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
0x0c047fff8070: fa fa 00 fa fa fa 00 fa fa fa fa fa fa fa fa fa
0x0c047fff8080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8090: 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
==188263==ABORTING
I've used g++ 10 with the -O2 flag turned on. I'm running on Ubuntu 20.04.
I would appreciate any help or guidance regarding this. Once again, I am very inexperienced in C++ and I might be doing things horribly wrong.

struct linepoint* sloc = (struct linepoint*)malloc(sizeof(struct linepoint*));
Your intention is to allocate memory for a linepoint, then assign the address of that allocated memory to sloc.
This is not what is happening, as you try to allocate space for a linepoint*, i.e. enough space for a pointer to such struct. You don't allocate enough memory
Change your code to
struct linepoint* sloc = (struct linepoint*)malloc(sizeof(struct linepoint)); so that malloc can allocate enough space.
Aside from that, you should rethink your use of malloc(). malloc does nothing more than allocate a chunk of memory for you. In C++ however, you should work with the laguage provided keyword new. new also allocates memory and returns a pointer to it, but it also makes sure that operations such as calling the constructors of your objects are performed.

Related

Why does my function work in g++, but not in LeetCode?

I'm trying to submit code for this question, https://leetcode.com/problems/zigzag-conversion/
I'm using g++ to compile on my system. It works and outputs all the example solutions correctly on my end. However, it keeps giving me an error when I put the code into the submission area.
Here's a look at my code...
#include <string>
#include <iostream>
using namespace std;
class Solution {
public:
string convert(string s, int numRows)
{
int size = s.size();
int i, j;
string *zigZag = new string[numRows];
char* retStr = new char[size];
int count = 0;
bool moreString = true;
int col = 0;
while(moreString)
{
for(i = 0; i< numRows && count < size; i++)
{
zigZag[i][col] = s[count];
count++;
}
col++;
for(i = numRows - 2; i > 0 && count < size; i--)
{
zigZag[i][col] = s[count];
count++;
col++;
}
if(count >= size)
moreString = false;
}
count = 0;
for(i = 0; i < numRows; i++)
{
for(j = 0; j < col; j++)
{
if(zigZag[i][j] != '\0')
{
retStr[count] = zigZag[i][j];
count++;
}
}
}
return retStr;
}
};
This is the error it keeps spitting out at me...
=================================================================
==31==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000001e at pc 0x0000003441f4 bp 0x7ffdf5b48350 sp 0x7ffdf5b48348
WRITE of size 1 at 0x60200000001e thread T0
#3 0x7f93f12dd0b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
0x60200000001e is located 0 bytes to the right of 14-byte region [0x602000000010,0x60200000001e)
allocated by thread T0 here:
#4 0x7f93f12dd0b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
Shadow bytes around the buggy address:
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa 00[06]fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: 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
Any advice would be appreciated.
The difference is that Leetcode seems to run your code with the address sanitizer. Gcc has some facilities to spot bugs in code that is syntactically correct and does not trigger compiler errors. The output you see can be generated with gcc and the flag -fsanitize=address: https://godbolt.org/z/1jse1snW7
As mentioned in comments the reason is that
string *zigZag = new string[numRows];
Allocates an array of pointers to string and then here:
zigZag[i][col] = s[count];
you assume that zigZag[i] points to an array, but you never allocated that array. As a result zigZag[i][col] dereferences an invalid pointer and is undefined behavior.

std move bug? heap error with std vector assignment of a vector reference if nesting the assignment copy within a loop that iterates more than once

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
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;
}

Trying to rotate an array by k places using modulo [duplicate]

The question is as follows:
Given an array, rotate the array to the right by k steps, where k is non-negative.
Here is my code:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int r =nums.size()-k;
vector<int>::iterator it;
it = nums.begin();
for(int i=0;i<r;i++){
nums.push_back(nums[0]);
nums.erase(it);
}
}
};
Test Case 1 :
Input: nums = [1,2,3,4,5,6,7], k = 3
Output: [5,6,7,1,2,3,4]
Here, My code compiled successfully and is giving the right solution.
Test Case 2:
Input: nums = [-1,-100,3,99], k = 2
Output: [3,99,-1,-100]
Here, all the problem starts, my code giving the following error :
=================================================================
==32==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000094 at pc 0x0000003189cf bp 0x7ffe0e44adf0 sp 0x7ffe0e44a5b8
READ of size 68719476672 at 0x602000000094 thread T0
#5 0x7f15fa2470b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
0x6020000000a0 is located 0 bytes to the right of 16-byte region [0x602000000090,0x6020000000a0)
freed by thread T0 here:
#4 0x7f15fa2470b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
previously allocated by thread T0 here:
#6 0x7f15fa2470b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
Shadow bytes around the buggy address:
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff8000: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
=>0x0c047fff8010: fa fa[fd]fd fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8060: 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
==32==ABORTING
I am what this error is, Please help.
Iterators of std::vector may be invalidated by push_back().
You should use nums.begin() directly without saving the iterator for erasing.
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int r =nums.size()-k;
// this iterator may be invalidated
//vector<int>::iterator it;
//it = nums.begin();
for(int i=0;i<r;i++){
nums.push_back(nums[0]);
// use begin() directly
//nums.erase(it);
nums.erase(nums.begin());
}
}
};
The code crashed because that the it would be invalidated after calling push_back, to fix it we may directly call begin.
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int r =nums.size()- (k % nums.size());
for(int i=0;i<r;i++){
nums.push_back(nums[0]);
nums.erase(nums.begin());
}
}
};
The algorithm in your code is not idental to right rotate, you are using left rotate. For right rotate, need to insert the last element into font, and then erase the last element, and we also need to modolus the vector's length to avoid uncessaray rotate, or there would be a waste, an accepted code might like:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int r = k % nums.size();
for (int i = 0; i < r; i++) {
nums.insert(nums.begin(), nums.back());
nums.erase(std::prev(nums.end()));
}
}
};
And we can also call the STL algorithm: rotate, to rotate towards the right, we need to use the reverse iterator here:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int r = k % nums.size();
std::rotate(nums.rbegin(), nums.rbegin() + r, nums.rend());
}
};
Your algorithm will cause the vector elements to be shifted at every insertion into the front, it is not efficient, think about we have a large vector, shift all the elements would be a bottle-neck.
The STL version might have some other performance enhancement since it may move the element range in batch rather than swap the elements one by one.
And we can also call std::reverse three times to implenment our own rotate:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int r = k % nums.size();
std::reverse(nums.begin(), nums.end());
std::reverse(nums.begin(), nums.begin() + r);
std::reverse(nums.begin() + r, nums.end());
}
};
The last two versions are much faster than the previous ones, it's recommended to use them.

Rotate Array LeetCode (189)

The question is as follows:
Given an array, rotate the array to the right by k steps, where k is non-negative.
Here is my code:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int r =nums.size()-k;
vector<int>::iterator it;
it = nums.begin();
for(int i=0;i<r;i++){
nums.push_back(nums[0]);
nums.erase(it);
}
}
};
Test Case 1 :
Input: nums = [1,2,3,4,5,6,7], k = 3
Output: [5,6,7,1,2,3,4]
Here, My code compiled successfully and is giving the right solution.
Test Case 2:
Input: nums = [-1,-100,3,99], k = 2
Output: [3,99,-1,-100]
Here, all the problem starts, my code giving the following error :
=================================================================
==32==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000094 at pc 0x0000003189cf bp 0x7ffe0e44adf0 sp 0x7ffe0e44a5b8
READ of size 68719476672 at 0x602000000094 thread T0
#5 0x7f15fa2470b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
0x6020000000a0 is located 0 bytes to the right of 16-byte region [0x602000000090,0x6020000000a0)
freed by thread T0 here:
#4 0x7f15fa2470b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
previously allocated by thread T0 here:
#6 0x7f15fa2470b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
Shadow bytes around the buggy address:
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff8000: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
=>0x0c047fff8010: fa fa[fd]fd fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8060: 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
==32==ABORTING
I am what this error is, Please help.
Iterators of std::vector may be invalidated by push_back().
You should use nums.begin() directly without saving the iterator for erasing.
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int r =nums.size()-k;
// this iterator may be invalidated
//vector<int>::iterator it;
//it = nums.begin();
for(int i=0;i<r;i++){
nums.push_back(nums[0]);
// use begin() directly
//nums.erase(it);
nums.erase(nums.begin());
}
}
};
The code crashed because that the it would be invalidated after calling push_back, to fix it we may directly call begin.
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int r =nums.size()- (k % nums.size());
for(int i=0;i<r;i++){
nums.push_back(nums[0]);
nums.erase(nums.begin());
}
}
};
The algorithm in your code is not idental to right rotate, you are using left rotate. For right rotate, need to insert the last element into font, and then erase the last element, and we also need to modolus the vector's length to avoid uncessaray rotate, or there would be a waste, an accepted code might like:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int r = k % nums.size();
for (int i = 0; i < r; i++) {
nums.insert(nums.begin(), nums.back());
nums.erase(std::prev(nums.end()));
}
}
};
And we can also call the STL algorithm: rotate, to rotate towards the right, we need to use the reverse iterator here:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int r = k % nums.size();
std::rotate(nums.rbegin(), nums.rbegin() + r, nums.rend());
}
};
Your algorithm will cause the vector elements to be shifted at every insertion into the front, it is not efficient, think about we have a large vector, shift all the elements would be a bottle-neck.
The STL version might have some other performance enhancement since it may move the element range in batch rather than swap the elements one by one.
And we can also call std::reverse three times to implenment our own rotate:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int r = k % nums.size();
std::reverse(nums.begin(), nums.end());
std::reverse(nums.begin(), nums.begin() + r);
std::reverse(nums.begin() + r, nums.end());
}
};
The last two versions are much faster than the previous ones, it's recommended to use them.

AddressSanitizer error on a throwing C++20 coroutine

I was playing with C++20 coroutine support and I found an addressing error that I can't explain nor fix. It happens on Xcode 12.5, shipping with Apple Clang 12.0.5, when enabling Address Sanitizer feature. Here is a minimum reproducible example:
#include <experimental/coroutine>
struct ReturnType
{
struct promise_type
{
std::experimental::suspend_never initial_suspend() { return {}; }
std::experimental::suspend_always final_suspend() noexcept { return {}; }
ReturnType get_return_object() { return {}; }
void unhandled_exception() { throw; }
void return_void() {}
};
};
ReturnType my_coroutine()
{
throw 0;
co_return;
}
int main() {
try {
my_coroutine();
} catch (...) {
}
return 0;
}
The coroutine merely throws a dummy int which is rethrown in promise_type::unhandled_exception. No local variables, no manual allocations, but still Address Sanitizer reports the following error:
=================================================================
==3204==ERROR: AddressSanitizer: heap-use-after-free on address 0x60600004bb18 at pc 0x000100001ea9 bp 0x7ffeefbff0f0 sp 0x7ffeefbff0e8
READ of size 8 at 0x60600004bb18 thread T0
#0 0x100001ea8 in my_coroutine() main.cpp:15
#1 0x1000024e3 in main main.cpp:24
#2 0x7fff204ed620 in start+0x0 (libdyld.dylib:x86_64+0x15620)
0x60600004bb18 is located 24 bytes inside of 64-byte region [0x60600004bb00,0x60600004bb40)
freed by thread T0 here:
#0 0x1001810bd in wrap__ZdlPv+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x550bd)
#1 0x100001e76 in my_coroutine() main.cpp:15
#2 0x1000024e3 in main main.cpp:24
#3 0x7fff204ed620 in start+0x0 (libdyld.dylib:x86_64+0x15620)
previously allocated by thread T0 here:
#0 0x100180c9d in wrap__Znwm+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x54c9d)
#1 0x10000153d in my_coroutine() main.cpp:15
#2 0x1000024e3 in main main.cpp:24
#3 0x7fff204ed620 in start+0x0 (libdyld.dylib:x86_64+0x15620)
SUMMARY: AddressSanitizer: heap-use-after-free main.cpp:15 in my_coroutine()
Shadow bytes around the buggy address:
0x1c0c00009710: 00 00 00 00 fa fa fa fa 00 00 00 00 00 00 00 00
0x1c0c00009720: fa fa fa fa 00 00 00 00 00 00 00 00 fa fa fa fa
0x1c0c00009730: 00 00 00 00 00 00 00 00 fa fa fa fa 00 00 00 00
0x1c0c00009740: 00 00 00 00 fa fa fa fa 00 00 00 00 00 00 00 00
0x1c0c00009750: fa fa fa fa 00 00 00 00 00 00 00 00 fa fa fa fa
=>0x1c0c00009760: fd fd fd[fd]fd fd fd fd fa fa fa fa fa fa fa fa
0x1c0c00009770: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x1c0c00009780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x1c0c00009790: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x1c0c000097a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x1c0c000097b0: 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
What is going on? Maybe a problem with the experimental coroutine support of Apple Clang 12?