1
votes

I'm working on a graphic application. It makes significant use of virtual classes. I'm getting some segmentation faults that I'm having trouble debugging.

The primary classes in this application are:

  • Shape (a virtual class)
    • Rectangle
    • Polygon
    • Circle
  • Picture (essentially a collection of shapes)

Here is a shortened copy of the applicable part of my code:

class Picture
{
  ...
  Picture(Graphics& gd)
  {
    gfx = &gd;
  }

  void Picture::draw() const
  {
    for(int i=0; i<shapes.size();i++)
    {
      shapes[i]->draw(*gfx);  // This line causes a segmentation fault
    }
  }
...
private:
  std::vector<Shape*> shapes;
  Graphics* gfx;
}

class Shape
{
...
virtual void draw(Graphics& g) const = 0;
...
}

Here is a gdb session showing some information:

Program terminated with signal 11, Segmentation fault.
[New process 89330    ]
#0  0x00020d38 in Rectangle::draw (this=0x41e10, g=@0xffbff904)
    at rectangle.cpp:42
42           g.setColor(getFillColor());
(gdb) print &g
$1 = (class Graphics *) 0xffbff904
(gdb) bt
#0  0x00020d38 in Rectangle::draw (this=0x41e10, g=@0xffbff904)
    at rectangle.cpp:42
#1  0x0001bae8 in Picture::draw (this=0xffbff950) at picture.cpp:45
#2  0x0002394c in writePicture (p=
      { = {_vptr.Figure = 0x2be38}, shapes = { >> = {_M_impl = {> = {> = {}, }, _M_start = 0x3f648, _M_finish = 0x3f664, _M_end_of_storage = 0x3f664}}, }, gfx = 0xffbff904}, fileName=
        {static npos = 4294967295, _M_dataplus = {> = {> = {}, }, _M_p = 0x3f49c "t1.dat.eps"}}) at testpicture.cpp:51
#3  0x00023b3c in simpleTest (inFileName=
        {static npos = 4294967295, _M_dataplus = {> = {> = {}, }, _M_p = 0x3fe24 "t1.dat"}}, outFileName=
        {static npos = 4294967295, _M_dataplus = {> = {> = {}, }, _M_p = 0x3f49c "t1.dat.eps"}}, bb=@0xffbff9c8) at testpicture.cpp:70
#4  0x00024c3c in main (argc=2, argv=0xffbffa74) at testpicture.cpp:165

I've been banging my head against the wall for a couple of hours now trying to figure this thing out. It has something to do with the Graphic member of the Picture class. However, I'm failing to see how it pieces together to create a segmentation fault.

EDIT:

Here is the portion of the testpicture.cpp where the Graphics object is created:

RectangularArea getPictureBounds (string fileName)
{
  ifstream in (fileName.c_str());

  PSGraphics gr(fileName + ".bb");
  Picture p0(gr);

  Shape* shape;
  while (in >> shape)
  {
    if (shape != NULL)
      p0.add(*shape);
  }
  return p0.boundingBox();
}

Graphic is a virtual class as well. In this case, PSGraphic inherits from it.

2
Can you post the testpicture.cpp - looks like the problem is there. How is the Graphics instance allocated? - Nikolai Fetissov
One can tell by the address that it is allocated from stack (auto storage). - Tronic
Yes, that's obvious. Questions hopefully make OP look at other parts of the code with suspicion. - Nikolai Fetissov
I've added the testpicture.cpp code where the graphics object is created. If this object is on the stack, how can I put a copy of it on the heap? There is no clone function (I cannot add a clone function). If using a standard copy, the relevant data would be stripped since Graphic is virtual. - the_gastropod
The in >> shape looks really suspicious here - most probably it just reads some integer into the pointer, and not allocate a Shape subclass as you expect. - Nikolai Fetissov

2 Answers

2
votes

gfx points to an object in stack. Are you sure that the object is still there (at the same position where it was) when you are trying to draw?

2
votes

It's bad practice to store pointer to argument given to you as a reference - this creates confusion about memory ownership. Either make a copy of the referenced object (if it's a value class), or change the method to take smart pointer (like boost::shared_ptr) to the shared resource. This way the resource ownership management is explicit.

To your immediate issue - the Graphics instance is probably allocated on the stack and goes out of scope, thus destructed. Then your Picture code references dead object.