views:

398

answers:

2

Hi

I have this piece of code here:

These are functions used to create and stop a pthread:

void WatchdogController::conscious_process_handler_start() {

    if ( debug ) cout << "WatchdogController: starting conscious process thread" << endl;

    cn_pr_thread_active = true;

    if ( pthread_create( &cn_pr_thread, NULL, conscious_process_handler, this ) < 0 ) {
     cn_pr_thread_active = false;
     throw WatchdogException( "Unable to start new thread" );
    }
}

void WatchdogController::conscious_process_handler_stop() {

    if ( debug ) cout << "WatchdogController: stopping conscious process thread" << endl;

    cn_pr_thread_active = false;

    int *retval;

    pthread_join( cn_pr_thread, ( void ** )&retval );

    if ( *retval < 0 ) {
     delete retval;
     string err = string( "Error returned by conscious_process_handler(): " ) + string( pthread_err );
     throw WatchdogException( err.c_str() );
    }

    delete retval;
}

I use select() in function passed to pthread, and when stopped it returns an error resulting in return value from pthread being negative, but that's not the issue, I'll fix it later - problem is, that when the exception is thrown here:

throw WatchdogException( err.c_str() );

and caught here:

try {
     watchdog_controller->hardware_watchdog_stop();
     watchdog_controller->unconscious_process_handler_stop();
     watchdog_controller->conscious_process_handler_stop();
    }
    catch ( HardwareWatchdogException &e ) {
     cerr << "Error stopping hardware watchdog!" << endl;
     cerr << e.get_reason() << endl;
     string err = string( "Exception thrown by hardware watchdog controller" ) + string( e.get_reason() );
     if ( log ) write_log( err.c_str() );
     delete watchdog_controller;
     return -1;
    }
    catch ( WatchdogException &e ) {
     cerr << "Exception cought when exiting!" << endl;
     cerr << e.get_reason() << endl;
     string err = string( "Exception cought when exiting" ) + string( e.get_reason() );
     if ( log ) write_log( err.c_str() );
     delete watchdog_controller;
     return -1;
    }

I get segmentation fault then trying to access the object at this point:

cerr << e.get_reason() << endl;

What could be the reason?

Reference &e points to something, but it seems as if the address was invalid.

Here's the exception class:

class WatchdogException {

    public:

     /**
      @brief  Default constructor
     */
     WatchdogException() : reason() {
     }

     /**
      @brief  Overloaded constructor - setting the error message
      @param  why   Error message
     */
     WatchdogException( const char *why ) : reason( why ) {
     }

     /**
      @brief  The destructor
     */
     virtual ~WatchdogException() {
     }

     /**
      @brief  A getter for the error message
      @return  Returns a string containing error description
     */
     virtual std::string get_reason() const {
      return reason;
     }

    protected:

     /**
      @var  reason  String containing the error message
     */
     std::string reason;

};
A: 

In WatchDogException's constructor, are you remembering the pointer to the c-string passed in or are you making a copy of it.

If you're simply storing the pointer then when "err" goes out of scope when the exception is thrown the pointer returned by c_str() will be bad, hence your seg fault when you try and use it.

ScaryAardvark
WatchDogException makes an internal copy of the C string, so this is not the issue.
Charles Salvia
+2  A: 

I am guessing that you are not properly allocating memory for retval, or that somehow you are returning an invalid pointer from cn_pr_thread, and that is why you get a segmentation fault when you call pthread_join.

Charles Salvia
I'm passing an uninitialized pointer, but I allocate memory for an integer inside the thread.What do you mean by saying potentially? Is it possible, that the function would go past the throw statement?
zbigh
Can you show where you're allocating memory for retval? As for the double delete, you're correct: it shouldn't get past the throw statement. I wasn't reading it carefully enough.
Charles Salvia
it doesn't matter if you've dynamically allocated the memory for the returned data inside the thread, you need something already allocated to copy it into.
Peeter Joot
int *ret = new int( 0 ); right at the beginning and then later I'm setting the return value right before pthread_exit
zbigh
@Peeter, no, I think we are wrong. Archwimiliuopoczański is doing the correct thing here. Pthread_join copies the address of the value returned by the terminating thread into the retval.
Charles Salvia
@Archwimiliuopoczański, you seem to be doing the correct thing, but I am still leaning towards saying it must be something to do with retval, because you don't get the segfault when you comment out pthread_join.
Charles Salvia
I edited my post, because I am not sure exactly what the issue is here, but I am pretty confident it is something related to retval. Can you recheck the code to make sure you are returning a properly allocated pointer from cn_pr_thread
Charles Salvia
That's interesting - I've run the program through valgrind and discovered a memory leak ( I called delete instead of delete[] on an array ) in function passed to the thread - this seems to fix it - no more segfaults... sorry for the problem, I never thought a memory leak could break the entire thread...
zbigh