@@ -3413,6 +3413,192 @@ S_lossless_NV_to_IV(const NV nv, IV *ivp)
3413
3413
return FALSE;
3414
3414
}
3415
3415
3416
+ /*
3417
+ * S_iv_{add,sub,mul}_may_overflow(a, b, p) virtually compute "a <op> b"
3418
+ * (where <op> is +, -, or *) in infinite precision, and, if the result
3419
+ * is (or may be) not representable with IV, return true.
3420
+ * Otherwise (no overflow), store the result to *p and return false.
3421
+ * These functions allow false positives (so their names contain "may")
3422
+ * to speed up simple common cases.
3423
+ */
3424
+
3425
+ /* Define IV_*_OVERFLOW_IS_EXPENSIVE below to nonzero value
3426
+ * if strict overflow checks are too expensive
3427
+ * (for example, for CPUs that have no hardware overflow detection flags).
3428
+ * If these macros have nonzero value, or overflow-checking compiler intrinsics
3429
+ * are not available, good-old heuristics (with some false positives)
3430
+ * will be used. */
3431
+ # ifndef IV_ADD_SUB_OVERFLOW_IS_EXPENSIVE
3432
+ # define IV_ADD_SUB_OVERFLOW_IS_EXPENSIVE 0
3433
+ # endif
3434
+ # ifndef IV_MUL_OVERFLOW_IS_EXPENSIVE
3435
+ /* Strict overflow check for IV multiplication is generally expensive
3436
+ * when IV is a multi-word integer.
3437
+ * We assume that PTRSIZE matches the platform word size; LONGSIZE might not
3438
+ * match for LLP64 platforms such as Win32 x86-64. */
3439
+ # define IV_MUL_OVERFLOW_IS_EXPENSIVE (IVSIZE > PTRSIZE)
3440
+ # endif
3441
+
3442
+ # if defined(I_STDCKDINT ) && !IV_ADD_SUB_OVERFLOW_IS_EXPENSIVE
3443
+ /* XXX Preparation for upcoming C23, but I_STDCKDINT is not yet tested */
3444
+ # define S_iv_add_may_overflow (il , ir , result ) ckd_add(result, il, ir)
3445
+ # elif defined(HAS_BUILTIN_ADD_OVERFLOW ) && !IV_ADD_SUB_OVERFLOW_IS_EXPENSIVE
3446
+ # define S_iv_add_may_overflow __builtin_add_overflow
3447
+ # else
3448
+ PERL_STATIC_INLINE bool
3449
+ S_iv_add_may_overflow (IV il , IV ir , IV * const result )
3450
+ {
3451
+ /* topl and topr hold only 2 bits */
3452
+ PERL_UINT_FAST8_T const topl = ((UV )il ) >> (UVSIZE * 8 - 2 );
3453
+ PERL_UINT_FAST8_T const topr = ((UV )ir ) >> (UVSIZE * 8 - 2 );
3454
+
3455
+ /* if both are in a range that can't under/overflow, do a simple integer
3456
+ * add: if the top of both numbers are 00 or 11, then it's safe */
3457
+ if (!( ((topl + 1 ) | (topr + 1 )) & 2 )) {
3458
+ * result = il + ir ;
3459
+ return false;
3460
+ }
3461
+ return true; /* addition may overflow */
3462
+ }
3463
+ # endif
3464
+
3465
+ /*
3466
+ * S_uv_{add,sub,mul}_overflow(a, b, p) are similar, but the results are UV
3467
+ * and they should perform strict overflow check (no false positives).
3468
+ */
3469
+
3470
+ # if defined(I_STDCKDINT )
3471
+ /* XXX Preparation for upcoming C23, but I_STDCKDINT is not yet tested */
3472
+ # define S_uv_add_overflow (auv , buv , result ) ckd_add(result, auv, buv)
3473
+ # elif defined(HAS_BUILTIN_ADD_OVERFLOW )
3474
+ # define S_uv_add_overflow __builtin_add_overflow
3475
+ # else
3476
+ PERL_STATIC_INLINE bool
3477
+ S_uv_add_overflow (UV auv , UV buv , UV * const result )
3478
+ {
3479
+ /* (auv + buv) < auv means that the addition wrapped around,
3480
+ i.e. overflowed. Note that unsigned integer overflow is well-defined
3481
+ in standard C to wrap around, in constrast to signed integer overflow
3482
+ whose behaviour is undefined. */
3483
+ return (* result = auv + buv ) < auv ;
3484
+ }
3485
+ # endif
3486
+
3487
+ # if defined(I_STDCKDINT ) && !IV_ADD_SUB_OVERFLOW_IS_EXPENSIVE
3488
+ /* XXX Preparation for upcoming C23, but I_STDCKDINT is not yet tested */
3489
+ # define S_iv_sub_may_overflow (il , ir , result ) ckd_sub(result, il, ir)
3490
+ # elif defined(HAS_BUILTIN_SUB_OVERFLOW ) && !IV_ADD_SUB_OVERFLOW_IS_EXPENSIVE
3491
+ # define S_iv_sub_may_overflow __builtin_sub_overflow
3492
+ # else
3493
+ PERL_STATIC_INLINE bool
3494
+ S_iv_sub_may_overflow (IV il , IV ir , IV * const result )
3495
+ {
3496
+ PERL_UINT_FAST8_T const topl = ((UV )il ) >> (UVSIZE * 8 - 2 );
3497
+ PERL_UINT_FAST8_T const topr = ((UV )ir ) >> (UVSIZE * 8 - 2 );
3498
+
3499
+ /* if both are in a range that can't under/overflow, do a simple integer
3500
+ * subtract: if the top of both numbers are 00 or 11, then it's safe */
3501
+ if (!( ((topl + 1 ) | (topr + 1 )) & 2 )) {
3502
+ * result = il - ir ;
3503
+ return false;
3504
+ }
3505
+ return true; /* subtraction may overflow */
3506
+ }
3507
+ # endif
3508
+
3509
+ # if defined(I_STDCKDINT )
3510
+ /* XXX Preparation for upcoming C23, but I_STDCKDINT is not yet tested */
3511
+ # define S_uv_sub_overflow (auv , buv , result ) ckd_sub(result, auv, buv)
3512
+ # elif defined(HAS_BUILTIN_SUB_OVERFLOW )
3513
+ # define S_uv_sub_overflow __builtin_sub_overflow
3514
+ # else
3515
+ PERL_STATIC_INLINE bool
3516
+ S_uv_sub_overflow (UV auv , UV buv , UV * const result )
3517
+ {
3518
+ return (* result = auv - buv ) > auv ;
3519
+ }
3520
+ # endif
3521
+
3522
+ # if defined(I_STDCKDINT ) && !IV_MUL_OVERFLOW_IS_EXPENSIVE
3523
+ /* XXX Preparation for upcoming C23, but I_STDCKDINT is not yet tested */
3524
+ # define S_iv_mul_may_overflow (il , ir , result ) ckd_mul(result, il, ir)
3525
+ # elif defined(HAS_BUILTIN_MUL_OVERFLOW ) && !IV_MUL_OVERFLOW_IS_EXPENSIVE
3526
+ # define S_iv_mul_may_overflow __builtin_mul_overflow
3527
+ # else
3528
+ PERL_STATIC_INLINE bool
3529
+ S_iv_mul_may_overflow (IV il , IV ir , IV * const result )
3530
+ {
3531
+ UV const topl = ((UV )il ) >> (UVSIZE * 4 - 1 );
3532
+ UV const topr = ((UV )ir ) >> (UVSIZE * 4 - 1 );
3533
+
3534
+ /* if both are in a range that can't under/overflow, do a simple integer
3535
+ * multiply: if the top halves(*) of both numbers are 00...00 or 11...11,
3536
+ * then it's safe.
3537
+ * (*) for 32-bits, the "top half" is the top 17 bits,
3538
+ * for 64-bits, its 33 bits */
3539
+ if (!(
3540
+ ((topl + 1 ) | (topr + 1 ))
3541
+ & ( (((UV )1 ) << (UVSIZE * 4 + 1 )) - 2 ) /* 11..110 */
3542
+ )) {
3543
+ * result = il * ir ;
3544
+ return false;
3545
+ }
3546
+ return true; /* multiplication may overflow */
3547
+ }
3548
+ # endif
3549
+
3550
+ # if defined(I_STDCKDINT )
3551
+ /* XXX Preparation for upcoming C23, but I_STDCKDINT is not yet tested */
3552
+ # define S_uv_mul_overflow (auv , buv , result ) ckd_mul(result, auv, buv)
3553
+ # elif defined(HAS_BUILTIN_MUL_OVERFLOW )
3554
+ # define S_uv_mul_overflow __builtin_mul_overflow
3555
+ # else
3556
+ PERL_STATIC_INLINE bool
3557
+ S_uv_mul_overflow (UV auv , UV buv , UV * const result )
3558
+ {
3559
+ const UV topmask = (~ (UV )0 ) << (4 * sizeof (UV ));
3560
+ const UV botmask = ~topmask ;
3561
+
3562
+ # if UVSIZE > LONGSIZE && UVSIZE <= 2 * LONGSIZE
3563
+ /* If UV is double-word integer, declare these variables as single-word
3564
+ integers to help compiler to avoid double-word multiplication. */
3565
+ unsigned long alow , ahigh , blow , bhigh ;
3566
+ # else
3567
+ UV alow , ahigh , blow , bhigh ;
3568
+ # endif
3569
+
3570
+ /* If this does sign extension on unsigned it's time for plan B */
3571
+ ahigh = auv >> (4 * sizeof (UV ));
3572
+ alow = auv & botmask ;
3573
+ bhigh = buv >> (4 * sizeof (UV ));
3574
+ blow = buv & botmask ;
3575
+
3576
+ if (ahigh && bhigh )
3577
+ /* eg 32 bit is at least 0x10000 * 0x10000 == 0x100000000
3578
+ which is overflow. */
3579
+ return true;
3580
+
3581
+ UV product_middle = 0 ;
3582
+ if (ahigh || bhigh ) {
3583
+ /* One operand is large, 1 small */
3584
+ /* Either ahigh or bhigh is zero here, so the addition below
3585
+ can't overflow. */
3586
+ product_middle = (UV )ahigh * blow + (UV )alow * bhigh ;
3587
+ if (product_middle & topmask )
3588
+ return true;
3589
+ /* OK, product_middle won't lose bits when we shift it. */
3590
+ product_middle <<= 4 * sizeof (UV );
3591
+ }
3592
+ /* else: eg 32 bit is at most 0xFFFF * 0xFFFF == 0xFFFE0001
3593
+ so the unsigned multiply cannot overflow. */
3594
+
3595
+ /* (UV) cast below is necessary to force the multiplication to produce
3596
+ UV result, as alow and blow might be narrower than UV */
3597
+ UV product_low = (UV )alow * blow ;
3598
+ return S_uv_add_overflow (product_middle , product_low , result );
3599
+ }
3600
+ # endif
3601
+
3416
3602
#endif
3417
3603
3418
3604
/* ------------------ pp.c, regcomp.c, toke.c, universal.c ------------ */
0 commit comments