std::vector<std::vector<int>> push_back 给出堆缓冲区溢出
std::vector<std::vector<int>> push_back gives heap-buffer-overflow
我正在尝试使用以下代码来解决 hackerrank 的 even tree task 以读取输入(std::cin
替换为自定义字符串数据以将输入和程序代码放在一个地方):
#include <iostream>
#include <vector>
#include <sstream>
int main()
{
std::istringstream input( "10 9\n2 1\n3 1\n4 3\n5 2\n6 1\n7 2\n8 6\n9 8\n10 8\n");
std::cin.rdbuf(input.rdbuf());
int n,m;
std::cin >> n >> m;
std::vector<std::vector<int>> v(n);
//std::vector<std::vector<int>> v(n, std::vector<int>(n, -1));
int ui, vi;
while (m--)
{
std::cin >> ui >> vi;
v[ui].push_back(vi);
v[vi].push_back(ui);
}
}
第二个数字将是边的数量(后续数字对),因此我可以预测我需要向量中的多少个元素。
此代码给我以下消毒剂错误(与注释行相同的错误):
clang++-3.6 -g -Wall -fsanitize=address --std=c++11 main.cpp && ./a.out
=================================================================
==11606==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x611000009ff8 at pc 0x0000004e0beb bp 0x7ffd09cb9ab0 sp 0x7ffd09cb9aa8
READ of size 8 at 0x611000009ff8 thread T0
#0 0x4e0bea (PATH/a.out+0x4e0bea)
#1 0x4dfa28 (PATH/a.out+0x4dfa28)
#2 0x7f407bd75ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
#3 0x438227 (PATH/a.out+0x438227)
0x611000009ff8 is located 8 bytes to the right of 240-byte region [0x611000009f00,0x611000009ff0)
allocated by thread T0 here:
#0 0x4de672 (PATH/a.out+0x4de672)
#1 0x4ecf8a (PATH/a.out+0x4ecf8a)
#2 0x4eccd5 (PATH/a.out+0x4eccd5)
#3 0x4eca90 (PATH/a.out+0x4eca90)
#4 0x4ec70f (PATH/a.out+0x4ec70f)
#5 0x4ea89a (PATH/a.out+0x4ea89a)
#6 0x4e047a (PATH/a.out+0x4e047a)
#7 0x4df8f2 (PATH/a.out+0x4df8f2)
#8 0x7f407bd75ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
Shadow bytes around the buggy address:
0x0c227fff93a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff93b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff93c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff93d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff93e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c227fff93f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa[fa]
0x0c227fff9400: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff9410: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff9420: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff9430: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff9440: 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
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
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
==11606==ABORTING
我在这里错过了什么?
编辑
好的,所以我找到了一种解决方案,即 emplace_back
v
上的默认 std::vector<int>
:
std::vector<std::vector<int>> v(n);
for (int i = 0; i < n; ++i) v.emplace_back();
但是为什么它之前没有工作,因为构造函数带有 size_type
cppreference
3) Constructs the container with count default-inserted instances of T. No copies are made.
在这一行
std::vector<std::vector<int>> v(n);
您创建了一个包含 10 个元素的向量,这意味着您可以访问包含索引 [0,9] 的元素。在最后的数据中,您有 10 8,这将导致超出范围的访问。如果您的数据在 [1,10] 范围内,您需要调整索引:
v[ui-1].push_back(vi);
v[vi-1].push_back(ui);
PS 您的添加消除了错误,因为您使用 10 个元素创建了 std::vector
,然后在循环中添加了 10 个元素,这使得索引有效 [0,19]。您可以通过以下方式修复您的代码:
std::vector<std::vector<int>> v(n+1);
没有额外的循环,如果你想在 [1,10] 区间使用索引(尽管索引为 0 的元素仍然存在)。
您可以考虑使用 std::map<std::vector<int>>
,您不必担心索引:
#include <iostream>
#include <vector>
#include <map>
#include <sstream>
int main()
{
std::istringstream input( "10 9\n2 1\n3 1\n4 3\n5 2\n6 1\n7 2\n8 6\n9 8\n10 8\n");
std::cin.rdbuf(input.rdbuf());
int n,m;
std::cin >> n >> m;
std::map<std::vector<int>> v;
int ui, vi;
while (m--)
{
std::cin >> ui >> vi;
v[ui].push_back(vi);
v[vi].push_back(ui);
}
}
在这种情况下,您将只有使用索引的数据,但按索引访问元素会慢得多。如果您不关心数据是否在容器内排序,您也可以考虑 std::unordered_map
以获得更快的访问速度。
我正在尝试使用以下代码来解决 hackerrank 的 even tree task 以读取输入(std::cin
替换为自定义字符串数据以将输入和程序代码放在一个地方):
#include <iostream>
#include <vector>
#include <sstream>
int main()
{
std::istringstream input( "10 9\n2 1\n3 1\n4 3\n5 2\n6 1\n7 2\n8 6\n9 8\n10 8\n");
std::cin.rdbuf(input.rdbuf());
int n,m;
std::cin >> n >> m;
std::vector<std::vector<int>> v(n);
//std::vector<std::vector<int>> v(n, std::vector<int>(n, -1));
int ui, vi;
while (m--)
{
std::cin >> ui >> vi;
v[ui].push_back(vi);
v[vi].push_back(ui);
}
}
第二个数字将是边的数量(后续数字对),因此我可以预测我需要向量中的多少个元素。
此代码给我以下消毒剂错误(与注释行相同的错误):
clang++-3.6 -g -Wall -fsanitize=address --std=c++11 main.cpp && ./a.out
=================================================================
==11606==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x611000009ff8 at pc 0x0000004e0beb bp 0x7ffd09cb9ab0 sp 0x7ffd09cb9aa8
READ of size 8 at 0x611000009ff8 thread T0
#0 0x4e0bea (PATH/a.out+0x4e0bea)
#1 0x4dfa28 (PATH/a.out+0x4dfa28)
#2 0x7f407bd75ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
#3 0x438227 (PATH/a.out+0x438227)
0x611000009ff8 is located 8 bytes to the right of 240-byte region [0x611000009f00,0x611000009ff0)
allocated by thread T0 here:
#0 0x4de672 (PATH/a.out+0x4de672)
#1 0x4ecf8a (PATH/a.out+0x4ecf8a)
#2 0x4eccd5 (PATH/a.out+0x4eccd5)
#3 0x4eca90 (PATH/a.out+0x4eca90)
#4 0x4ec70f (PATH/a.out+0x4ec70f)
#5 0x4ea89a (PATH/a.out+0x4ea89a)
#6 0x4e047a (PATH/a.out+0x4e047a)
#7 0x4df8f2 (PATH/a.out+0x4df8f2)
#8 0x7f407bd75ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
Shadow bytes around the buggy address:
0x0c227fff93a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff93b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff93c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff93d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff93e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c227fff93f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa[fa]
0x0c227fff9400: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff9410: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff9420: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff9430: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff9440: 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
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
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
==11606==ABORTING
我在这里错过了什么?
编辑
好的,所以我找到了一种解决方案,即 emplace_back
v
上的默认 std::vector<int>
:
std::vector<std::vector<int>> v(n);
for (int i = 0; i < n; ++i) v.emplace_back();
但是为什么它之前没有工作,因为构造函数带有 size_type
cppreference
3) Constructs the container with count default-inserted instances of T. No copies are made.
在这一行
std::vector<std::vector<int>> v(n);
您创建了一个包含 10 个元素的向量,这意味着您可以访问包含索引 [0,9] 的元素。在最后的数据中,您有 10 8,这将导致超出范围的访问。如果您的数据在 [1,10] 范围内,您需要调整索引:
v[ui-1].push_back(vi);
v[vi-1].push_back(ui);
PS 您的添加消除了错误,因为您使用 10 个元素创建了 std::vector
,然后在循环中添加了 10 个元素,这使得索引有效 [0,19]。您可以通过以下方式修复您的代码:
std::vector<std::vector<int>> v(n+1);
没有额外的循环,如果你想在 [1,10] 区间使用索引(尽管索引为 0 的元素仍然存在)。
您可以考虑使用 std::map<std::vector<int>>
,您不必担心索引:
#include <iostream>
#include <vector>
#include <map>
#include <sstream>
int main()
{
std::istringstream input( "10 9\n2 1\n3 1\n4 3\n5 2\n6 1\n7 2\n8 6\n9 8\n10 8\n");
std::cin.rdbuf(input.rdbuf());
int n,m;
std::cin >> n >> m;
std::map<std::vector<int>> v;
int ui, vi;
while (m--)
{
std::cin >> ui >> vi;
v[ui].push_back(vi);
v[vi].push_back(ui);
}
}
在这种情况下,您将只有使用索引的数据,但按索引访问元素会慢得多。如果您不关心数据是否在容器内排序,您也可以考虑 std::unordered_map
以获得更快的访问速度。