ctime(3) gives incorrect results

P

Pietro Cerutti

Hi group,

#include <stdio.h>
#include <unistd.h>
#include <time.h>

int main(void)
{
time_t t1, t2;
char *st1, *st2;

t1 = time(NULL);

if(sleep(1)) {
printf("Signal received, exiting\n");
return (1);
}

t2 = time(NULL);

printf("t1 is %lu\n", (unsigned long)t1);
printf("t2 is %lu\n", (unsigned long)t2);

st1 = ctime(&t1);
st2 = ctime(&t2);

printf("st1 is %s", st1);
printf("st2 is %s", st2);

return(0);
}

The code above gives this output:
t1 is 1183506197
t2 is 1183506198
st1 is Wed Jul 4 01:43:18 2007
st2 is Wed Jul 4 01:43:18 2007

How can it happen that two outputs of ctime(3), given two different
inputs (t1 != t2) are the same (st1 == st2) ?

Moreover, on a shell console:

$ date -r 1183506197
Wed Jul 4 01:43:17 CEST 2007
$ date -r 1183506198
Wed Jul 4 01:43:18 CEST 2007

Here date gives a correct result (i.e. the first date is one second
before the second date).

I doubt it has something to do with the compiler grouping the two calls
to time(NULL). If it's the case, how can I avoid it?

Thank you.
 
L

Lew Pitcher

Pietro said:
Hi group,

#include <stdio.h>
#include <unistd.h>
#include <time.h>

int main(void)
{
time_t t1, t2;
char *st1, *st2;

t1 = time(NULL);

if(sleep(1)) {
printf("Signal received, exiting\n");
return (1);
}

t2 = time(NULL);

printf("t1 is %lu\n", (unsigned long)t1);
printf("t2 is %lu\n", (unsigned long)t2);

st1 = ctime(&t1);
st2 = ctime(&t2);

printf("st1 is %s", st1);
printf("st2 is %s", st2);

return(0);
}

The code above gives this output:
t1 is 1183506197
t2 is 1183506198
st1 is Wed Jul 4 01:43:18 2007
st2 is Wed Jul 4 01:43:18 2007

How can it happen that two outputs of ctime(3), given two different
inputs (t1 != t2) are the same (st1 == st2) ?

Well, you get these results because both st1 and st2 point to the same string.

ctime() returns a pointer to a statically allocated character array in which
the date/time string is stored (by asctime(), under the covers). This array is
reused with each call to ctime(), so your second call to ctime() wiped out the
string generated by the first call to ctime().

What you /should/ have done is something like....

printf("t1 is %s\n",ctime(&t1));
printf("t2 is %s\n",ctime(&t2));

If you needed to defer the printing until after both times were collected, you
should strcpy() the results of the first ctime() call to somewhere safe before
calling ctime() the second time.

HTH
--
Lew Pitcher

Master Codewright & JOAT-in-training | Registered Linux User #112576
http://pitcher.digitalfreehold.ca/ | GPG public key available by request
---------- Slackware - Because I know what I'm doing. ------
 
K

Keith Thompson

Pietro Cerutti said:
#include <stdio.h>
#include <unistd.h>
#include <time.h>

int main(void)
{
time_t t1, t2;
char *st1, *st2;

t1 = time(NULL);

if(sleep(1)) {
printf("Signal received, exiting\n");
return (1);
}

t2 = time(NULL);

printf("t1 is %lu\n", (unsigned long)t1);
printf("t2 is %lu\n", (unsigned long)t2);

st1 = ctime(&t1);
st2 = ctime(&t2);

printf("st1 is %s", st1);
printf("st2 is %s", st2);

return(0);
}

The code above gives this output:
t1 is 1183506197
t2 is 1183506198
st1 is Wed Jul 4 01:43:18 2007
st2 is Wed Jul 4 01:43:18 2007
[...]

ctime() returns a pointer to a statically allocated string. It
returns the same char* value each time it's called; the call has the
side effect of modifying the string that that pointer points to.

Your system's documentation for ctime() and asctime() should explain
this. Did you read it?

