Skip to content

Fix GH-24063: SCCP merges 0.0 and -0.0 into a single constant - #24064

Merged
arnaud-lb merged 4 commits into
php:PHP-8.4from
lazerg:fix/gh-24063-sccp-signed-zero
Oct 2, 2026
Merged

arnaud-lb merged 4 commits into
php:PHP-8.4from
lazerg:fix/gh-24063-sccp-signed-zero

Conversation

@lazerg

@lazerg lazerg commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

SCCP joins phi values with zend_is_identical(), which compares doubles with ==, so 0.0 and -0.0 count as the same value. A ternary like $n < 0 ? -0.0 : 0.0 then gets folded to whichever constant the first branch held, and the condition disappears. The same thing happens for constant arrays and for elements of partial arrays.

The join now compares doubles bitwise (like compact_literals.c already does), recursing into arrays, and falls back to zend_is_identical() for everything else.

Fixes GH-24063

Comment thread Zend/Optimizer/sccp.c Outdated

static bool sccp_is_identical(const zval *a, const zval *b);

static int sccp_hash_is_not_identical(const zval *a, const zval *b)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the usefulness of this one line helper while you can just use !sccp_is_identical in it's only call site?

@lazerg lazerg Oct 2, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the zend_hash_compare() callback, which has to return 0 on a match, so !sccp_is_identical can't be passed directly.

@LamentXU123 LamentXU123 Oct 2, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is I doubt this design. what do you think of

static int sccp_values_differ(const void *p1, const void *p2)
{
    const zval *a = p1;
    const zval *b = p2;

    if (Z_TYPE_P(a) == IS_DOUBLE && Z_TYPE_P(b) == IS_DOUBLE) {
        return memcmp(&Z_DVAL_P(a), &Z_DVAL_P(b), sizeof(double)) != 0;
    }

    if (Z_TYPE_P(a) == IS_ARRAY && Z_TYPE_P(b) == IS_ARRAY) {
        return Z_ARRVAL_P(a) != Z_ARRVAL_P(b)
            && zend_hash_compare(
                Z_ARRVAL_P(a), Z_ARRVAL_P(b),
                sccp_values_differ, /* ordered */ true) != 0;
    }

    return !zend_is_identical(a, b);
}

ps: I remove my next review because I don't prefer the original design of this.

@lazerg lazerg Oct 2, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 90d0706.

@LamentXU123

LamentXU123 commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Thank you. Okay now I want to hear from others about this. /cc @iluuu1994 @arnaud-lb

@arnaud-lb arnaud-lb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

Comment thread Zend/Optimizer/sccp.c
return Z_ARRVAL_P(a) != Z_ARRVAL_P(b)
&& zend_hash_compare(Z_ARRVAL_P(a), Z_ARRVAL_P(b), sccp_values_differ, 1) != 0;
}
return !zend_is_identical(a, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case we add more persistent containers in the future, an assertion like this would be helpful:

    ZEND_ASSERT((1 << Z_TYPE_P(a)) & MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_BOOL|MAY_BE_LONG|MAY_BE_STRING);

(We can check that Z_TYPE_P(a) == Z_TYPE_P(b) at the beginning of the function to simplify the rest.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 478d95a. The assert also lets PARTIAL_ARRAY/PARTIAL_OBJECT through, because nested partial arrays reach it via join_hash_tables().

@arnaud-lb
arnaud-lb merged commit 87d728d into php:PHP-8.4 Oct 2, 2026
18 checks passed
arnaud-lb added a commit that referenced this pull request Oct 2, 2026
* PHP-8.6:
  Fix GH-24063: SCCP merges 0.0 and -0.0 into a single constant (#24064)
@arnaud-lb

Copy link
Copy Markdown
Member

Thank you!

devnexen pushed a commit to devnexen/php-src that referenced this pull request Oct 2, 2026
* PHP-8.4:
  Fix phpGH-24063: SCCP merges 0.0 and -0.0 into a single constant (php#24064)
devnexen pushed a commit to devnexen/php-src that referenced this pull request Oct 2, 2026
* PHP-8.5:
  Fix phpGH-24063: SCCP merges 0.0 and -0.0 into a single constant (php#24064)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants