2

My system ram is small, 1.5GB. I have a C++ programm that calls a specific method about 300 times. This method uses 2 maps (they are cleared every time) and I would like to know if it is possible in some of the calls of this method that the stack is overflowed and the program fails. If I put small data (so the method is called 30 times) the program runs fine. But now it raises SIGSEGV error. I am trying to fix this for about 3 days and no luck, every solution I tried failed.

I found some cause of the SIGSEGV below but nothing helped What is SIGSEGV run time error in C++?

Ok, here is the code. I have 2 instances, which contain some keywords-features and their scores

I want to get their eucleidian distance, which means I have to save all the keywords for each of the instances, then find the diffs for the keywords of the first one with those of the second and then find the diffs for the remaining of the second instance. What I want is while iterating the first map, to be able to delete elements from the second. The following method is called multiple times as we have two message collections, and every message from the first one is compared with every message from the second.

I have this code but it suddenly stops although I checked it is working for some seconds with multiple cout I put in some places

Note that this is for a university task so I cannot use boost and all those tricks. But I would like to know the way to bypass the problem I am into.

float KNNClassifier::distance(const Instance& inst1, const Instance& inst2) {   
map<string,unsigned> feat1;
map<string,unsigned> feat2;
for (unsigned i=0; i<inst1.getNumberOfFeatures(); i++) {
  feat1[inst1.getFeature(i)]=i;
}
for (unsigned i=0; i<inst2.getNumberOfFeatures(); i++) {
  feat2[inst2.getFeature(i)]=i;
}
float dist=0;

map<string,unsigned>::iterator it;
for (it=feat1.begin(); it!=feat1.end(); it++) {
  if (feat2.find(it->first)!=feat2.end()) {//if and only if it exists in inst2
    dist+=pow( (double) inst1.getScore(it->second) - inst2.getScore(feat2[it->first]) , 2.0);
    feat2.erase(it->first);
  }
  else {
    dist+=pow( (double) inst1.getScore(it->second) , 2.0);
  }
}

for (it=feat2.begin(); it!=feat2.end(); it++) {//for the remaining words
  dist+=pow( (double) inst2.getScore(it->second) , 2.0);
}
feat1.clear(); feat2.clear(); //ka8arizoume ta map gia thn epomenh xrhsh
return sqrt(dist);    
}

and I also tried this idea in order to not have to delete something but it suddenly stops too.

float KNNClassifier::distance(const Instance& inst1, const Instance& inst2) {
map<string,unsigned> feat1;
map<string,unsigned> feat2;
map<string,bool> exists;
for (unsigned i=0; i<inst1.getNumberOfFeatures(); i++) {
  feat1[inst1.getFeature(i)]=i;
}
for (unsigned i=0; i<inst2.getNumberOfFeatures(); i++) {
  feat2[inst2.getFeature(i)]=i;
  exists[inst2.getFeature(i)]=false;
  if (feat1.find(inst2.getFeature(i))!=feat1.end()) {
    exists[inst2.getFeature(i)]=true;
  }
}
float dist=0;
map<string,unsigned>::iterator it;
for (it=feat1.begin(); it!=feat1.end(); it++) {
  if (feat2.find(it->first)!=feat2.end()) {
    dist+=pow( (double) inst1.getScore(it->second) - inst2.getScore(feat2[it->first]) ,      2.0);
  }
  else {
    dist+=pow( (double) inst1.getScore(it->second) , 2.0);
  }
}

for (it=feat2.begin(); it!=feat2.end(); it++) {
  if(it->second==false){//if it is true, it means the diff was done in the previous iteration
    dist+=pow( (double) inst2.getScore(it->second) , 2.0);
  }
}

feat1.clear(); feat2.clear(); exists.clear();
return sqrt(dist);
}
Community
  • 1
  • 1
  • 2
    Yes, it can (for bad written program). If program tries to allocate memory via malloc or new, and it doesn't check allocation for success, NULL pointers may be generated and used, leading to SIGSEGV. – osgx Dec 29 '12 at 19:26
  • 1
    Also, there can be active `ulimit -s` which limits the available stack size. If your program consumes stack (has recursion or lot of temporary variables - local or auto), and it wants to use more stack that is allowed, SIGSEGV will be generated too. – osgx Dec 29 '12 at 19:40
  • The amount of RAM has nothing to do with whether or not your program runs out of memory if it runs on a demand-paged operating system. An embedded system with 1.5 gigabytes sounds unlikely. – Hans Passant Dec 29 '12 at 19:51
  • Even if the low RAM is causing the SIGSEGV, it would still take a bug in your program to allow it to happen. The bug would be failing to check the return value of a memory allocation function. But it is much more likely that you have a typical bug such as failing to allocate enough memory to hold a structure, accessing a structure after freeing it, or something like that. – David Schwartz Dec 29 '12 at 20:05
  • 1
    I added the code, I hope one of you will see what I am doing terribly wrong, I can't believe I am stuck for 3 days on this. I have checked it many many times. –  Dec 29 '12 at 20:50

5 Answers5

6

If malloc fails and thus returns NULL it can indeed lead to a SIGSEGV assuming the program does not properly handle that failure. However, if memory was that low your system would more likely start killing processes using lots of memory (the actual logic is more complicated, google for "oom killer" if you are interested).

Chances are good that there's simply a bug in your program. A good way to figure this out is using a memory debugger such as valgrind to see if you access invalid memory locations.

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
1

One possible explanation is that your program accesses a dynamically-allocated object after freeing it. If the object is small enough, the memory allocator keeps the memory around for the next allocation, and the access after free is harmless. If the object is large, the memory allocator unmaps the pages used to hold the object, and the access after free causes a SIGSEGV.

It is virtually certain that regardless of the underlying mechanism by which the SIGSEGV occurs, there is a bug in the code somewhere that is a key part of the causal chain.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
0

1.5GB isn't that small. You can do a lot in 1.5GB in general. For 300 iterations to use up 1.5GB (let's say 0.5GB is used by the OS kernel, etc), you need to use roughly 32MB per iteration. That is quite a lot of memory, so, my guess is that either your code is actually using A LOT of memory, or your code contains a leak of some sort. More likely the latter. I have worked on machines with less than 64KB, and my first PC had 8MB of ram, and that was considered A LOT at the time.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
0

No, this code is unable to cause a segfault if the system runs out of memory. map allocation uses the new operator, which does not use the stack for allocation. It uses the heap, and will throw a bad_alloc exception if the memory is exhausted, aborting before an invalid memory access can happen:

    $ cat crazyalloc.cc
    int main(void)
    {
            while(1) {
                    new int[100000000];
            }

            return 0;
    }
    $ ./crazyalloc
    terminate called after throwing an instance of 'std::bad_alloc'
      what():  std::bad_alloc
    Aborted (core dumped)

The fact that an alternative implementation also crashes is a hint that the problem is not in this code.

The problem is on the Instance class instead. It's probably not lack of memory, it should be a buffer overflow, which can be confirmed with a debugger.

hdante
  • 7,685
  • 3
  • 31
  • 36
0

As mentioned above, the most probable cause is bad memory allocation or memory leak. Check for buffer overflows, or if you try to access a resource after you free it.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055