C ++ segfault,可重现的示例

时间:2019-11-16 03:10:20

标签: c++ debugging vector segmentation-fault gdb

使用其他人建议的完整代码重新发布。刚刚使用导致分段错误的硬编码参数更新了主函数。

宽度高度更改为其他值可使程序正常运行,例如分别为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所说的确切发生。如果有人可以提供进一步的见解,将不胜感激。

1 个答案:

答案 0 :(得分:3)

崩溃发生在这里:

#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中崩溃时,您应该立即怀疑堆损坏。

address sanitizer(在您的编译和链接命令行中添加-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 s像素画一条线。您可能有一个错误的错误-有效像素索引的范围为[0 .. width-1] * [0 .. height-1]

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