Crash when using "time.h"

919 views Asked by At

==FINAL CLASS BENEATH THIS LINE==

It was not an issue with std::ostringstream, I was doing bad things with "time.h" which I did not fully understand. The original question shows up after the class. The final class looks like this:

timestamp.h

#ifndef __TIMESTAMP_H
#define __TIMESTAMP_H

#include <string>
#include "time.h"


class CTimestamp {

    private:
        std::string timestamp;
        time_t rawtime;
        struct tm errorTime;
        struct tm tempTime;
        bool quality;

    public:
        CTimestamp();
        void set(std::string inputTime);
        std::string get();
        std::string get(int modifiedBy);
        bool good();

        void getWeekday();  // Mainly for testing purposes - if this returns
                            // the correct weekday for your modified timestamp,
                            // you probably modified it correctly.
};

#endif

timestamp.cpp

#include "timestamp.h"
#include "time.h"
#include <string>
#include <stdlib.h>
#include <iostream>
#include <sstream>

CTimestamp::CTimestamp(){

    quality = 0;
}

void CTimestamp::set(std::string inputTime){

    quality = 1;

    int year, month, day, hour, minute, second;

    if (19 == inputTime.length()){

        inputTime.replace(10,1," ");
        inputTime.replace(13,1,":");
        inputTime.replace(16,1,":");

        year = atoi(inputTime.substr(0,4).c_str());
        month = atoi(inputTime.substr(5,2).c_str());
        day = atoi(inputTime.substr(8,2).c_str());
        hour = atoi(inputTime.substr(11,2).c_str());
        minute = atoi(inputTime.substr(14,2).c_str());         
        second = atoi(inputTime.substr(17,2).c_str());

        timestamp = inputTime;
    }
    else{
        quality = 0;
    }

    if(quality){
        // Get current time with the "time_t time(struct tm * timeptr)" function from time.h
        time(&rawtime);

        // Change to local time with "struct tm * localtime (const time_t * timer)" function from time.h
        errorTime = *localtime(&rawtime);

        // Change to the time of the timestamp
        errorTime.tm_year = year - 1900;   //Years since 1900
        errorTime.tm_mon  = month - 1;     //Months since january
        errorTime.tm_mday = day;           //Day of the month
        errorTime.tm_hour = hour;      //Hours since midnight
        errorTime.tm_min  = minute;        //minutes since hour
        errorTime.tm_sec  = second;        //Seconds since minute

        // modifies errorTime so overflows in lower units increment higher units then sets tm_wday and tm_yday
        mktime ( &errorTime );
    }
}

void CTimestamp::getWeekday(){

    const char * weekday[] = {"sun", "mon", "tue", "wed", "thu", "fri", "sat"};
    std::cout << weekday[errorTime.tm_wday];
}

std::string CTimestamp::get(){
    std::string returnValue = "Bad Initialization";
    if(quality){
        returnValue = timestamp;
    }
    return returnValue;
}

std::string CTimestamp::get(int modifiedBy){

    std::string returnValue = "Bad Initialization";
    if(quality){

        tempTime = errorTime;
        tempTime.tm_sec = (errorTime.tm_sec+modifiedBy);
        mktime( &tempTime);

        std::string year, month, day, hour, minute, second;

        // This compiler does not support the C++11 std::to_string but there is a workaround with stringstreams
        // http://www.cplusplus.com/articles/D9j2Nwbp/
        year   = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime.tm_year+1900)) )->str();
        month  = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime.tm_mon+1)) )->str();
        day    = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime.tm_mday)) )->str();
        hour   = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime.tm_hour)) )->str();
        minute = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime.tm_min)) )->str();
        second = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime.tm_sec)) )->str();

        if(month.length()  == 1) { month  = "0" + month;  }
        if(day.length()    == 1) { day    = "0" + day;    }
        if(hour.length()   == 1) { hour   = "0" + hour;   }
        if(minute.length() == 1) { minute = "0" + minute; }
        if(second.length() == 1) { second = "0" + second; }

        returnValue = year+"-"+month+"-"+day+" "+hour+":"+minute+":"+second;
    }

    return returnValue;
}

bool CTimestamp::good(){

    return quality;
}

==ORIGINAL QUESTION STARTS HERE BENEATH THIS LINE==

