@@ -8,6 +8,8 @@ fn main() {
8
8
test_localtime_r_gmt ( ) ;
9
9
test_localtime_r_pst ( ) ;
10
10
test_localtime_r_epoch ( ) ;
11
+ test_localtime_r_verify_string_deduplication ( ) ;
12
+ test_localtime_r_multiple_calls_deduplication ( )
11
13
// Architecture-specific tests.
12
14
#[ cfg( target_pointer_width = "32" ) ]
13
15
test_localtime_r_future_32b ( ) ;
@@ -125,7 +127,7 @@ fn test_localtime_r_gmt() {
125
127
fn test_localtime_r_pst ( ) {
126
128
let key = "TZ" ;
127
129
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
129
131
let custom_time_ptr = & TIME_SINCE_EPOCH ;
130
132
let mut tm = create_empty_tm ( ) ;
131
133
@@ -276,3 +278,100 @@ fn test_localtime_r_future_32b() {
276
278
assert ! ( ptr:: eq( res, & mut tm) ) ;
277
279
env:: remove_var ( key) ;
278
280
}
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