1

This portion of my code (for this project) gives me a segmentation fault. The source code is available here.

void PackageManager::install_package(string pname)
{
  if(repository->exists_package(pname)) {
    Package *pkg;
    ConcretePackage *cpkg;
    MetaPackage *mpkg;
    if(repository->is_virtual(pname)) {
      //code for dealing with meta packages
      mpkg = new MetaPackage(pname);
      pkg = mpkg;
      system->operator+(pname);
    } else {
      //code for dealing with concrete packages
      cpkg = new ConcretePackage(pname);
      pkg = cpkg;
      system->operator+(pname);
      if( cpkg->getDependencies().size() > 0) {
        for(set<string>::iterator sit = pkg->getDependencies().begin();
            sit!=pkg->getDependencies().end(); ++sit) {
          cout<<*sit<<endl;
          system->operator+(*sit);
        }
      }
    }
  } else {
    cout<<"Invalid Package Name"<<endl;
  }
}

Here is the error when I run gdb and also the backtrace.

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b6db03 in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ()
   from /usr/lib/libstdc++.so.6
(gdb) backtrace
#0  0x00007ffff7b6db03 in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ()
   from /usr/lib/libstdc++.so.6
#1  0x00000000004052e8 in PackageManager::install_package (this=0x7fffffffe280, pname=...) at packagemanager.cpp:39
#2  0x000000000040575a in main () at packagemanager.cpp:79

I'm trying to iterate through a set and perform some operation. I can pode more code if needed. I would also like it if someone could guide me to a place where I could learn to understand these segfaults. I don't know much about them and I tend to panic when I encounter these.

This is the operator+ for the System class.

void System::operator+(string pname)
{
  installed_packages.insert(pname);
  log.push_back("Added " + pname);
}

I know the design isn't the best but I'm trying to implement the items of a checklist for this project, which covers various areas of Object Oriented Programming. The checklist is also available on github.

I have tried to run the code through the debugger, printng out *sit. It works for sometime and then crashes. I don't know too much about gdb.

Community
  • 1
  • 1
nikhil
  • 8,925
  • 21
  • 62
  • 102
  • 2
    What is `system->operator+()`? – Drahakar Nov 29 '11 at 07:56
  • 1
    @GregHewgill From what I can see in the stacktrace, the error is comming from `PackageManager::install_package` in the `operator<<`of `std::ostream`. Seems like it's in the for loop. – Drahakar Nov 29 '11 at 08:02
  • @GregHewgill : I have added the link to my repo at github. – nikhil Nov 29 '11 at 11:07
  • @Drahakar : I've added the definition of the overloaded operator. Also how can you infer things from the stacktrace. I'd want to be able to do that too. – nikhil Nov 29 '11 at 11:08

1 Answers1

5

StackOverflow has a few "What is a segmentation fault?" style Q&A:

What is a segmentation fault?

Ideally you are working in an environment with a debugger and the ability to step through your code line-by-line, or place breakpoints. This can help you isolate the circumstances surrounding your crash. You already had a line number in the stack trace--which we are assuming points a smoking gun at:

cout<<*sit<<endl;

But stepping through with a debugger could answer questions like whether this happens the first time through the loop...and if not then on which element.


UPDATE: Looking at the pieces of this code you have on GitHub (which doesn't include the above code), I see that ConcretePackage::getDependencies() is returning a set by value and not by reference. This means that each time you call the member, you get a new copy of the set. Iterators from different containers should not be compared with each other, even if they are the same type:

comparing iterators from different containers

To address this, you could change:

for(set<string>::iterator sit = pkg->getDependencies().begin();
        sit!=pkg->getDependencies().end(); ++sit) { ... }

...into:

set<string> deps = pkg->getDependencies();
for(set<string>::iterator sit = deps.begin(); sit!=deps.end(); ++sit) { ... }

...or you could change your definition of getDependencies to return a reference:

set<string>& ConcretePackage::getDependencies() {
    return dependencies;
}

Studying the reasons to do it one way vs. another is left as an exercise to the student. :P


A few more notes:

  • You don't need a special-case test against zero size for collection classes you're going to use iterators with. If a set contains no elements, then the .begin() of that set will return an iterator that is equal to the .end(). The loop you have above handles this case fine and would exit immediately.

  • Explicitly calling operator+ in your code without doing anything with the return value suggests you probably have some kind of side-effect. Few people expect expressions like a = b + c to change b or c...and a single line of code like b->operator+(c); suggests you're doing something of the sort. While technically possible, I'd avoid it. See point #2 here: Operator overloading

  • When you post code samples try and keep them readable and not needing a lot of scroll bars to display. Break lines up if you notice in the preview that it's putting a long horizontal scroll bar. Instead of using separate lines for each brace, put them on the same lines as the condition. (Regardless of what convention you use in your codebase, the briefer the better when asking for technical help online.)

(Also provide context. If you don't say it's homework and a design of your own, then people like me will go Googling to try and figure what sort of package manager you are using. Luckily I found your programmers.stackexchange.com post...)

Community
  • 1
  • 1
  • You are right, I should have provided the context. I was being brief, I didn't want to post too much code. I have zeroed on this segment and thought it'd be most relevant. I didn't initially test for 0 but after getting that error I thought that it might somehow prevent it. If you could provide some suggestions by looking at the code, I'd be grateful. – nikhil Nov 29 '11 at 11:11
  • 1
    @nikhil I've found your problem (well, the cause of this one anyway). Updated. Also I notice that your Makefile is wrong and is probably causing you a lot of frustration because it won't rebuild the right files after edits. If you're going to use make then do some reading up on it to be sure you're using it correctly: http://www.cs.umd.edu/class/fall2002/cmsc214/Tutorial/makefile.html – HostileFork says dont trust SE Nov 29 '11 at 12:21
  • 1
    Incidentally, you should strike that use of operator overloading of `+` as a nonsensical way of calling a log function. If you have to demonstrate operator overloading somewhere, I'm sure there are more reasonable things you could do where operator overloads let you "add" and "subtract" dependencies from packages (for instance)... – HostileFork says dont trust SE Nov 29 '11 at 12:53
  • You sir, are a life saver. Now if you could guide me to some tutorial where i can learn to debug the segmentation faults myself. I've tried a few gdb tutorials but they deal with obvious errors and nothing seems to apply when I actually code. I did check out your blog, its really nice. I appreciate your taking the time out to help a beginner like me. – nikhil Nov 29 '11 at 16:29
  • 1
    @nikhil Glad to help, it's fun to participate in such a thing that didn't exist when I was learning to program...and now I can tell people I saved a kid's life in India. :) Thanks for looking into the blog, I actually have been doing StackOverflow instead of writing for it. As for debugging, you need an IDE and I think advice on that front is a whole separate question! Ask it and outline what tools and platform you have, as well as what the constraints are for your class...and detail the kind of confusion you currently have that gets you stuck. – HostileFork says dont trust SE Nov 29 '11 at 21:00