Skip to content

Null dereference because cache_slot is null #11614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
danog opened this issue Jul 7, 2023 · 11 comments
Closed

Null dereference because cache_slot is null #11614

danog opened this issue Jul 7, 2023 · 11 comments
Labels

Comments

@danog
Copy link
Contributor

danog commented Jul 7, 2023

Description

We've recently enabled coredump reporting in production, and we've been getting loads of coredumps, here's one of them.

This seems to be caused by a null pointer dereference in zend_fetch_ce_from_cache_slot (if (EXPECTED(HAVE_CACHE_SLOT && *cache_slot)) {:

Gdb backtrace:

#0  zend_fetch_ce_from_cache_slot (type=0x5643d29e5de8, cache_slot=0x0) at ./Zend/zend_execute.c:1092
#1  zend_check_type_slow (is_internal=false, is_return_type=false, cache_slot=0x0, ref=0x0, arg=0x7f8a68615f00, type=0x5643d29e5de8) at ./Zend/zend_execute.c:1092
#2  zend_check_type (is_internal=false, is_return_type=false, scope=0x5643d29e6d80, cache_slot=0x0, arg=0x7f8a68615f00, type=0x5643d29e5de8) at ./Zend/zend_execute.c:1144
#3  zend_verify_recv_arg_type (cache_slot=0x0, arg=0x7f8a68615f00, arg_num=1, zf=0x5643d29e7058) at ./Zend/zend_execute.c:1162
#4  zend_verify_recv_arg_type_helper_SPEC (op_1=0x7f8a68615f00) at ./Zend/zend_vm_execute.h:2576
#5  0x00005643cc33a7b6 in ZEND_RECV_SPEC_UNUSED_HANDLER () at ./Zend/zend_vm_execute.h:3918
#6  execute_ex (ex=0x7f8a68615f00) at ./Zend/zend_vm_execute.h:56204
#7  0x00005643cc33d701 in zend_execute (op_array=0x7f8a6867e000, return_value=0x0) at ./Zend/zend_vm_execute.h:60396
#8  0x00005643cc2cae55 in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0, file_count=file_count@entry=3) at ./Zend/zend.c:1827
#9  0x00005643cc2663fa in php_execute_script (primary_file=<optimized out>) at ./main/main.c:2542
#10 0x00005643cc3b450a in do_cli (argc=9, argv=0x5643ccd23170) at ./sapi/cli/php_cli.c:964
#11 0x00005643cc0f6c5b in main (argc=9, argv=0x5643ccd23170) at ./sapi/cli/php_cli.c:1333

zbacktrace:

[0x7f8a68615eb0] CuyZ\Valinor\Definition\FunctionsContainer->__construct(object[0x7f8a68615f00], array(0)[0x7f8a68615f10])
/zoon/zoon/vendor/cuyz/valinor/src/Definition/FunctionsContainer.php:23
[0x7f8a68615e00] CuyZ\Valinor\Library\Container->CuyZ\Valinor\Library\{closure}() /zoon/zoon/vendor/cuyz/valinor/src/Library/Container.php:160
[0x7f8a68615d70] CuyZ\Valinor\Library\Container->get("CuyZ\Valinor\Mapper\Object\Factory\ObjectBuilderFactory") /zoon/zoon/vendor/cuyz/valinor/src/Library/Container.php:248
[0x7f8a68615bb0] CuyZ\Valinor\Library\Container->CuyZ\Valinor\Library\{closure}() /zoon/zoon/vendor/cuyz/valinor/src/Library/Container.php:108
[0x7f8a68615b20] CuyZ\Valinor\Library\Container->get("CuyZ\Valinor\Mapper\Tree\Builder\NodeBuilder") /zoon/zoon/vendor/cuyz/valinor/src/Library/Container.php:248
[0x7f8a68615a50] CuyZ\Valinor\Library\Container->CuyZ\Valinor\Library\{closure}() /zoon/zoon/vendor/cuyz/valinor/src/Library/Container.php:91
// lots of other frames

ref: compressed_coredump-php.97977.1688702525

Feel free to tag me if further inspection of the coredump is needed.

PHP Version

PHP 8.2.7

Operating System

Ubuntu 20.04, ondrej repos

@Girgias
Copy link
Member

Girgias commented Jul 7, 2023

Can you provide any info on the configurations? Because AFAIK all CEs should be available from a cache slot for usage for the type checker.

Also on what type is it failing? As this might be an issue of not having allocated enough cache slots (considering I implemented intersection and DNF types and that's an issue I hit into by not having enough tests...)

@danog
Copy link
Contributor Author

danog commented Jul 10, 2023

Hi @Girgias, this is our PHP config: https://paste.daniil.it/config, PHP segfaulted when validating input with https://github.com/zoonru/valinor, here's some more of the PHP stacktrace:

[0x7f8a68615eb0] CuyZ\Valinor\Definition\FunctionsContainer->__construct(object[0x7f8a68615f00], array(0)[0x7f8a68615f10])
/zoon/zoon/vendor/cuyz/valinor/src/Definition/FunctionsContainer.php:23
[0x7f8a68615e00] CuyZ\Valinor\Library\Container->CuyZ\Valinor\Library\{closure}() /zoon/zoon/vendor/cuyz/valinor/src/Library/Container.php:160
[0x7f8a68615d70] CuyZ\Valinor\Library\Container->get("CuyZ\Valinor\Mapper\Object\Factory\ObjectBuilderFactory") /zoon/zoon/vendor/cuyz/valinor/src/Library/Container.php:248
[0x7f8a68615bb0] CuyZ\Valinor\Library\Container->CuyZ\Valinor\Library\{closure}() /zoon/zoon/vendor/cuyz/valinor/src/Library/Container.php:108
[0x7f8a68615b20] CuyZ\Valinor\Library\Container->get("CuyZ\Valinor\Mapper\Tree\Builder\NodeBuilder") /zoon/zoon/vendor/cuyz/valinor/src/Library/Container.php:248
[0x7f8a68615a50] CuyZ\Valinor\Library\Container->CuyZ\Valinor\Library\{closure}() /zoon/zoon/vendor/cuyz/valinor/src/Library/Container.php:91
[0x7f8a686159c0] CuyZ\Valinor\Library\Container->get("CuyZ\Valinor\Mapper\Tree\Builder\RootNodeBuilder") /zoon/zoon/vendor/cuyz/valinor/src/Library/Container.php:248
[0x7f8a68615950] Zoon\ORM\ObjectAnnotation\ObjectAnnotationHelper->getRootNodeBuilder() /zoon/zoon/vendor/zoon/orm/src/ObjectAnnotation/ObjectAnnotationHelper.php:53

And here's some more type information:

(gdb) frame 3
#3  zend_verify_recv_arg_type (cache_slot=0x0, arg=0x7f8a68615f00, arg_num=1, zf=0x5643d29e7058) at ./Zend/zend_execute.c:1162
1162				&& UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, cache_slot, zf->common.scope, 0, 0))) {
(gdb) printzv arg
[0x7f8a68615f00] (refcount=2) object(CuyZ\Valinor\Definition\Repository\Cache\CacheFunctionDefinitionRepository) #505 {
delegate => [0x7f8a5b89a578] (refcount=1) object(CuyZ\Valinor\Definition\Repository\Reflection\ReflectionFunctionDefinitionRepository) #531 {
typeParserFactory => [0x7f8a5baa9e68] (refcount=3) object(CuyZ\Valinor\Type\Parser\Factory\LexingTypeParserFactory) #535 {
nativeParser => [0x7f8a5b89a3e8] UNDEF
templateParser => [0x7f8a5b89a3f8] (refcount=2) object(CuyZ\Valinor\Type\Parser\Template\BasicTemplateParser) #536 {




(gdb) print (const char *) ((zend_string *) cur_arg_info->type->ptr)->val
$8 = 0x5643cdaaeb88 "CuyZ\\Valinor\\Definition\\Repository\\FunctionDefinitionRepository"

@danog
Copy link
Contributor Author

danog commented Jul 10, 2023

@Girgias Got permission to share the full coredump, I've DM-ed to you on mastodon, feel free to share it with any other PHP dev as needed (didn't feel comfortable to share it here :)

@Girgias
Copy link
Member

Girgias commented Jul 10, 2023

I cannot get the coredump to work, can't you give me reproducible steps so that I can run in on my machine?

@danog
Copy link
Contributor Author

danog commented Jul 10, 2023

To inspect the coredump, you can add the ondrej repos on ubuntu 20.04, and install:

sudo apt-get install gdb php-common php-pear php8.2-apcu-dbgsym php8.2-apcu php8.2-bcmath-dbgsym php8.2-bcmath php8.2-cli-dbgsym php8.2-cli php8.2-common-dbgsym php8.2-common php8.2-curl-dbgsym php8.2-curl php8.2-dev php8.2-fpm-dbgsym php8.2-fpm php8.2-gd-dbgsym php8.2-gd php8.2-gmp-dbgsym php8.2-gmp php8.2-igbinary-dbgsym php8.2-igbinary php8.2-intl-dbgsym php8.2-intl php8.2-maxminddb-dbgsym php8.2-maxminddb php8.2-mbstring-dbgsym php8.2-mbstring php8.2-memcached-dbgsym php8.2-memcached php8.2-mongodb-dbgsym php8.2-mongodb php8.2-msgpack-dbgsym php8.2-msgpack php8.2-mysql-dbgsym php8.2-mysql php8.2-opcache-dbgsym php8.2-opcache php8.2-readline-dbgsym php8.2-readline php8.2-redis-dbgsym php8.2-redis php8.2-soap-dbgsym php8.2-soap php8.2-tidy-dbgsym php8.2-tidy php8.2-xdebug php8.2-xhprof-dbgsym php8.2-xhprof php8.2-xml-dbgsym php8.2-xml php8.2-zip-dbgsym php8.2-zip php8.2-zstd-dbgsym php8.2-zstd

Then checkout the PHP-8.2.7 tag of php-src and run gdb php compressed_coredump-php.97977.1688702525 while in the php-src directory.

To reproduce approximately what we're doing in our code:


use AssertionError;
use CuyZ\Valinor\Definition\Properties;
use CuyZ\Valinor\Definition\PropertyDefinition;
use CuyZ\Valinor\Definition\Repository\Cache\Compiler\AttributesCompiler;
use CuyZ\Valinor\Definition\Repository\Cache\Compiler\PropertyDefinitionCompiler;
use CuyZ\Valinor\Definition\Repository\Cache\Compiler\TypeCompiler;
use CuyZ\Valinor\Definition\Repository\Reflection\NativeAttributesRepository;
use CuyZ\Valinor\Definition\Repository\Reflection\ReflectionClassDefinitionRepository;
use CuyZ\Valinor\Library\Container;
use CuyZ\Valinor\Library\Settings;
use CuyZ\Valinor\Mapper\Tree\Builder\RootNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Shell;
use CuyZ\Valinor\Mapper\TypeTreeMapperError;
use CuyZ\Valinor\Type\Parser\Factory\LexingTypeParserFactory;
use CuyZ\Valinor\Type\Parser\Template\BasicTemplateParser;
use CuyZ\Valinor\Type\Types\NativeClassType;

final class ObjectAnnotationHelper {

	/** @var array<class-string<MongoObject|DataObject>, Properties> $propertyAttributes */
	private static array $propertyAttributes = [];

	/** @var array<class-string<MongoObject|DataObject>, array<string, AbstractVirtualMethod>> $virtualMethods */
	private static array $virtualMethods = [];

	private static ?RootNodeBuilder $rootNodeBuilder = null;

	public static function getRootNodeBuilder(): RootNodeBuilder {
		if (self::$rootNodeBuilder) {
			return self::$rootNodeBuilder;
		}
		$settings = new Settings;
		$settings->allowPermissiveTypes = true;
		$settings->enableFlexibleCasting = true;
		self::$rootNodeBuilder = (new Container($settings))->get(RootNodeBuilder::class);
		return self::$rootNodeBuilder;
	}
}

ObjectAnnotationHelper::getRootNodeBuilder();

@danog
Copy link
Contributor Author

danog commented Jul 10, 2023

Ah and of course the coredump is compressed with zstd (the extension can be easy to miss given the long filename), it has to be decompressed with zstd -d first

@Girgias
Copy link
Member

Girgias commented Jul 10, 2023

I am on Fedora, so Ubuntu debug steps are not going to help me here :/

@danog
Copy link
Contributor Author

danog commented Jul 10, 2023

This can be done inside of a docker image too, actually I'm debugging this precisely on the official ubuntu:20.04 image

@Girgias
Copy link
Member

Girgias commented Jul 10, 2023

I don't use Docker, so I suppose time to figure that out. But frankly having a better (and actual) reproducible script that segfaults would be way more useful, as this would also become the regression test.

Just looking at the stack trace tho the cache_slot pointer is NULL which is pretty fishy, so I'm not even sure this has anything to do with cache slot allocations.

@nielsdos
Copy link
Member

nielsdos commented Mar 5, 2025

Does this still affect you? Or have you seen something like this? A reproducer or a coredump would be great.

Copy link

No feedback was provided. The issue is being suspended because we assume that you are no longer experiencing the problem. If this is not the case and you are able to provide the information that was requested earlier, please do so. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants