Quick update: The variation11 tests I mentioned are now passing after
fixing:

1. Empty string ordering - now sorts before numbers to match '' < 5
2. Windows ZTS - initialization in init_executor()

All CI tests pass. PR ready for review:
https://github.com/php/php-src/pull/20315

- Jason

On Wed, Oct 29, 2025 at 9:56 AM Jason Marble <
[email protected]> wrote:

> Hello PHP Internals!
>
> I believe I've found an acceptable solution to the issue that's plagued
> SORT_REGULAR since the dawn of time.
>
> Fundamentally, all sorting algorithms require transitive comparisons (if A
> ≤ B and B ≤ C, then A ≤ C). However, PHP's SORT_REGULAR comparison function
> violates transitivity when mixing numeric strings, non-numeric strings, and
> numbers, leading to unpredictable and non-deterministic sort results.
>
> **The Solution:**
> Add a `transitive_compare_mode` flag to executor_globals (TLS) that
> signals zendi_smart_strcmp() to enforce consistent ordering during
> SORT_REGULAR operations:
> - Numeric strings are consistently ordered relative to non-numeric strings
> - Eliminates circular comparisons
> - Maintains PHP 8+ semantics (numeric-types < numeric-strings <
> non-numeric)
>
> **Implementation:**
> - PR: https://github.com/php/php-src/pull/20315
> - Uses save/restore pattern for reentrancy safety
> - New test coverage included
>
> **Historical Context:**
> Raghubansh Kumar documented this issue in 2007, creating tests with the
> note "(OK to fail as result is unpredectable)". Nikita Popov's 2019 RFC
> improved string-to-number comparison semantics but didn't eliminate the
> transitivity violation. This fix completes that work.
>
> **Test Results:**
> Four variation11 tests currently fail as expected, but their outputs are
> now deterministic and more "sane" than both the 2007 and 2019 versions imo:
> https://gist.github.com/jmarble/957a096cb2bf25b577de47449305723f
>
> **ABI Considerations:**
> This adds a field to _zend_executor_globals, which is technically an ABI
> break appropriate for PHP 8.6. However, practical impact is minimal, I
> think, since most extensions access executor_globals through the EG() macro
> (which abstracts the struct layout),
> not via direct struct manipulation.
>
> I'd appreciate review and feedback on this approach. This is a
> long-standing correctness issue.
>
> Thank you for your time and consideration!
>
> - Jason
>

Reply via email to