@@ -8,6 +8,8 @@ fn main() {
88 test_localtime_r_gmt ( ) ;
99 test_localtime_r_pst ( ) ;
1010 test_localtime_r_epoch ( ) ;
11+ test_localtime_r_verify_string_deduplication ( ) ;
12+ test_localtime_r_multiple_calls_deduplication ( )
1113 // Architecture-specific tests.
1214 #[ cfg( target_pointer_width = "32" ) ]
1315 test_localtime_r_future_32b ( ) ;
@@ -125,7 +127,7 @@ fn test_localtime_r_gmt() {
125127fn test_localtime_r_pst ( ) {
126128 let key = "TZ" ;
127129 env:: set_var ( key, "PST8PDT" ) ;
128- const TIME_SINCE_EPOCH : libc:: time_t = 1712475836 ; // 2024-04-07 07:43:56 GMT
130+ const TIME_SINCE_EPOCH : libc:: time_t = 1712475836 ; // 2024-04-07 07:43:56 GMT
129131 let custom_time_ptr = & TIME_SINCE_EPOCH ;
130132 let mut tm = create_empty_tm ( ) ;
131133
@@ -276,3 +278,100 @@ fn test_localtime_r_future_32b() {
276278 assert ! ( ptr:: eq( res, & mut tm) ) ;
277279 env:: remove_var ( key) ;
278280}
281+
282+ fn test_localtime_r_verify_string_deduplication ( ) {
283+ let key = "TZ" ;
284+ env:: set_var ( key, "PST8PDT" ) ;
285+
286+ // Two timestamps that are in the same timezone (PST/PDT).
287+ const TIME_SINCE_EPOCH_TZ_CONST1 : libc:: time_t = 1712475836 ; // 2024-04-07 07:43:56 GMT
288+ const TIME_SINCE_EPOCH_TZ_CONST2 : libc:: time_t = 1712575836 ; // 2024-04-08 11:23:56 GMT
289+ const TIME_SINCE_EPOCH_TZ_CONST3 : libc:: time_t = 1712675836 ; // 2024-04-09 11:23:56 GMT
290+
291+ let mut tm1 = create_empty_tm ( ) ;
292+ let mut tm2 = create_empty_tm ( ) ;
293+ let mut tm3 = create_empty_tm ( ) ;
294+
295+ unsafe {
296+ let res1 = libc:: localtime_r ( & TIME_SINCE_EPOCH_TZ_CONST1 , & mut tm1) ;
297+ let res2 = libc:: localtime_r ( & TIME_SINCE_EPOCH_TZ_CONST2 , & mut tm2) ;
298+ let res3 = libc:: localtime_r ( & TIME_SINCE_EPOCH_TZ_CONST3 , & mut tm3) ;
299+
300+ assert ! ( res1. is_null( ) == false , "localtime_r failed for first timestamp" ) ;
301+ assert ! ( res2. is_null( ) == false , "localtime_r failed for second timestamp" ) ;
302+ assert ! ( res3. is_null( ) == false , "localtime_r failed for third timestamp" ) ;
303+
304+ #[ cfg( any(
305+ target_os = "linux" ,
306+ target_os = "macos" ,
307+ target_os = "freebsd" ,
308+ target_os = "android"
309+ ) ) ]
310+ {
311+ let tm_zone1 = std:: ffi:: CStr :: from_ptr ( tm1. tm_zone ) ;
312+ let tm_zone2 = std:: ffi:: CStr :: from_ptr ( tm2. tm_zone ) ;
313+
314+ println ! ( "tz res1 :: {:#?}" , tm1. tm_zone) ;
315+ println ! ( "tz res2 :: {:#?}" , tm2. tm_zone) ;
316+ println ! ( "tz res3 :: {:#?}" , tm3. tm_zone) ;
317+
318+ assert_eq ! (
319+ tm_zone1, tm_zone2,
320+ "tm_zone strings are not equal, indicating different values."
321+ ) ;
322+
323+ assert_eq ! (
324+ tm1. tm_zone, tm2. tm_zone,
325+ "tm_zone pointers are not equal, string deduplication is not happening."
326+ ) ;
327+ }
328+ }
329+ }
330+
331+ fn test_localtime_r_multiple_calls_deduplication ( ) {
332+ let key = "TZ" ;
333+ env:: set_var ( key, "PST8PDT" ) ;
334+
335+ const TIME_SINCE_EPOCH_BASE : libc:: time_t = 1712475836 ; // Base timestamp: 2024-04-07 07:43:56 GMT
336+ const NUM_CALLS : usize = 50 ;
337+
338+ let mut tm_array: Vec < libc:: tm > = vec ! [ create_empty_tm( ) ; NUM_CALLS ] ;
339+ let mut unique_pointers = std:: collections:: HashSet :: new ( ) ;
340+
341+ unsafe {
342+ for i in 0 ..NUM_CALLS {
343+ let timestamp = TIME_SINCE_EPOCH_BASE + ( i as libc:: time_t * 3600 ) ; // Increment by 1 hour for each call
344+ let tm_ptr = libc:: localtime_r ( & timestamp, & mut tm_array[ i] ) ;
345+
346+ assert ! ( !tm_ptr. is_null( ) , "localtime_r failed for timestamp {timestamp}" ) ;
347+
348+ #[ cfg( any(
349+ target_os = "linux" ,
350+ target_os = "macos" ,
351+ target_os = "freebsd" ,
352+ target_os = "android"
353+ ) ) ]
354+ {
355+ let tm_zone_ptr = tm_array[ i] . tm_zone ;
356+ unique_pointers. insert ( tm_zone_ptr) ;
357+ }
358+ }
359+
360+ #[ cfg( any(
361+ target_os = "linux" ,
362+ target_os = "macos" ,
363+ target_os = "freebsd" ,
364+ target_os = "android"
365+ ) ) ]
366+ {
367+ let unique_count = unique_pointers. len ( ) ;
368+ println ! ( "Number of unique tm_zone pointers: {}" , unique_count) ;
369+
370+ assert ! (
371+ unique_count >= 2 && unique_count <= ( NUM_CALLS - 1 ) ,
372+ "Unexpected number of unique tm_zone pointers: {} (expected between 2 and {})" ,
373+ unique_count, NUM_CALLS - 1
374+ ) ;
375+ }
376+ }
377+ }
0 commit comments