cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 mktime() function has the 2038 year bug - where is source code?

XI
Associate

Hi,

We use an RTC and the POSIX function mktime() to convert a broken-down time into a time in seconds.

Function prototype: time_t mktime(struct tm *tm);

Problem is: this mktime() function has the 2038 year bug (see here https://en.wikipedia.org/wiki/Year_2038_problem for details).

Here is a small test function:

#include <stdio.h>
#include <time.h>
 
struct timeval testTimeval(void)
{
	struct timeval time;
	struct tm t_decomp;
 
	time.tv_sec = -1;
 
	t_decomp.tm_year = 139; //2039
	t_decomp.tm_mon = 0;
	t_decomp.tm_mday = 1;
	t_decomp.tm_hour = 8;
	t_decomp.tm_min = 37;
	t_decomp.tm_sec = 53;
	t_decomp.tm_isdst = -1; 
 
	time.tv_sec = mktime(&t_decomp);
	time.tv_usec = 0;
 
	printf("t_decomp : %d-%d-%d => %llds, sizeof(time.tv_sec) = %d\r\n", t_decomp.tm_year, t_decomp.tm_mon, t_decomp.tm_mday, (long long int)time.tv_sec, sizeof(time.tv_sec));
	}
 
//This fonction prints:
//t_decomp : 139-0-1 => -2117483423s, sizeof(time.tv_sec) = 8
//note that the time returned by mktime() is negative, which should not be the case for the year 2039. Also note that sizeof(time_t) is 8, so the time is stored in a 64 bits variable (not 32 bits), which is fine.
//Which is decoded into 1902-11-26 02:09:37,000 (instead of 2039-01-01)
 
//If I set the year to 2038, everything is OK:
//t_decomp : 138-0-1 => 2145948149s, sizeof(time.tv_sec) = 8
//Note that the time returned is positive this time
//And decoding the time back gives 2038-01-01 08:42:29,000 which is fine

Sum-up: any year above 2038 passed to mktime() function will result in wrong returned value and a year rolling back to 19xx.

Note: the bug is not due to the "time_t" type which is a 64 bit variable for the STM32 (fine for the year 2038), but most likely to a bug into the mktime() function itself which I guess uses 32 bits signed internal types internally. Where can I find the source code of the STM32 toolchain to check my assumptions?

Anyway, I have used an external mktime() function from here, and everything is working fine, so I am quite confident that the bug is inside the STM32 toolchain.

I am using STM32L4A6 with System Workbench (SW4STM32) and gcc version 7.2.1 20170904 (release) [ARM/embedded-7-branch revision 255204] (GNU Tools for Arm Embedded Processors 7-2017-q4-major)

5 REPLIES 5

> Where can I find the source code of the STM32 toolchain to check my assumptions?

I guess you ought to search for the source code of

> (GNU Tools for Arm Embedded Processors 7-2017-q4-major)

https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads

> Also note that sizeof(time_t) is 8

Show.

JW

XI
Associate

Ok, thanks for your help. I have downloaded the source and I can confirm that gcc-arm-none-eabi-7-2017-q4-major-src.tar.bz2 (provided by SW4STM32 v2.7) has the bug.

It is corrected in gcc-arm-none-eabi-9-2019-q4-major-src.tar.bz2 (I don't know if SW4STM32 v2.8 or v2.9 correct this bug though, since I can't find any changelog for System Workbench...)

More info about the bug:

The files for mktime is "src/newlib/newlib/libc/time/mktime.c"

And the faulty line is here (gcc-arm-none-eabi-7-2017-q4-major):

time_t tim = 0;
  long days = 0;
 [...]
  tim += (days * _SEC_IN_DAY);

Problem is: "days" has a type "long int" which is 32 bits wide ; should be "long long int" to prevent counter overflow and 2038 year bug.

Problem now corrected with this code (in gcc-arm-none-eabi-9-2019-q4-major):

tim += (time_t)days * _SEC_IN_DAY;

(note the (time_t) cast)

So it's a newlib bug.

You should then be able to find the moment it was fixed in newlib's changelog or tracer or whatever they use.

Of course that does not tell when did the fix propagate to ARM's bundle and then in turn when does it propagate to AC6's bundle... Maybe ask AC6?

JW

AFrie.13
Associate

Thanks for the info, @AFrie.13​ .

JW