I need some custome timestamp functionality and I am trying to make a class for it. Unfortunately, it crashes my program when I try to call one of the functions and I'm not quite sure why, especially in light of the fact that it DOESN'T crash when I use it in a smaller toy program to test the class.

#ifndef __TIMESTAMP_H
#define __TIMESTAMP_H

#include <string>
#include "time.h"
#include "debug.h"

class CTimestamp {

    private:
        std::string timestamp;
        time_t rawtime;
        struct tm * errorTime;
        struct tm * tempTime;
        bool quality;

    public:
        CTimestamp();
        void set(std::string inputTime);
        std::string get();
        std::string get(int modifiedBy);
        bool good();

        void getWeekday();  // Mainly for testing purposes - if this returns
                            // the correct weekday for your modified timestamp,
                            // you probably modified it correctly.
};

#endif

The problem occurs when I call

std::cout << timeStamp.get(-30);

Specifically, at this point:

year   = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_year+1900)) )->str();

Which is part of the following method:

std::string CTimestamp::get(int modifiedBy){
    if ( 1 < __DEBUG__ ){std::cout << "\nDEBUG " << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ ;}

    std::string returnValue = "Bad Initialization";
    if(quality){

        tempTime->tm_year  = errorTime->tm_year;
        tempTime->tm_mon   = errorTime->tm_mon;
        tempTime->tm_mday  = errorTime->tm_mday;
        tempTime->tm_hour  = errorTime->tm_hour;
        tempTime->tm_min   = errorTime->tm_min;
        tempTime->tm_sec   = errorTime->tm_sec;
        mktime(tempTime);

        tempTime->tm_sec = tempTime->tm_sec + modifiedBy;
        mktime(tempTime);

        std::string year, month, day, hour, minute, second;

        if ( 1 < __DEBUG__ ){std::cout << "\nDEBUG " << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ ;}

        // This compiler does not support the C++11 std::to_string but there is a workaround with stringstreams
        // http://www.cplusplus.com/articles/D9j2Nwbp/
        year   = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_year+1900)) )->str();
        month  = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_mon+1)) )->str();
        day    = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_mday)) )->str();
        hour   = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_hour)) )->str();
        minute = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_min)) )->str();
        second = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_sec)) )->str();

        if ( 1 < __DEBUG__ ){std::cout << "\nDEBUG " << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ ;}

        if(month.length() == 1)
        {
            month = "0" + month;
        }
        if(day.length() == 1)
        {
            day = "0" + day;
        }
        if(hour.length() == 1)
        {
            hour = "0" + hour;
        }
        if(minute.length() == 1)
        {
            minute = "0" + minute;
        }
        if(second.length() == 1)
        {
            second = "0" + second;
        }

        if ( 1 < __DEBUG__ ){std::cout << "\nDEBUG " << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ ;}

        returnValue = year+"-"+month+"-"+day+" "+hour+":"+minute+":"+second;

        if ( 1 < __DEBUG__ ){std::cout << "\nDEBUG " << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ ;}

    }

    if ( 1 < __DEBUG__ ){std::cout << "\nDEBUG " << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ ;}

    return returnValue;
}

EDIT

Ok this weirds me out:

When I call

std::cout << timeStamp.get();

it crashes on the line I indicated.

When I instead go

std::string hey = timeStamp.get();
std::cout << hey;

it crashes on the second __DEBUG__ statement (right after if(quality))

EDIT EDIT

errorTime is initialized here:

void CTimestamp::set(std::string inputTime){

    quality = 1;

    int year, month, day, hour, minute, second;

    if (19 == inputTime.length()){

        inputTime.replace(10,1," ");
        inputTime.replace(13,1,":");
        inputTime.replace(16,1,":");

        year = atoi(inputTime.substr(0,4).c_str());
        month = atoi(inputTime.substr(5,2).c_str());
        day = atoi(inputTime.substr(8,2).c_str());
        hour = atoi(inputTime.substr(11,2).c_str());
        minute = atoi(inputTime.substr(14,2).c_str());         
        second = atoi(inputTime.substr(17,2).c_str());

        timestamp = inputTime;
    }
    else{
        quality = 0;
    }

    if(quality){
        // Get current time with the "time_t time(struct tm * timeptr)" function from time.h
        time(&rawtime);

        // Change to local time
        errorTime = localtime(&rawtime);

        // Change to the time of the timestamp
        errorTime->tm_year = year - 1900;   //Years since 1900
        errorTime->tm_mon  = month - 1;     //Months since january
        errorTime->tm_mday = day;           //Day of the month
        errorTime->tm_hour = hour;          //Hours since midnight
        errorTime->tm_min  = minute;        //minutes since hour
        errorTime->tm_sec  = second;        //Seconds since minute

        // modifies errorTime so overflows in lower units increment higher units then sets tm_wday and tm_yday
        mktime ( errorTime );
    }
}

