Make WordPress Core

Opened 5 weeks ago

Last modified 4 weeks ago

#63099 new defect (bug)

wp_rand() function returns only 0 or 1 when called without parameters on 32-bit PHP systems

Reported by: kalonya's profile kalonya Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 6.7.2
Component: General Keywords: has-patch
Focuses: Cc:

Description

I've identified a bug in WordPress's wp_rand() function that causes it to return only the values 0 or 1 when called without parameters on 32-bit PHP systems.

Environment Information:

  • PHP Version: 7.4.33
  • PHP Int Max: 2147483647 (32-bit system)
  • PHP Int Size: 4
  • OS: Linux (64-bit)
  • Server Software: Apache
  • WordPress Version: 6.7.2
  • Random Int Available: Yes
  • OpenSSL Available: Yes

Issue Description:
When calling wp_rand() without parameters on a 32-bit PHP system, it consistently returns only the values 0 or 1, rather than generating random numbers across the expected range. This occurs due to an integer overflow issue.

Debug Results:

Array
(
    [start] => Array
        (
            [min] => 
            [max] => 
            [rnd_value_length] => 0
            [rnd_value] => ...
        )

    [max_random_number] => 4294967295
    [php_int_max] => 2147483647
    [after_cast] => Array
        (
            [min] => 0
            [max] => -1
            [max === max_random_number] => false
        )

    [use_random_int_functionality] => true
    [random_int_try] => Array
        (
            [_min] => -1
            [_max] => 0
        )

    [random_int_result] => -1
    [return_path] => random_int success
    [final_result] => 1
)

Root Cause Analysis:

  1. On 32-bit PHP systems (PHP_INT_MAX = 2147483647), the function sets $max_random_number to 4294967295 (unsigned 32-bit int max value)
  2. When this value is cast to an integer in 32-bit PHP, it overflows and becomes -1
  3. The function then calls random_int(-1, 0) which returns either -1 or 0
  4. Finally, the absint() function converts -1 to 1, resulting in only 0 or 1 being returned

Steps to Reproduce:

  1. Run WordPress on a 32-bit PHP system
  2. Call wp_rand() without parameters multiple times
  3. Observe that only 0 or 1 is returned

Expected Behavior:
The function should return random numbers across the full range (0 to getrandmax() or similar) when called without parameters, just like PHP's native rand() function.

Additional Tests:

  • PHP's native rand() and mt_rand() functions work correctly on the same system
  • When wp_rand() is called with specific parameters (e.g., wp_rand(10, 100)), it behaves correctly

This appears to be a bug in how the function handles 32-bit PHP systems when called without parameters.

Change History (4)

#1 @kalonya
5 weeks ago

Maybe we should set the $max_random_number like this?

$max_random_number = PHP_INT_SIZE === 4 ? (float) PHP_INT_MAX * 2 + 1 : PHP_INT_MAX;

The code tries to cast a (float) number to (int), which causes an overflow in a 32-bit system.

Last edited 5 weeks ago by kalonya (previous) (diff)

This ticket was mentioned in PR #8507 on WordPress/wordpress-develop by @debarghyabanerjee.


5 weeks ago
#2

  • Keywords has-patch added

Trac Ticket: Core-63099

## Problem

On 32-bit PHP systems, the wp_rand() function would incorrectly return only 0 or 1 when called without parameters due to an integer overflow. This occurred because the function sets $max_random_number to 4294967295, which overflows to -1 on 32-bit systems, leading to invalid arguments being passed to random_int().

## Solution

  • Modified the calculation of $max_random_number to dynamically use PHP_INT_MAX for 32-bit systems (PHP_INT_SIZE === 4).
  • For 64-bit systems, the previous behavior with 4294967295 remains unchanged.

#3 follow-up: @johnbillion
4 weeks ago

@kalonya What exactly is your server configuration please? In the ticket description you state that the OS is Linux (64-bit). Are you running a 32 bit version of PHP and OpenSSL on a 64 bit OS?

#4 in reply to: ↑ 3 @kalonya
4 weeks ago

Replying to johnbillion:

@kalonya What exactly is your server configuration please? In the ticket description you state that the OS is Linux (64-bit). Are you running a 32 bit version of PHP and OpenSSL on a 64 bit OS?

Not me, but three of our clients. They use a 32-bit version of PHP on a 64-bit OS. It doesn't happen on all 32-bit PHPs. Some implementations handle this problem by clamping 4294967295 to 2147483647, and some others just overflow and return -1. Unfortunately, I don't have access to their web server.

Note: See TracTickets for help on using tickets.