1

I am writing a client-server daemon which have to accept and translate specific message formats, check them submit to submit all activity to DB. Program is multithreaded. So, I started to work, and began to get SIGSEGV in some cases. So I had to redesign my program and start all over. I am wondering, if there are any "best practices" or tips on how to minimize risk of SIGSEGV ? I know, that each pointer should be checked before usage and NULLED after deleting, but if there any high level, design tips ?

P.S. Sorry, if my question if quite dummy, but I googled for this topic and did not find any reasonable articles on this topic. All your opinions are appreciated.

unresolved_external
  • 1,930
  • 5
  • 30
  • 65
  • 3
    Don't use pointers. And if you do always check for `NULL` pointers. – Some programmer dude May 27 '13 at 07:43
  • 1
    Without pointers a lot of C++ advantages would be missing – unresolved_external May 27 '13 at 07:44
  • Minimize the use of pointers, access any kind of arrays within its bounds, check whether pointer is `NULL` before using, make sure you allocate new memory before using a pointer which you have already freed (it may not be giving `NULL`). – raj raj May 27 '13 at 07:47
  • How do you even "check pointer before usage"? It may very well point to an already-deleted-object, and they look nothing special. Or worse, it may point to a memory where a destoryed object, and now another object resides, in the middle of the construction. – Joker_vD May 27 '13 at 07:49
  • 2
    The most common use of pointers seems to be variable length collections, and C++ have an excellent collection of collections (pun not intended). And using copy or move constructors properly you barely need to put pointers in the collections. And instead of passing pointers around you pass references around. Yes, there are cases where you can't get rid of pointers, but then use smart pointers _and check for `NULL` pointers!_ – Some programmer dude May 27 '13 at 07:50
  • Actually you should __not__ set pointers to NULL and check against that. This is a very common error/misconception. You should set pointers to an invalid pointer value (and check for that for validation). The reason is that setting pointers to NULL hides some errors. It is e.g. perfectly legal to invoke `delete 0;`. Thus, by setting a pointer to NULL, you have just destroyed one valuable possibility to detect an ownership problem (because it _won't_ crash). And no, it is not safer to write `if(ptr != NULL) delete ptr;` as some books are trying to teach you as "safe delete". – Damon May 27 '13 at 08:15
  • Do you mean using some kind of 0xDEADBEEF address ? – unresolved_external May 28 '13 at 07:50

2 Answers2

3

Major sources of segmentation faults are

  • Uninitialized pointers (or uninitialized variables in general)
  • Out-of-bound access to arrays
  • Poorly coded pointer arithmetics

The main strategies to deal with this include:

  • Always initialize your variables, in particular pointers
  • Avoid naked pointers (prefer smart pointers, such as std::unique_ptr or std::shared_ptr for pointers that own data, and use iterators into standard containers if you want to merely point at stuff)
  • Use standard containers (e.g. std::vector) instead of arrays and pointer arithmetics

As mentioned in the comments, poorly coded concurrency or parallelization can cause segmentation faults (and many other problems), in a similar way as uninitialized variables can, because they may cause the value of a variable to be altered unexpectedly. General strategies to deal with this include:

  • Avoid shared data – prefer messaging / queues for inter-thread communication
  • If you have shared data, and at least one thread writes into those data, use mutexes, std::atomic or similar for protection

However, both may in some cases mean that you loose significant performance benefits. Getting parallel algorithms right is a matter of careful analysis and design.

jogojapan
  • 68,383
  • 11
  • 101
  • 131
2

Concurrency can be the source of lots of issues, in several different ways, and SIGSEV is one of the issues. A beginner might pass a pointer Data* p; to two threads, and before exiting make them execute this code.

if(p){
 delete p->data;
 delete p;
 p = NULL;
}

You just need both threads to see p as non null, be preempted to have a SIGSEV scenario. Using standard containers or smart pointers as @jogojapan pointed out can mitigate this issues.

UmNyobe
  • 22,539
  • 9
  • 61
  • 90