EDIT EDIT EDIT

I tried getting rid of the fancy pointer work and allow this to take up a few more lines. Unfortunately, it did not seem to work:

    /*
    year   = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_year+1900)) )->str();
    month  = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_mon+1)) )->str();
    day    = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_mday)) )->str();
    hour   = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_hour)) )->str();
    minute = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_min)) )->str();
    second = static_cast<std::ostringstream*>( &(std::ostringstream() << (tempTime->tm_sec)) )->str();
    */

    int timeConvertINT;
    std::ostringstream timeConvertOSS;

    timeConvertINT = (tempTime->tm_year)+1900;
    timeConvertOSS << timeConvertINT;
    year = timeConvertOSS.str();

    timeConvertINT = (tempTime->tm_mon)+1;
    timeConvertOSS << timeConvertINT;
    month = timeConvertOSS.str();

    timeConvertINT = (tempTime->tm_mday);
    timeConvertOSS << timeConvertINT;
    day = timeConvertOSS.str();

    timeConvertINT = (tempTime->tm_hour);
    timeConvertOSS << timeConvertINT;
    hour = timeConvertOSS.str();

    timeConvertINT = (tempTime->tm_min);
    timeConvertOSS << timeConvertINT;
    minute = timeConvertOSS.str();

    timeConvertINT = (tempTime->tm_sec);
    timeConvertOSS << timeConvertINT;
    second = timeConvertOSS.str();

EDIT EDIT EDIT EDIT

Huh. So it seems that ostreamstring is NOT the offender here - it crashes at that exact line even when I comment all OSS functionality out and just hardcode a reply.

This means that in this block:

if(quality){

    if ( 1 < __DEBUG__ ){std::cout << "\nDEBUG " << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ ;}

    tempTime->tm_year  = errorTime->tm_year;
    tempTime->tm_mon   = errorTime->tm_mon;
    tempTime->tm_mday  = errorTime->tm_mday;
    tempTime->tm_hour  = errorTime->tm_hour;
    tempTime->tm_min   = errorTime->tm_min;
    tempTime->tm_sec   = errorTime->tm_sec;
    mktime(tempTime);

    if ( 1 < __DEBUG__ ){std::cout << "\nDEBUG " << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ ;}

    tempTime->tm_sec = tempTime->tm_sec + modifiedBy;
    mktime(tempTime);

    std::string year, month, day, hour, minute, second;

    if ( 1 < __DEBUG__ ){std::cout << "\nDEBUG " << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ ;}

    year = "2013";
    month = "11";
    day = "05";
    hour = "12";
    minute = "00";
    second = "00";

I see the first debug output (And none later) when calling it as

std::string hey = timeStamp.get();
std::cout << hey;

But when I call it as

std::cout << timeStamp.get();

I see the debug output right after

std::string year, month, day, hour, minute, second;
2

There are 2 answers

2
Blastfurnace On BEST ANSWER

Mysterious crashes and pointers go together so check that tempTime and errorTime point to valid objects before you dereference them. The posted code doesn't show where you initialize tempTime so that is where to start looking.

In addition to assigning values to the pointers be sure the object lifetimes are also still valid when you use the pointers. You don't want to save a pointer to a temporary object that has gone out of scope.

3
Sergei Nosov On

The code "seems" legit, but formally - it's actually ill-formed, because you're taking an address of a temporary. &(std::ostringstream() << (tempTime->tm_year+1900)).

You could easily avoid it - simply writing (std::ostringstream() << (tempTime->tm_year+1900)).str(). If it still crashes - try giving std::ostringstream() a name, like

std::ostringstream() oss;
oss << (tempTime->tm_year+1900);
oss.str();

If it doesn't help either - I'm out of ideas for now.