C++segfault,可重复的例子

C++ segfault, reproducible example

本文关键字:C++segfault      更新时间:2023-10-16

按照其他人的建议,用完整的代码重新测试。刚刚用导致分段错误的硬编码参数更新了主函数。

宽度高度更改为其他值可以使程序正常运行,例如分别为500和433。

主文件:

#include <cstdint>
#include <iostream>
#include <sstream>
#include <vector>
#include <cmath>
#include "sierpinski.h"
Triangle::Triangle() {
this->pixels = nullptr;
this->top = Coordinate();
this->left = Coordinate();
this->right = Coordinate();
this->fg_color = 0;
this->area = 0.0;
}
Triangle::Triangle(uint32_t* pixels, Coordinate top, Coordinate left, Coordinate right, uint32_t fg_color) {
this->pixels = pixels;
this->top = top;
this->left = left;
this->right = right;
this->fg_color = fg_color;
this->area = calculateArea(top, left, right);
}
void Triangle::DrawLines(Coordinate top, Coordinate left, Coordinate right) {
int width = getWidth(this->left, this->right);
//left to top
std::vector<Coordinate> line = left.Bresenham(top);
for (unsigned int i = 0; i < line.size(); i++) {
this->pixels[width * line[i].getY() + line[i].getX()] = this->fg_color;
}
line.clear();
// left to right
line = left.Bresenham(right);
for (unsigned int i = 0; i < line.size(); i++) {
this->pixels[width * line[i].getY() + line[i].getX()] = this->fg_color;
}
line.clear();
// top to right
line = top.Bresenham(right);
for (unsigned int i = 0; i < line.size(); i++) {
this->pixels[width * line[i].getY() + line[i].getX()] = this->fg_color;
}
}
void Triangle::Sierpinski(Coordinate top, Coordinate left, Coordinate right, const double min_area) {
if (calculateArea(top, left, right) < min_area) {
return;
}
DrawLines(top, left, right);
Triangle triangle(this->pixels, top, left, right, this->fg_color);
Sierpinski(top, top.Midpoint(left), top.Midpoint(right), min_area);
Sierpinski(top.Midpoint(left), left, left.Midpoint(right), min_area);
Sierpinski(top.Midpoint(right), left.Midpoint(right), right, min_area);
}
uint32_t* Triangle::getPixels() {
return this->pixels;
}
uint32_t Triangle::getFg_color() {
return this->fg_color;
}
double Triangle::getArea() {
return this->area;
}
double Triangle::getWidth(Coordinate left, Coordinate right) {
return left.distance(right);
}
double Triangle::calculateArea(Coordinate top, Coordinate left, Coordinate right) {
return std::abs(top.getX() * (left.getY() - right.getY()) + left.getX() * (right.getY() - top.getY()) + right.getX() * (top.getY() - left.getY())) / 2.0;
}
Coordinate::Coordinate() {
this->x = 0;
this->y = 0;
}
Coordinate::Coordinate(int x, int y) {
this->x = x;
this->y = y;
}
Coordinate::Coordinate(const Coordinate &other) {
this->x = other.x;
this->y = other.y;
}
int Coordinate::getX() {
return this->x;
}
int Coordinate::getY() {
return this->y;
}
double Coordinate::distance(Coordinate other) {
return std::sqrt(std::pow((this->x - other.x), 2) + std::pow((this->y - other.y), 2));
}
Coordinate Coordinate::Midpoint(Coordinate other) {
double midX = (this->x + other.getX()) / 2;
double midY = (this->y + other.getY()) / 2;
return Coordinate(midX, midY);
}
int Coordinate::gcd(int a, int b) {
if (b == 0)
return a;
return gcd(b, a%b);
}
std::vector<Coordinate> Coordinate::Bresenham(Coordinate other) {
int x1 = this->x, y1 = this->y;
int const x2 = other.x, y2 = other.y;
std::vector<Coordinate> points;
int delta_x(x2 - x1);
signed char const ix((delta_x > 0) - (delta_x < 0));
delta_x = std::abs(delta_x) << 1;
int delta_y(y2 - y1);
signed char const iy((delta_y > 0) - (delta_y < 0));
delta_y = std::abs(delta_y) << 1;
Coordinate newPoint1(x1, y1);
points.push_back(newPoint1);
if (delta_x >= delta_y) {
int error(delta_y - (delta_x >> 1));
while (x1 != x2) {
if ((error > 0) || (!error && (ix > 0))) {
error -= delta_x;
y1 += iy;
}
error += delta_y;
x1 += ix;
Coordinate newPoint2(x1, y1);
points.push_back(newPoint2);
}
} else {
int error(delta_x - (delta_y >> 1));
while (y1 != y2) {
if ((error > 0) || (!error && (iy > 0))) {
error -= delta_y;
x1 += ix;
}
error += delta_x;
y1 += iy;
Coordinate newPoint3(x1, y1);
points.push_back(newPoint3);
}
}
return points;
}
int main() {
int width = 55;
int height = 40;
uint32_t bg_color = 4095617261;
uint32_t fg_color = 2988200782;
double min_area = 1.08;
std::vector<uint32_t> pixels(width * height, bg_color);
Coordinate top, left, right;
top = Coordinate(width / 2, 0);
left = Coordinate(0, height);
right = Coordinate(width, height);
Triangle triangle = Triangle(pixels.data(), top, left, right, fg_color);
triangle.Sierpinski(top, left, right, min_area);
std::cout.write(reinterpret_cast<char *>(pixels.data()), width * height * 4);
}