Try rearranging the calls to ctime, so the result is displayed
immediately after each call:

st1 = ctime(&t1);
printf("st1 is %s", st1);

st2 = ctime(&t2);
printf("st2 is %s", st2);

If you want to save the string for later use, you'll need to copy it
somewhere. (As it happens, the standard guarantees that a 26-byte
array will be sufficient to hold it.)
 
P

Pietro Cerutti

Lew said:
Well, you get these results because both st1 and st2 point to the same string.

ctime() returns a pointer to a statically allocated character array in which
the date/time string is stored (by asctime(), under the covers). This array is
reused with each call to ctime(), so your second call to ctime() wiped out the
string generated by the first call to ctime().

What you /should/ have done is something like....

printf("t1 is %s\n",ctime(&t1));
printf("t2 is %s\n",ctime(&t2));

If you needed to defer the printing until after both times were collected, you
should strcpy() the results of the first ctime() call to somewhere safe before
calling ctime() the second time.

HTH

Uh, thank you!
 
P

Pietro Cerutti

Keith said:
Pietro Cerutti said:
#include <stdio.h>
#include <unistd.h>
#include <time.h>

int main(void)
{
time_t t1, t2;
char *st1, *st2;

t1 = time(NULL);

if(sleep(1)) {
printf("Signal received, exiting\n");
return (1);
}

t2 = time(NULL);

printf("t1 is %lu\n", (unsigned long)t1);
printf("t2 is %lu\n", (unsigned long)t2);

st1 = ctime(&t1);
st2 = ctime(&t2);

printf("st1 is %s", st1);
printf("st2 is %s", st2);

return(0);
}

The code above gives this output:
t1 is 1183506197
t2 is 1183506198
st1 is Wed Jul 4 01:43:18 2007
st2 is Wed Jul 4 01:43:18 2007
[...]

ctime() returns a pointer to a statically allocated string. It
returns the same char* value each time it's called; the call has the
side effect of modifying the string that that pointer points to.

Your system's documentation for ctime() and asctime() should explain
this. Did you read it?

Yep, but it seems I didn't get to the BUGS section, which says:

BUGS
Except for difftime(), mktime(), and the _r() variants of the other
functions, these functions leaves their result in an internal static
object and return a pointer to that object. Subsequent calls to these
function will modify the same object.

I'll fill a bug report if that sentence doesn't belong that section of
the man page.

What do you think about it?
 
K

Keith Thompson

Pietro Cerutti said:
Keith Thompson wrote: [...]
ctime() returns a pointer to a statically allocated string. It
returns the same char* value each time it's called; the call has the
side effect of modifying the string that that pointer points to.

Your system's documentation for ctime() and asctime() should explain
this. Did you read it?

Yep, but it seems I didn't get to the BUGS section, which says:

BUGS
Except for difftime(), mktime(), and the _r() variants of the other
functions, these functions leaves their result in an internal static
object and return a pointer to that object. Subsequent calls to these
function will modify the same object.

I'll fill a bug report if that sentence doesn't belong that section of
the man page.

What do you think about it?

I think that the authors of a man page can put their information
anywhere they like. You might argue that it shouldn't be in the BUGS
section because functions behave correctly as defined by the C
standard, but <OT>traditionally the BUGS section is used for any
potential problems with the thing being documented</OT>.

The function behaves as it's documented to behave, and your system's
documentation told you about the potential problem. Frankly, I don't
think you've got much to complain about.
 
K

Kenny McCormack

Keith Thompson said:
The function behaves as it's documented to behave, and your system's
documentation told you about the potential problem. Frankly, I don't
think you've got much to complain about.

You never do.
 
B

Barry

Keith Thompson said:
Pietro Cerutti said:
Keith Thompson wrote: [...]
ctime() returns a pointer to a statically allocated string. It
returns the same char* value each time it's called; the call has the
side effect of modifying the string that that pointer points to.

Your system's documentation for ctime() and asctime() should explain
this. Did you read it?

Yep, but it seems I didn't get to the BUGS section, which says:

BUGS
Except for difftime(), mktime(), and the _r() variants of the other
functions, these functions leaves their result in an internal static
object and return a pointer to that object. Subsequent calls to these
function will modify the same object.

I'll fill a bug report if that sentence doesn't belong that section of
the man page.

What do you think about it?

I think that the authors of a man page can put their information
anywhere they like. You might argue that it shouldn't be in the BUGS
section because functions behave correctly as defined by the C
standard, but <OT>traditionally the BUGS section is used for any
potential problems with the thing being documented</OT>.

The function behaves as it's documented to behave, and your system's
documentation told you about the potential problem. Frankly, I don't
think you've got much to complain about.

<OT> I would disagree with you here. The documentation should
describe how the functions work and possibly qualify them as
defined by C.

The BUGS section is usually regulated to implementation defects or
simplifications. </OT>
 
M

Martin Ambuhl

Pietro said:
Hi group,

#include <stdio.h>
#include <unistd.h>
#include <time.h>

int main(void)
{
time_t t1, t2;
char *st1, *st2;

t1 = time(NULL);

if(sleep(1)) {
printf("Signal received, exiting\n");
return (1);
}

t2 = time(NULL);

printf("t1 is %lu\n", (unsigned long)t1);
printf("t2 is %lu\n", (unsigned long)t2);

st1 = ctime(&t1);
st2 = ctime(&t2);

printf("st1 is %s", st1);
printf("st2 is %s", st2);

return(0);
}

The code above gives this output:
t1 is 1183506197
t2 is 1183506198
st1 is Wed Jul 4 01:43:18 2007
st2 is Wed Jul 4 01:43:18 2007

How can it happen that two outputs of ctime(3), given two different
inputs (t1 != t2) are the same (st1 == st2) ?

/* mha: off-topic non-standard functionality retained here, although
flagged. The problem does not lie with those non-standard
features, and I was too lazy to create a new example. */

#include <stdio.h>
#include <unistd.h> /* mha: not a standard C header */
#include <time.h>
#include <stdlib.h> /* mha: added so the error return
returns a portably defined value */
#include <string.h> /* mha: added for strcpy */

int main(void)
{
time_t t1, t2;
char st1[26], st2[26]; /* mha: replaced pointers with arrays */

t1 = time(NULL);

if (sleep(1) /* mha: not a standard C function */ ) {
printf("Signal received, exiting\n");
return EXIT_FAILURE; /* mha: replaced the (1) return value */
}

t2 = time(NULL);

printf("t1 is %lu\n", (unsigned long) t1);
printf("t2 is %lu\n", (unsigned long) t2);

/* mha: below were two assignments to two pointers of a pointers to
the same static array. I have fixed that. These two lines are not
actually needed, since the calls to ctime() could be done in
the arguments to printf. */
strcpy(st1, ctime(&t1));
strcpy(st2, ctime(&t2));

printf("st1 is %s", st1);
printf("st2 is %s", st2);

return 0;
}
 
K

Keith Thompson

Barry said:
<OT> I would disagree with you here. The documentation should
describe how the functions work and possibly qualify them as
defined by C.

The BUGS section is usually regulated to implementation defects or
simplifications. </OT>

I don't strongly disagree. But in any case, if there's a BUGS
section, then anyone trying to use the function should certainly read
it first.
 
P

Pietro Cerutti

Keith said:
Pietro Cerutti said:
Keith Thompson wrote: [...]
ctime() returns a pointer to a statically allocated string. It
returns the same char* value each time it's called; the call has the
side effect of modifying the string that that pointer points to.

Your system's documentation for ctime() and asctime() should explain
this. Did you read it?
Yep, but it seems I didn't get to the BUGS section, which says:

BUGS
Except for difftime(), mktime(), and the _r() variants of the other
functions, these functions leaves their result in an internal static
object and return a pointer to that object. Subsequent calls to these
function will modify the same object.

I'll fill a bug report if that sentence doesn't belong that section of
the man page.

What do you think about it?

I think that the authors of a man page can put their information
anywhere they like. You might argue that it shouldn't be in the BUGS
section because functions behave correctly as defined by the C
standard, but <OT>traditionally the BUGS section is used for any
potential problems with the thing being documented</OT>.

The function behaves as it's documented to behave, and your system's
documentation told you about the potential problem. Frankly, I don't
think you've got much to complain about.

I wasn't complaining at all. Instead, I was asking myself whether it
would have been an improvement for the man page to provide a NOTE
section (as Linux's does) where to put the information.
 
A

Army1987

Pietro Cerutti said:
Hi group,

#include <stdio.h>
#include <unistd.h>
#include <time.h>

int main(void)
{
time_t t1, t2;
char *st1, *st2;

t1 = time(NULL);

if(sleep(1)) {
printf("Signal received, exiting\n");
return (1);
}

t2 = time(NULL);

printf("t1 is %lu\n", (unsigned long)t1);
printf("t2 is %lu\n", (unsigned long)t2);

st1 = ctime(&t1);
st2 = ctime(&t2);

7.23.3 Time conversion functions
1 Except for the strftime function, these functions each return a pointer to one of two
types of static objects: a broken-down time structure or an array of char. Execution of
any of the functions that return a pointer to one of these object types may overwrite the
information in any object of the same type pointed to by the value returned from any
previous call to any of them.

Here the second call of ctime overwrites the result of the first.
Try declaring st1 and st2 as arrays of chars, and to use strcpy().
char st1[26];
char st2[26];
/* ... */
strcpy(st1, ctime(&t1));
strcpy(st2, ctime(&t2));
printf("st1 is %s", st1);
printf("st2 is %s", st2);

return(0);
}

The code above gives this output:
t1 is 1183506197
t2 is 1183506198
st1 is Wed Jul 4 01:43:18 2007
st2 is Wed Jul 4 01:43:18 2007

How can it happen that two outputs of ctime(3), given two different
inputs (t1 != t2) are the same (st1 == st2) ?

Moreover, on a shell console:

$ date -r 1183506197
Wed Jul 4 01:43:17 CEST 2007
$ date -r 1183506198
Wed Jul 4 01:43:18 CEST 2007

Here date gives a correct result (i.e. the first date is one second
before the second date).

I doubt it has something to do with the compiler grouping the two calls
to time(NULL). If it's the case, how can I avoid it?

If this were the case, you could declare t1 and t2 as volatile. But
it isn't, as t1 < t2.
 
A

Army1987

Pietro Cerutti said:
Keith said:
Pietro Cerutti said:
#include <stdio.h>
#include <unistd.h>
#include <time.h>

int main(void)
{
time_t t1, t2;
char *st1, *st2;

t1 = time(NULL);

if(sleep(1)) {
printf("Signal received, exiting\n");
return (1);
}

t2 = time(NULL);

printf("t1 is %lu\n", (unsigned long)t1);
printf("t2 is %lu\n", (unsigned long)t2);

st1 = ctime(&t1);
st2 = ctime(&t2);

printf("st1 is %s", st1);
printf("st2 is %s", st2);

return(0);
}

The code above gives this output:
t1 is 1183506197
t2 is 1183506198
st1 is Wed Jul 4 01:43:18 2007
st2 is Wed Jul 4 01:43:18 2007
[...]

ctime() returns a pointer to a statically allocated string. It
returns the same char* value each time it's called; the call has the
side effect of modifying the string that that pointer points to.

Your system's documentation for ctime() and asctime() should explain
this. Did you read it?

Yep, but it seems I didn't get to the BUGS section, which says:

BUGS
Except for difftime(), mktime(), and the _r() variants of the other
functions, these functions leaves their result in an internal static
object and return a pointer to that object. Subsequent calls to these
function will modify the same object.

I'll fill a bug report if that sentence doesn't belong that section of
the man page.

What do you think about it?
The C standards allows them to do so, so, unless they state
otherwise, there is no bug.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,810
Latest member
Kassie0918

Latest Threads

Top