Reputation: 145
I'm asking this question more out of curiosity than actual need, but this has been baffling me for a while. I'd really like to know what's wrong with my code below. BTW don't try to understand the aim of the function - it's just meant to show the problem.
The code below causes a segmentation fault when run on Linux (using gcc), but it works just fine on Windows (using Visual Studio). As far as I know, there's nothing wrong with returning a struct by value, so what am I doing wrong below?
#include <time.h>
#include <stdint.h>
using namespace std;
struct tm testFunc(const uint32_t rawtime) {
struct tm * localTime;
localTime = gmtime ((const time_t*)&rawtime);
struct tm testval = *localTime;
return testval;
}
int main() {
uint32_t now = 1538442104;
testFunc(now);
}
Upvotes: 3
Views: 368
Reputation: 30115
The gmtime
line results in undefined behaviour. localTime = gmtime((const time_t*)&rawtime);
is converting a uint32_t*
to a time_t*
but there is no guarantee the sizes are the same, indeed on many modern platforms time_t
is 64bits.
If that does not crash it, then gmtime
likely gets junk and then returns null, at which point the testval = *localtime
will crash on reading from a null pointer.
Upvotes: 3
Reputation: 155333
time_t
on Linux (at least on my RHEL6 box) is a signed long
, which will be 64 bits in size on a 64 bit build. You're passing the address of an uint32_t
, which means gmtime
is reading four garbage bytes, invoking undefined behavior.
Windows seems to default to a 64 bit time_t
as well, but it has the option to make it use a 32 bit type at the expense of triggering the Y2038 bug eventually. Either way, it might just work on Windows by coincidence (after all, undefined behavior can include "works as expected").
When the value is huge garbage, gmtime
can end up returning NULL
, which will cause a segfault if you attempt to read it.
Upvotes: 3