头文件:

#ifndef SIERPINSKI_H
#define SIERPINSKI_H
#include <vector>
class Coordinate {
public:
Coordinate();
Coordinate(int x, int y);
Coordinate(const Coordinate &other);
int getX();
int getY();
double distance(Coordinate);
Coordinate Midpoint(Coordinate other);
int gcd(int a, int b);
std::vector<Coordinate> Bresenham(Coordinate other);
int countPoints(Coordinate other);
std::vector<Coordinate> getPoints(Coordinate other);
private:
int x;
int y;
};
class Triangle {
public:
Triangle();
Triangle(uint32_t* pixels, Coordinate top, Coordinate left, Coordinate right, uint32_t fg_color);
void DrawLines(Coordinate top, Coordinate left, Coordinate right);
void Draw(double min_area);
void Sierpinski(Coordinate top, Coordinate left, Coordinate right, double min_area);
double calculateArea(Coordinate top, Coordinate left, Coordinate right);
uint32_t* getPixels();
uint32_t getFg_color();
double getArea();
Coordinate top, left, right;
double getWidth(Coordinate left, Coordinate right);
private:
uint32_t* pixels;
uint32_t fg_color;
double area;
};
#endif

使用gdb后,我的Bresenham函数中似乎出现了错误:

points.push_back(newPoint3);

但其他用户表示,seg故障可能并没有发生在gdb所说的地方。如果有人能提供进一步的见解,我们将不胜感激。

崩溃发生在这里:

#0  0x00007ffff7b12c46 in malloc () from /lib64/libc.so.6
#1  0x00007ffff7e5e059 in operator new(unsigned long) () from /lib64/libstdc++.so.6
#2  0x00000000004035ac in __gnu_cxx::new_allocator<Coordinate>::allocate (this=0x7fffffffd3f0, __n=2) at /usr/include/c++/9/ext/new_allocator.h:114
#3  0x000000000040335b in std::allocator_traits<std::allocator<Coordinate> >::allocate (__a=..., __n=2) at /usr/include/c++/9/bits/alloc_traits.h:444
#4  0x0000000000402fe2 in std::_Vector_base<Coordinate, std::allocator<Coordinate> >::_M_allocate (this=0x7fffffffd3f0, __n=2) at /usr/include/c++/9/bits/stl_vector.h:343
#5  0x00000000004028be in std::vector<Coordinate, std::allocator<Coordinate> >::_M_realloc_insert<Coordinate const&> (this=0x7fffffffd3f0, __position={x = 0, y = 0}, __args#0=...) at /usr/include/c++/9/bits/vector.tcc:440
#6  0x00000000004024a0 in std::vector<Coordinate, std::allocator<Coordinate> >::push_back (this=0x7fffffffd3f0, __x=...) at /usr/include/c++/9/bits/stl_vector.h:1195
#7  0x0000000000401f48 in Coordinate::Bresenham (this=0x7fffffffd4c8, other=...) at t.cc:205
#8  0x0000000000401610 in Triangle::DrawLines (this=0x7fffffffd580, top=..., left=..., right=...) at t.cc:86
#9  0x0000000000401823 in Triangle::Sierpinski (this=0x7fffffffd580, top=..., left=..., right=..., min_area=1.0800000000000001) at t.cc:96
#10 0x0000000000402154 in main () at t.cc:225

任何malloc发生崩溃时,都应该立即怀疑堆已损坏。

以下是地址清理程序(只需将-fsanitize=address添加到编译和链接命令行(所说的内容:

=================================================================
==5470==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x625000002360 at pc 0x000000401e84 bp 0x7fffffffcdb0 sp 0x7fffffffcda0
WRITE of size 4 at 0x625000002360 thread T0
#0 0x401e83 in Triangle::DrawLines(Coordinate, Coordinate, Coordinate) /tmp/t.cc:76
#1 0x4028c5 in Triangle::Sierpinski(Coordinate, Coordinate, Coordinate, double) /tmp/t.cc:96
#2 0x4043df in main /tmp/t.cc:225
#3 0x7ffff707ef32 in __libc_start_main (/lib64/libc.so.6+0x23f32)
#4 0x40126d in _start (/tmp/a.out+0x40126d)
0x625000002360 is located 0 bytes to the right of 8800-byte region [0x625000000100,0x625000002360)
allocated by thread T0 here:
#0 0x7ffff768a9d7 in operator new(unsigned long) (/lib64/libasan.so.5+0x10f9d7)
#1 0x406f82 in __gnu_cxx::new_allocator<unsigned int>::allocate(unsigned long, void const*) /usr/include/c++/9/ext/new_allocator.h:114
#2 0x406e67 in std::allocator_traits<std::allocator<unsigned int> >::allocate(std::allocator<unsigned int>&, unsigned long) /usr/include/c++/9/bits/alloc_traits.h:444
#3 0x406b8f in std::_Vector_base<unsigned int, std::allocator<unsigned int> >::_M_allocate(unsigned long) /usr/include/c++/9/bits/stl_vector.h:343
#4 0x40663e in std::_Vector_base<unsigned int, std::allocator<unsigned int> >::_M_create_storage(unsigned long) /usr/include/c++/9/bits/stl_vector.h:358
#5 0x405a5c in std::_Vector_base<unsigned int, std::allocator<unsigned int> >::_Vector_base(unsigned long, std::allocator<unsigned int> const&) /usr/include/c++/9/bits/stl_vector.h:302
#6 0x404bf0 in std::vector<unsigned int, std::allocator<unsigned int> >::vector(unsigned long, unsigned int const&, std::allocator<unsigned int> const&) /usr/include/c++/9/bits/stl_vector.h:521
#7 0x403faa in main /tmp/t.cc:218
#8 0x7ffff707ef32 in __libc_start_main (/lib64/libc.so.6+0x23f32)
SUMMARY: AddressSanitizer: heap-buffer-overflow /tmp/t.cc:76 in Triangle::DrawLines(Coordinate, Coordinate, Coordinate)

因此,确实存在堆损坏(已分配的堆缓冲区溢出(。

希望这是足够的信息,你可以在你的程序中找到一个逻辑错误。

p.S.

看起来您正在分配一个height*width像素的矩形,然后尝试从height * width的像素中画一条线。您可能有一个逐个错误——有效像素索引[0 .. width-1] * [0 .. height-1]范围内。

当我在向量中保留(width+1) * (height+1)空间时,问题就消失了。