简体   繁体   English

C++ 段错误,可重现的示例

[英]C++ segfault, reproducible example

Reposting with full code, as suggested from others.根据其他人的建议,使用完整代码重新发布。 Just updated the main function with hard coded arguments that causes segmentation fault.刚刚使用导致分段错误的硬编码 arguments 更新了主要的 function。

Changing the width and height to something else lets the program run fine, for example 500 and 433 respectively.宽度高度更改为其他值可以让程序运行良好,例如分别为 500 和 433。

Main file:主文件:

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

Header file: Header 文件:

#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

After using gdb, it seemed the error was occuring in my Bresenham function at the line:使用 gdb 后,我的 Bresenham function 似乎出现了错误:

points.push_back(newPoint3);

But other users stated that seg fault may not be occurring exactly where gdb says it is.但其他用户表示,段错误可能不会完全发生在 gdb 所说的位置。 If anyone can provide further insight it would be greatly appreciated.如果有人可以提供进一步的见解,将不胜感激。

The crash happens here:崩溃发生在这里:

#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

Any time you have a crash in malloc , you should immediately suspect heap corruption.每当您在malloc中发生崩溃malloc ,您应该立即怀疑堆损坏。

Here is what address sanitizer (just add -fsanitize=address to your compile and link command lines) says:这是地址清理程序(只需将-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)

So indeed you have heap corruption (overflow of allocated heap buffer).所以确实你有堆损坏(分配的堆缓冲区溢出)。

Hopefully this is enough info for you to find a logic bug in your program.希望这些信息足以让您找到程序中的逻辑错误。

PS附言

It looks like you are allocating a rectangle of height * width pixels, then try to draw a line from the height * width s pixel.看起来您正在分配一个height * width像素的矩形,然后尝试从height * width s 像素绘制一条线。 You likely have an off-by-one bug -- valid pixel indices are in the range [0.. width-1] * [0.. height-1] .您可能有一个错误 - 有效像素索引[0.. width-1] * [0.. height-1]范围内。

When I reserve (width+1) * (height+1) space in the vector, the problem goes away.当我在向量中保留(width+1) * (height+1)空间时,问题就消失了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM