ext/bcmath: guard BcMath\Number against an uninitialized bc_num#22259
Open
nicolas-grekas wants to merge 1 commit into
Open
ext/bcmath: guard BcMath\Number against an uninitialized bc_num#22259nicolas-grekas wants to merge 1 commit into
nicolas-grekas wants to merge 1 commit into
Conversation
A BcMath\Number whose constructor or __unserialize() never ran has a NULL bc_num. This cannot happen through normal PHP (the class is final with a custom create_object, so newInstanceWithoutConstructor() is rejected and unserialize() routes through __unserialize()), but C code such as an extension calling create_object directly can build one, after which every operation dereferences the NULL bc_num and crashes. Guard the entry points (value stringification, clone, comparison, arithmetic, the operator overloads, the bool cast and property checks) so they throw a clean Error instead. Normal, fully constructed instances are unaffected.
Member
|
This is a general issue caused by shitty PHP design choices. |
Contributor
Author
|
🤷 could still be worth fixing adhoc. I'll let maintainers do what they prefer with this PR :) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
BcMath\Numberis afinalinternal class with a customcreate_object, so the engine rejectsReflectionClass::newInstanceWithoutConstructor()for it andunserialize()always routes through__unserialize(). A freshlycreate_object-ed instance has aNULLbc_numonly transiently, before__construct()/__unserialize()runs; an uninitialized instance can never escape to userland.C code can however build one via
create_objectdirectly (e.g. the deep-clone extension at symfony/php-ext-deepclone, while reconstructing object graphs). EveryBcMath\Numberhandler dereferencesintern->num, so such an instance is a NULL-pointer dereference waiting to happen:(string) $n,clone $n,$n <=> $x,$n + 1,$n->add(...),(bool) $n,var_dump($n)all crash.This guards the entry points that read
num(value stringification /__serialize/get_properties_for,clone, thecompareanddo_operationoperator overloads, the arithmetic/sqrt/floor/ceil/round/divmod/powmod/comparemethods, the bool cast andhas_property) so they throwinstead of crashing, reusing the wording
DateTime/DateTimeZonealready use for the same situation. Fully constructed instances are unaffected.No
.phptis included because the uninitialized state is not reachable from pure PHP; it is exercised by the deep-clone extension's test suite.Surfaced while adding
BcMath\Numbersupport to the deep-clone extension and its polyfill for symfony/symfony#64323.