Mod'ing struct tm causes segmentation fault on RHEL 5.4

Josh Miller joshua at itsecureadmin.com
Tue Jul 6 21:37:50 UTC 2010


On 07/06/2010 09:42 AM, Tim P. Starrin wrote:
> They're all 64 bit systems.
>
> I already gdb'ed it. The segfault occurs in the following location when
> I mod date->tm_year.
>
> (gdb) run
> Starting program: /home/noid/fault
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x000000000040054f in main () at fault.c:15
> 15 date->tm_year %= 100;
>
> Did you compile the program with "-DBUG"?

Hi Tim,

I must admit, I'm in a little over my head here.

I was able to reproduce this issue when using a 64 bit system.  I 
believe the issue has to do with performing a mod on a signed int value. 
  Are all of the systems that you run this on 64 bit?

When I compile with debugging symbols enabled and run with gdb, it 
doesn't segfault on me but I do get a negative year value:

$ gcc -g -DBUG -o fault fault.c

Temporary breakpoint 1, main () at fault.c:10
10       date_as_int = time ((time_t *) NULL);
(gdb) step
11       date = localtime ((time_t *) &date_as_int);
(gdb)
14       date->tm_year %= 100;
(gdb)
20       printf ("%02d/%02d/%02d %02d:%02d:%02d\n",
(gdb)
-4/08/21 14:29:20
23      }
(gdb)
0x000000363f41d974 in __libc_start_main () from /lib64/libc.so.6
(gdb)
Single stepping until exit from function __libc_start_main,
which has no line number information.

Program exited with code 022.

When running under valgrind, I get an invalid memory read:

$ valgrind -v ./fault
...
==19572== Conditional jump or move depends on uninitialised value(s)
==19572==    at 0x363F48A754: __offtime (in /lib64/libc-2.5.so)
==19572==    by 0x363F48C50D: __tz_convert (in /lib64/libc-2.5.so)
==19572==    by 0x400546: main (fault.c:11)
==19572==
==19572== Invalid read of size 4
==19572==    at 0x40054F: main (fault.c:14)
==19572==  Address 0x14 is not stack'd, malloc'd or (recently) free'd
==19572==
...

I did a little bit of research on this and found the following to work 
properly:

#include <stdio.h>
#include <time.h>
#include <sys/time.h>

main ()
{
   time_t tim=time(NULL) ;
   struct tm *date=localtime(&tim) ;

#ifdef BUG
  date->tm_year %= 100;
#else
  while (date->tm_year >= 100)
    date->tm_year -= 100;
#endif

  printf ("%02d/%02d/%02d %02d:%02d:%02d\n",
      date->tm_year, date->tm_mon+1, date->tm_mday,
      date->tm_hour, date->tm_min, date->tm_sec);
}

(re:  http://rabbit.eng.miami.edu/info/functions/time.html#localtime)

-- 
Josh Miller, RHCE/VCP
Seattle, WA
Linux Solutions Provider
Website:  http://itsecureadmin.com/




More information about the redhat-list mailing list