Skip to content

Commit 941ad2f

Browse files
Fix Year 2038 Problem in Sntp_ConvertToUnixTime (#104)
* Fix year 2038 problem * Fix bound checking test and remove the case for SntpErrorTimeNotSupported * Fix CBMC failure * Add underflow check * Fix formatting * Fix CI issue with python version * Fix CI issue with python version * Fix coverage tests to run with respect to Ubuntu 24.04 * Fix CI check for lcov V2.3.1 * Fix CI check for lcov V2.3.1 * Fix CI check for lcov V2.3.1 * Add ruby installation for coverage * Fix coverage fail * Fix CI check * Fix CI check * Fix lcov: ERROR * Add comments * Address review comments * Fix doxygen build * Address review comments
1 parent 55b42ff commit 941ad2f

File tree

10 files changed

+64
-67
lines changed

10 files changed

+64
-67
lines changed

.github/workflows/ci.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ jobs:
7979

8080
- name: Build
8181
run: |
82-
sudo apt-get install -y lcov sed
8382
# Build with logging enabled.
83+
sudo apt-get install -y lcov
8484
cmake -S test -B build/ \
8585
-G "Unix Makefiles" \
8686
-DCMAKE_BUILD_TYPE=Debug \
@@ -97,9 +97,9 @@ jobs:
9797
- name: Run Coverage
9898
run: |
9999
make -C build/ coverage
100-
declare -a EXCLUDE=("\*test\*" "\*CMakeCCompilerId\*" "\*mocks\*")
101-
echo ${EXCLUDE[@]} | xargs lcov --rc lcov_branch_coverage=1 -r build/coverage.info -o build/coverage.info
102-
lcov --rc lcov_branch_coverage=1 --list build/coverage.info
100+
declare -a EXCLUDE=("\*test\*" "\*CMakeCCompilerId.c")
101+
echo ${EXCLUDE[@]} | xargs lcov --rc branch_coverage=1 --ignore-errors empty --ignore-errors source -r build/coverage.info -o build/coverage.info
102+
lcov --rc branch_coverage=1 --ignore-errors empty --ignore-errors source --list build/coverage.info
103103
104104
- name: Check Coverage
105105
uses: FreeRTOS/CI-CD-Github-Actions/coverage-cop@main
@@ -198,7 +198,7 @@ jobs:
198198
- name: Install Python3
199199
uses: actions/setup-python@v3
200200
with:
201-
python-version: "3.7.x"
201+
python-version: "3.8"
202202
- name: Measure sizes
203203
uses: FreeRTOS/CI-CD-Github-Actions/memory_statistics@main
204204
with:

docs/doxygen/code_examples/example_sntp_client_posix.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ static void sntpClient_SetTime( const SntpServerInfo_t * pTimeServer,
139139
SntpLeapSecondInfo_t leapSecondInfo )
140140
{
141141
/* @[code_example_sntp_converttounixtime] */
142-
uint32_t unixSecs;
142+
UnixTime_t unixSecs;
143143
uint32_t unixMs;
144144
SntpStatus_t status = Sntp_ConvertToUnixTime( pServerTime, &unixSecs, &unixMs );
145145

docs/doxygen/include/size_table.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<tr>
1111
<td>core_sntp_client.c</td>
1212
<td><center>1.7K</center></td>
13-
<td><center>1.4K</center></td>
13+
<td><center>1.3K</center></td>
1414
</tr>
1515
<tr>
1616
<td>core_sntp_serializer.c</td>
@@ -20,6 +20,6 @@
2020
<tr>
2121
<td><b>Total estimates</b></td>
2222
<td><b><center>2.7K</center></b></td>
23-
<td><b><center>2.2K</center></b></td>
23+
<td><b><center>2.1K</center></b></td>
2424
</tr>
2525
</table>

source/core_sntp_client.c

-4
Original file line numberDiff line numberDiff line change
@@ -959,10 +959,6 @@ const char * Sntp_StatusToStr( SntpStatus_t status )
959959
pString = "SntpZeroPollInterval";
960960
break;
961961

962-
case SntpErrorTimeNotSupported:
963-
pString = "SntpErrorTimeNotSupported";
964-
break;
965-
966962
case SntpErrorDnsFailure:
967963
pString = "SntpErrorDnsFailure";
968964
break;

source/core_sntp_serializer.c

+5-11
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ SntpStatus_t Sntp_CalculatePollInterval( uint16_t clockFreqTolerance,
812812
}
813813

814814
SntpStatus_t Sntp_ConvertToUnixTime( const SntpTimestamp_t * pSntpTime,
815-
uint32_t * pUnixTimeSecs,
815+
UnixTime_t * pUnixTimeSecs,
816816
uint32_t * pUnixTimeMicrosecs )
817817
{
818818
SntpStatus_t status = SntpSuccess;
@@ -821,13 +821,6 @@ SntpStatus_t Sntp_ConvertToUnixTime( const SntpTimestamp_t * pSntpTime,
821821
{
822822
status = SntpErrorBadParameter;
823823
}
824-
/* Check if passed time does not lie in the [UNIX epoch in 1970, UNIX time overflow in 2038] time range. */
825-
else if( ( pSntpTime->seconds > SNTP_TIME_AT_LARGEST_UNIX_TIME_SECS ) &&
826-
( pSntpTime->seconds < SNTP_TIME_AT_UNIX_EPOCH_SECS ) )
827-
{
828-
/* The SNTP timestamp is outside the supported time range for conversion. */
829-
status = SntpErrorTimeNotSupported;
830-
}
831824
else
832825
{
833826
/* Handle case when timestamp represents date in SNTP era 1
@@ -839,12 +832,13 @@ SntpStatus_t Sntp_ConvertToUnixTime( const SntpTimestamp_t * pSntpTime,
839832
* +
840833
* Sntp Time since Era 1 Epoch
841834
*/
842-
*pUnixTimeSecs = UNIX_TIME_SECS_AT_SNTP_ERA_1_SMALLEST_TIME + pSntpTime->seconds;
835+
*pUnixTimeSecs = ( UnixTime_t ) ( UNIX_TIME_SECS_AT_SNTP_ERA_1_SMALLEST_TIME + ( UnixTime_t ) ( pSntpTime->seconds ) );
843836
}
837+
844838
/* Handle case when SNTP timestamp is in SNTP era 1 time range. */
845-
else
839+
if( pSntpTime->seconds >= SNTP_TIME_AT_UNIX_EPOCH_SECS )
846840
{
847-
*pUnixTimeSecs = pSntpTime->seconds - SNTP_TIME_AT_UNIX_EPOCH_SECS;
841+
*pUnixTimeSecs = ( UnixTime_t ) ( ( UnixTime_t ) ( pSntpTime->seconds ) - SNTP_TIME_AT_UNIX_EPOCH_SECS );
848842
}
849843

850844
/* Convert SNTP fractions to microseconds for UNIX time. */

source/include/core_sntp_serializer.h

+27-19
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@
4343
#endif
4444
/* *INDENT-ON* */
4545

46+
/**
47+
* @brief Type representing seconds since Unix epoch (January 1, 1970 UTC).
48+
*
49+
* The width of this type depends on the configuration macro USE_LEGACY_TIME_API:
50+
* - If USE_LEGACY_TIME_API is defined, a 32-bit unsigned integer is used.
51+
* This limits date representation to the year 2038 (Y2038 limitation).
52+
* - Otherwise, a 64-bit unsigned integer is used for Y2038 compliance.
53+
*/
54+
#ifdef USE_LEGACY_TIME_API
55+
typedef uint32_t UnixTime_t; /**< 32-bit Unix time for legacy systems. */
56+
#else
57+
typedef uint64_t UnixTime_t; /**< 64-bit Unix time for Y2038 compliance. */
58+
#endif
59+
4660
/**
4761
* @ingroup sntp_constants
4862
* @brief The base packet size of request and response of the (S)NTP protocol.
@@ -189,12 +203,6 @@ typedef enum SntpStatus
189203
*/
190204
SntpZeroPollInterval,
191205

192-
/**
193-
* @brief SNTP timestamp cannot be converted to UNIX time as time does not lie
194-
* in time range supported by Sntp_ConvertToUnixTime.
195-
*/
196-
SntpErrorTimeNotSupported,
197-
198206
/**
199207
* @brief The user-defined DNS resolution interface, @ref SntpResolveDns_t, failed to resolve
200208
* address for a time server. This status is returned by the @ref Sntp_SendTimeRequest API.
@@ -496,17 +504,18 @@ SntpStatus_t Sntp_CalculatePollInterval( uint16_t clockFreqTolerance,
496504
* @brief Utility to convert SNTP timestamp (that uses 1st Jan 1900 as the epoch) to
497505
* UNIX timestamp (that uses 1st Jan 1970 as the epoch).
498506
*
499-
* @note This function can ONLY handle conversions of SNTP timestamps that lie in the
500-
* range from 1st Jan 1970 0h 0m 0s, the UNIX epoch time, to 19th Jan 2038 3h 14m 7s,
501-
* the maximum UNIX time that can be represented in a signed 32 bit integer. (The
502-
* limitation is to support systems that use signed 32-bit integer to represent the
503-
* seconds part of the UNIX time.)
507+
* @note This function converts SNTP timestamps to UNIX time supporting both 32-bit and
508+
* 64-bit representations based on the configuration macro USE_LEGACY_TIME_API.
509+
*
510+
* - If USE_LEGACY_TIME_API is defined, the conversion is limited to the date range
511+
* from 1st Jan 1970 0h 0m 0s (UNIX epoch) to 19th Jan 2038 3h 14m 7s, due to the
512+
* 32-bit width limitation.
504513
*
505-
* @note This function supports overflow of the SNTP timestamp (from the 7 Feb 2036
506-
* 6h 28m 16s time, i.e. SNTP era 1) by treating the timestamps with seconds part
507-
* in the range [0, 61,505,152] seconds where the upper limit represents the UNIX
508-
* overflow time (i.e. 19 Jan 2038 3h 14m 7s) for systems that use signed 32-bit
509-
* integer to represent time.
514+
* - If USE_LEGACY_TIME_API is not defined, 64-bit UNIX time representation is used,
515+
* allowing conversion of SNTP timestamps beyond the year 2038 (Y2038 problem mitigated).
516+
*
517+
* @note The function also correctly handles SNTP era overflow (from 7 Feb 2036 6h 28m 16s,
518+
* i.e., SNTP era 1) to ensure accurate conversion across SNTP eras.
510519
*
511520
* @param[in] pSntpTime The SNTP timestamp to convert to UNIX time.
512521
* @param[out] pUnixTimeSecs This will be filled with the seconds part of the
@@ -517,15 +526,14 @@ SntpStatus_t Sntp_CalculatePollInterval( uint16_t clockFreqTolerance,
517526
* @return Returns one of the following:
518527
* - #SntpSuccess if conversion to UNIX time is successful
519528
* - #SntpErrorBadParameter if any of the passed parameters are NULL.
520-
* - #SntpErrorTimeNotSupported if the passed SNTP time does not lie in the
521-
* supported time range.
522529
*/
523530
/* @[define_sntp_converttounixtime] */
524531
SntpStatus_t Sntp_ConvertToUnixTime( const SntpTimestamp_t * pSntpTime,
525-
uint32_t * pUnixTimeSecs,
532+
UnixTime_t * pUnixTimeSecs,
526533
uint32_t * pUnixTimeMicrosecs );
527534
/* @[define_sntp_converttounixtime] */
528535

536+
529537
/* *INDENT-OFF* */
530538
#ifdef __cplusplus
531539
}

test/cbmc/proofs/Sntp_ConvertToUnixTime/Sntp_ConvertToUnixTime_harness.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@
3232
void harness()
3333
{
3434
SntpTimestamp_t * pSntpTime;
35-
uint32_t * pUnixTimeSecs;
35+
UnixTime_t * pUnixTimeSecs;
3636
uint32_t * pUnixTimeMicrosecs;
3737
SntpStatus_t sntpStatus;
3838

3939
pSntpTime = malloc( sizeof( SntpTimestamp_t ) );
40-
pUnixTimeSecs = malloc( sizeof( uint32_t ) );
40+
pUnixTimeSecs = malloc( sizeof( UnixTime_t ) );
4141
pUnixTimeMicrosecs = malloc( sizeof( uint32_t ) );
4242

4343
sntpStatus = Sntp_ConvertToUnixTime( pSntpTime, pUnixTimeSecs, pUnixTimeMicrosecs );
4444

45-
__CPROVER_assert( ( sntpStatus == SntpErrorBadParameter || sntpStatus == SntpErrorTimeNotSupported || sntpStatus == SntpSuccess ), "The return value is not a valid SNTP Status" );
45+
__CPROVER_assert( ( sntpStatus == SntpErrorBadParameter || sntpStatus == SntpSuccess ), "The return value is not a valid SNTP Status" );
4646
}

test/unit-test/core_sntp_client_utest.c

-1
Original file line numberDiff line numberDiff line change
@@ -1374,7 +1374,6 @@ void test_StatusToStr( void )
13741374
TEST_ASSERT_EQUAL_STRING( "SntpErrorBufferTooSmall", Sntp_StatusToStr( SntpErrorBufferTooSmall ) );
13751375
TEST_ASSERT_EQUAL_STRING( "SntpInvalidResponse", Sntp_StatusToStr( SntpInvalidResponse ) );
13761376
TEST_ASSERT_EQUAL_STRING( "SntpZeroPollInterval", Sntp_StatusToStr( SntpZeroPollInterval ) );
1377-
TEST_ASSERT_EQUAL_STRING( "SntpErrorTimeNotSupported", Sntp_StatusToStr( SntpErrorTimeNotSupported ) );
13781377
TEST_ASSERT_EQUAL_STRING( "SntpErrorDnsFailure", Sntp_StatusToStr( SntpErrorDnsFailure ) );
13791378
TEST_ASSERT_EQUAL_STRING( "SntpErrorNetworkFailure", Sntp_StatusToStr( SntpErrorNetworkFailure ) );
13801379
TEST_ASSERT_EQUAL_STRING( "SntpServerNotAuthenticated", Sntp_StatusToStr( SntpServerNotAuthenticated ) );

test/unit-test/core_sntp_serializer_utest.c

+5-17
Original file line numberDiff line numberDiff line change
@@ -877,32 +877,20 @@ void test_ConvertToUnixTime_InvalidParams( void )
877877

878878
/* Use same memory for UNIX seconds and microseconds as we are not
879879
* testing those values. */
880-
uint32_t unixTime;
880+
UnixTime_t unixTime;
881+
uint32_t unixTimeMs;
881882

882883
/* Test with NULL SNTP time. */
883884
TEST_ASSERT_EQUAL( SntpErrorBadParameter, Sntp_ConvertToUnixTime( NULL,
884885
&unixTime,
885-
&unixTime ) );
886+
&unixTimeMs ) );
886887
/* Test with NULL output parameters. */
887888
TEST_ASSERT_EQUAL( SntpErrorBadParameter, Sntp_ConvertToUnixTime( &sntpTime,
888889
NULL,
889-
&unixTime ) );
890+
&unixTimeMs ) );
890891
TEST_ASSERT_EQUAL( SntpErrorBadParameter, Sntp_ConvertToUnixTime( &sntpTime,
891892
&unixTime,
892893
NULL ) );
893-
894-
/* Test with time before UNIX epoch or 1st Jan 1970 .*/
895-
sntpTime.seconds = SNTP_TIME_AT_UNIX_EPOCH_SECS - 5;
896-
TEST_ASSERT_EQUAL( SntpErrorTimeNotSupported, Sntp_ConvertToUnixTime( &sntpTime,
897-
&unixTime,
898-
&unixTime ) );
899-
900-
/* Test with timestamp that after largest UNIX time for signed 32-bit integer systems
901-
* (i.e. after 18 Jan 2036 3:14:07) */
902-
sntpTime.seconds = SNTP_TIME_AT_LARGEST_UNIX_TIME_SECS + 5;
903-
TEST_ASSERT_EQUAL( SntpErrorTimeNotSupported, Sntp_ConvertToUnixTime( &sntpTime,
904-
&unixTime,
905-
&unixTime ) );
906894
}
907895

908896
/**
@@ -912,7 +900,7 @@ void test_ConvertToUnixTime_InvalidParams( void )
912900
void test_ConvertToUnixTime_Nominal( void )
913901
{
914902
SntpTimestamp_t sntpTime = TEST_TIMESTAMP;
915-
uint32_t unixTimeSecs;
903+
UnixTime_t unixTimeSecs;
916904
uint32_t unixTimeMs;
917905

918906
#define TEST_SNTP_TO_UNIX_CONVERSION( sntpTimeSecs, sntpTimeFracs, \

tools/cmock/coverage.cmake

+16-4
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ execute_process( COMMAND lcov --directory ${CMAKE_BINARY_DIR}
1414
--base-directory ${CMAKE_BINARY_DIR}
1515
--initial
1616
--capture
17-
--rc lcov_branch_coverage=1
17+
--rc branch_coverage=1
18+
--ignore-errors empty
19+
--ignore-errors source
1820
--rc genhtml_branch_coverage=1
1921
--output-file=${CMAKE_BINARY_DIR}/base_coverage.info
22+
--quiet
2023
)
2124
file(GLOB files "${CMAKE_BINARY_DIR}/bin/tests/*")
2225

@@ -45,11 +48,14 @@ execute_process(COMMAND ruby
4548
# capture data after running the tests
4649
execute_process(
4750
COMMAND lcov --capture
48-
--rc lcov_branch_coverage=1
51+
--rc branch_coverage=1
52+
--ignore-errors empty
53+
--ignore-errors source
4954
--rc genhtml_branch_coverage=1
5055
--base-directory ${CMAKE_BINARY_DIR}
5156
--directory ${CMAKE_BINARY_DIR}
5257
--output-file ${CMAKE_BINARY_DIR}/second_coverage.info
58+
--quiet
5359
)
5460

5561
# combile baseline results (zeros) with the one after running the tests
@@ -60,11 +66,17 @@ execute_process(
6066
--add-tracefile ${CMAKE_BINARY_DIR}/second_coverage.info
6167
--output-file ${CMAKE_BINARY_DIR}/coverage.info
6268
--no-external
63-
--rc lcov_branch_coverage=1
69+
--rc branch_coverage=1
70+
--ignore-errors empty
71+
--ignore-errors source
72+
--quiet
6473
)
6574
execute_process(
66-
COMMAND genhtml --rc lcov_branch_coverage=1
75+
COMMAND genhtml --rc branch_coverage=1
76+
--ignore-errors empty
77+
--ignore-errors source
6778
--branch-coverage
6879
--output-directory ${CMAKE_BINARY_DIR}/coverage
6980
${CMAKE_BINARY_DIR}/coverage.info
81+
--quiet
7082
)

0 commit comments

Comments
 (0)