collectRealCallStackOnMemoryLimitViolation()
last analyzed

Size

Total Lines 88
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 56
c 0
b 0
f 0
nc 11
nop 9
dl 0
loc 88

How to fix   Long Method    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/**
4
 * This file is part of the reliforp/reli-prof package.
5
 *
6
 * (c) sji <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Reli\Lib\PhpProcessReader\PhpMemoryReader;
15
16
use Reli\Inspector\Settings\MemoryProfilerSettings\MemoryLimitErrorDetails;
17
use Reli\Inspector\Settings\TargetPhpSettings\TargetPhpSettings;
18
use Reli\Lib\Log\Log;
19
use Reli\Lib\PhpInternals\Types\Zend\Bucket;
0 ignored issues
show
Bug introduced by
The type Reli\Lib\PhpInternals\Types\Zend\Bucket was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use Reli\Lib\PhpInternals\Types\Zend\ZendArray;
0 ignored issues
show
Bug introduced by
The type Reli\Lib\PhpInternals\Types\Zend\ZendArray was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use Reli\Lib\PhpInternals\Types\Zend\ZendCastedTypeProvider;
22
use Reli\Lib\PhpInternals\Types\Zend\ZendClassConstant;
23
use Reli\Lib\PhpInternals\Types\Zend\ZendClassEntry;
24
use Reli\Lib\PhpInternals\Types\Zend\ZendClosure;
25
use Reli\Lib\PhpInternals\Types\Zend\ZendCompilerGlobals;
26
use Reli\Lib\PhpInternals\Types\Zend\ZendConstant;
27
use Reli\Lib\PhpInternals\Types\Zend\ZendExecuteData;
28
use Reli\Lib\PhpInternals\Types\Zend\ZendExecutorGlobals;
29
use Reli\Lib\PhpInternals\Types\Zend\ZendFunction;
30
use Reli\Lib\PhpInternals\Types\Zend\ZendMmChunk;
31
use Reli\Lib\PhpInternals\Types\Zend\ZendObject;
32
use Reli\Lib\PhpInternals\Types\Zend\ZendObjectsStore;
33
use Reli\Lib\PhpInternals\Types\Zend\ZendReference;
34
use Reli\Lib\PhpInternals\Types\Zend\ZendResource;
35
use Reli\Lib\PhpInternals\Types\Zend\ZendString;
36
use Reli\Lib\PhpInternals\Types\Zend\Zval;
37
use Reli\Lib\PhpInternals\ZendTypeReader;
38
use Reli\Lib\PhpInternals\ZendTypeReaderCreator;
39
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\CallFrameHeaderMemoryLocation;
40
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\CallFrameVariableTableMemoryLocation;
41
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\DefaultPropertiesTableMemoryLocation;
42
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\DefaultStaticMembersTableMemoryLocation;
43
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\DynamicFuncDefsTableMemoryLocation;
44
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\LocalVariableNameTableMemoryLocation;
45
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\MemoryLocations;
46
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ObjectsStoreMemoryLocation;
47
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\RuntimeCacheMemoryLocation;
48
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\StaticMembersTableMemoryLocation;
49
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\VmStackMemoryLocation;
50
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendArenaMemoryLocation;
51
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendArgInfosMemoryLocation;
52
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendArrayMemoryLocation;
53
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendArrayTableMemoryLocation;
54
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendArrayTableOverheadMemoryLocation;
55
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendClassConstantMemoryLocation;
56
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendClassEntryMemoryLocation;
57
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendConstantMemoryLocation;
58
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendMmChunkMemoryLocation;
59
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendMmHugeListMemoryLocation;
60
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendObjectHandlersMemoryLocation;
61
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendObjectMemoryLocation;
62
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendOpArrayBodyMemoryLocation;
63
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendOpArrayHeaderMemoryLocation;
64
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendPropertyInfoMemoryLocation;
65
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendReferenceMemoryLocation;
66
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendResourceMemoryLocation;
67
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocation\ZendStringMemoryLocation;
68
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ArgInfoContext;
69
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ArgInfosContext;
70
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ArrayElementContext;
71
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ArrayElementsContext;
72
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ArrayHeaderContext;
73
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ArrayPossibleOverheadContext;
74
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\CallFrameContext;
75
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\CallFramesContext;
76
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\CallFrameVariableTableContext;
77
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ClassConstantContext;
78
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ClassConstantInfoContext;
79
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ClassConstantsContext;
80
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ClassDefinitionContext;
81
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ClassEntryContext;
82
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ClassStaticPropertiesContext;
83
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ClosureContext;
84
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\DefaultPropertiesTableContext;
85
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\DefaultStaticPropertiesContext;
86
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\DefinedClassesContext;
87
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\DefinedFunctionsContext;
88
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\DynamicFuncDefsContext;
89
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\FunctionDefinitionContext;
90
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\GlobalConstantContext;
91
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\GlobalConstantsContext;
92
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\GlobalVariablesContext;
93
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\IncludedFilesContext;
94
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\InternalFunctionDefinitionContext;
95
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\LocalVariableNameTableContext;
96
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ObjectContext;
97
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ObjectPropertiesContext;
98
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ObjectsStoreContext;
99
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\OpArrayContext;
100
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\PhpReferenceContext;
101
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\PropertiesInfoContext;
102
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\PropertyInfoContext;
103
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ReferenceContext;
104
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ResourceContext;
105
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\RuntimeCacheContext;
106
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\ScalarValueContext;
107
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\StringContext;
108
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\TopReferenceContext;
109
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ReferenceContext\UserFunctionDefinitionContext;
110
use Reli\Lib\PhpProcessReader\PhpZendMemoryManagerChunkFinder;
111
use Reli\Lib\Process\MemoryReader\MemoryReaderInterface;
112
use Reli\Lib\Process\Pointer\Dereferencer;
113
use Reli\Lib\Process\Pointer\PointedTypeResolver;
114
use Reli\Lib\Process\Pointer\Pointer;
115
use Reli\Lib\Process\Pointer\RemoteProcessDereferencer;
116
use Reli\Lib\Process\ProcessSpecifier;
117
118
/** @psalm-import-type VersionDecided from TargetPhpSettings */
119
final class MemoryLocationsCollector
120
{
121
    private ?ZendTypeReader $zend_type_reader = null;
122
    private ?UserFunctionDefinitionContext $memory_limit_error_function_context = null;
123
124
    public function __construct(
125
        private MemoryReaderInterface $memory_reader,
126
        private ZendTypeReaderCreator $zend_type_reader_creator,
127
        private PhpZendMemoryManagerChunkFinder $chunk_finder,
128
    ) {
129
    }
130
131
    /**
132
     * @param value-of<ZendTypeReader::ALL_SUPPORTED_VERSIONS> $php_version
0 ignored issues
show
Documentation Bug introduced by
The doc comment value-of<ZendTypeReader::ALL_SUPPORTED_VERSIONS> at position 0 could not be parsed: Unknown type name 'value-of' at position 0 in value-of<ZendTypeReader::ALL_SUPPORTED_VERSIONS>.
Loading history...
133
     */
134
    public function getTypeReader(string $php_version): ZendTypeReader
135
    {
136
        if (is_null($this->zend_type_reader)) {
137
            $this->zend_type_reader = $this->zend_type_reader_creator->create($php_version);
138
        }
139
        return $this->zend_type_reader;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->zend_type_reader could return the type null which is incompatible with the type-hinted return Reli\Lib\PhpInternals\ZendTypeReader. Consider adding an additional type-check to rule them out.
Loading history...
140
    }
141
142
    /**
143
     * @param value-of<ZendTypeReader::ALL_SUPPORTED_VERSIONS> $php_version
0 ignored issues
show
Documentation Bug introduced by
The doc comment value-of<ZendTypeReader::ALL_SUPPORTED_VERSIONS> at position 0 could not be parsed: Unknown type name 'value-of' at position 0 in value-of<ZendTypeReader::ALL_SUPPORTED_VERSIONS>.
Loading history...
144
     */
145
    private function getDereferencer(int $pid, string $php_version): Dereferencer
146
    {
147
        return new RemoteProcessDereferencer(
148
            $this->memory_reader,
149
            new ProcessSpecifier($pid),
150
            new ZendCastedTypeProvider(
151
                $this->getTypeReader($php_version),
152
            ),
153
            new class ($php_version) implements PointedTypeResolver {
154
                public function __construct(
155
                    private string $php_version,
156
                ) {
157
                }
158
159
                public function resolve(string $type_name): string
160
                {
161
                    return match ($this->php_version) {
162
                        ZendTypeReader::V70,
163
                        ZendTypeReader::V71,
164
                        ZendTypeReader::V72 => match ($type_name) {
165
                            Bucket::class => \Reli\Lib\PhpInternals\Types\Zend\V70\Bucket::class,
166
                            ZendArray::class => \Reli\Lib\PhpInternals\Types\Zend\V70\ZendArray::class,
167
                            Zval::class => \Reli\Lib\PhpInternals\Types\Zend\V70\Zval::class,
168
                            default => $type_name,
169
                        },
170
                        ZendTypeReader::V73 => match ($type_name) {
171
                            Bucket::class => \Reli\Lib\PhpInternals\Types\Zend\V73\Bucket::class,
172
                            ZendArray::class => \Reli\Lib\PhpInternals\Types\Zend\V73\ZendArray::class,
173
                            Zval::class => \Reli\Lib\PhpInternals\Types\Zend\V73\Zval::class,
174
                            default => $type_name,
175
                        },
176
                        ZendTypeReader::V74 => match ($type_name) {
177
                            Bucket::class => \Reli\Lib\PhpInternals\Types\Zend\V74\Bucket::class,
178
                            ZendArray::class => \Reli\Lib\PhpInternals\Types\Zend\V74\ZendArray::class,
179
                            Zval::class => \Reli\Lib\PhpInternals\Types\Zend\V74\Zval::class,
180
                            default => $type_name,
181
                        },
182
                        ZendTypeReader::V80,
183
                        ZendTypeReader::V81 => match ($type_name) {
184
                            ZendArray::class => \Reli\Lib\PhpInternals\Types\Zend\V80\ZendArray::class,
185
                            default => $type_name,
186
                        },
187
                        ZendTypeReader::V82,
188
                        ZendTypeReader::V83 => $type_name,
189
                    };
190
                }
191
            }
192
        );
193
    }
194
195
    /** @param TargetPhpSettings<VersionDecided> $target_php_settings */
196
    private function getMainChunkAddress(
197
        ProcessSpecifier $process_specifier,
198
        TargetPhpSettings $target_php_settings,
199
        Dereferencer $dereferencer,
200
    ): int {
201
        $chunk_address = $this->chunk_finder->findAddress(
202
            $process_specifier,
203
            $target_php_settings,
204
            $dereferencer,
205
        );
206
        if (is_null($chunk_address)) {
207
            throw new \RuntimeException('chunk address not found');
208
        }
209
        return $chunk_address;
210
    }
211
212
    /** @param TargetPhpSettings<VersionDecided> $target_php_settings */
213
    public function collectAll(
214
        ProcessSpecifier $process_specifier,
215
        TargetPhpSettings $target_php_settings,
216
        int $eg_address,
217
        int $cg_address,
218
        ?MemoryLimitErrorDetails $memory_limit_error_details = null,
219
    ): CollectedMemories {
220
        $pid = $process_specifier->pid;
221
        $php_version = $target_php_settings->php_version;
0 ignored issues
show
Documentation Bug introduced by
It seems like $target_php_settings->php_version of type string is incompatible with the declared type Reli\Inspector\Settings\TargetPhpSettings\TVersion of property $php_version.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
222
        $dereferencer = $this->getDereferencer($pid, $php_version);
223
        $zend_type_reader = $this->zend_type_reader_creator->create($php_version);
224
225
        $main_chunk_header_pointer = new Pointer(
226
            ZendMmChunk::class,
227
            $this->getMainChunkAddress(
228
                $process_specifier,
229
                $target_php_settings,
230
                $dereferencer,
231
            ),
232
            $zend_type_reader->sizeOf('zend_mm_chunk'),
233
        );
234
235
        $memory_locations = new MemoryLocations();
236
        $chunk_memory_locations = new MemoryLocations();
237
238
        $zend_mm_main_chunk = $dereferencer->deref($main_chunk_header_pointer);
239
        foreach ($zend_mm_main_chunk->iterateChunks($dereferencer) as $chunk) {
240
            $chunk_memory_location = ZendMmChunkMemoryLocation::fromZendMmChunk($chunk);
241
            $chunk_memory_locations->add(
242
                $chunk_memory_location
243
            );
244
        }
245
        $huge_memory_locations = new MemoryLocations();
246
        foreach ($zend_mm_main_chunk->heap_slot->iterateHugeList($dereferencer) as $huge_list) {
247
            $huge_memory_locations->add(
248
                ZendMmChunkMemoryLocation::fromZendMmHugeList($huge_list)
249
            );
250
            $memory_locations->add(
251
                ZendMmHugeListMemoryLocation::fromZendMmHugeList($huge_list)
252
            );
253
        }
254
255
        $memory_get_usage_size = $zend_mm_main_chunk->heap_slot->size;
256
        $memory_get_usage_real_size = $zend_mm_main_chunk->heap_slot->real_size;
257
        $cached_chunks_size = $zend_mm_main_chunk->heap_slot->cached_chunks_count * ZendMmChunk::SIZE;
258
259
        $eg_pointer = new Pointer(
260
            ZendExecutorGlobals::class,
261
            $eg_address,
262
            $zend_type_reader->sizeOf('zend_executor_globals')
263
        );
264
        $cg_pointer = new Pointer(
265
            ZendCompilerGlobals::class,
266
            $cg_address,
267
            $zend_type_reader->sizeOf('zend_compiler_globals')
268
        );
269
270
        $compiler_arena_memory_locations = new MemoryLocations();
271
        /** @var ZendCompilerGlobals $cg */
272
        $cg = $dereferencer->deref($cg_pointer);
273
        if ($cg->arena !== null) {
274
            $arena_root = $dereferencer->deref($cg->arena);
275
            foreach ($arena_root->iterateChain($dereferencer) as $arena) {
276
                $compiler_arena_memory_locations->add(
277
                    ZendArenaMemoryLocation::fromZendArena($arena)
278
                );
279
            }
280
        }
281
282
        if ($cg->ast_arena !== null) {
283
            $ast_arena_root = $dereferencer->deref($cg->ast_arena);
284
            foreach ($ast_arena_root->iterateChain($dereferencer) as $ast_arena) {
285
                $compiler_arena_memory_locations->add(
286
                    ZendArenaMemoryLocation::fromZendArena($ast_arena)
287
                );
288
            }
289
        }
290
291
        /** @var ZendExecutorGlobals $eg */
292
        $eg = $dereferencer->deref($eg_pointer);
293
294
        $vm_stack_memory_locations = new MemoryLocations();
295
        if (!is_null($eg->vm_stack)) {
296
            $vm_stack_curent = $dereferencer->deref($eg->vm_stack);
297
            foreach ($vm_stack_curent->iterateStackChain($dereferencer) as $vm_stack) {
298
                $vm_stack_memory_locations->add(
299
                    VmStackMemoryLocation::fromZendVmStack($vm_stack),
300
                );
301
            }
302
        }
303
304
        $context_pools = ContextPools::createDefault();
305
306
        $included_files_context = $this->collectIncludedFiles(
307
            $eg->included_files,
308
            $dereferencer,
309
            $memory_locations,
310
            $context_pools,
311
        );
312
313
        $interned_strings_context = $this->collectInternedStrings(
314
            $cg->interned_strings,
315
            $cg->map_ptr_base,
316
            $dereferencer,
317
            $zend_type_reader,
318
            $memory_locations,
319
            $context_pools,
320
        );
321
322
        assert(!is_null($eg->function_table));
323
        assert(!is_null($eg->class_table));
324
        assert(!is_null($eg->zend_constants));
325
326
        $function_table = $dereferencer->deref($eg->function_table);
327
        $class_table = $dereferencer->deref($eg->class_table);
328
        $zend_constants = $dereferencer->deref($eg->zend_constants);
329
330
        $global_variables_context = $this->collectGlobalVariables(
331
            $eg->symbol_table,
332
            $cg->map_ptr_base,
333
            $dereferencer,
334
            $zend_type_reader,
335
            $memory_locations,
336
            $context_pools,
337
        );
338
339
        $call_frames_context = $this->collectCallFrames(
340
            $eg,
341
            $cg->map_ptr_base,
342
            $dereferencer,
343
            $zend_type_reader,
344
            $memory_locations,
345
            $context_pools,
346
        );
347
348
        $defined_functions_context = $this->collectFunctionTable(
349
            $function_table,
350
            $cg->map_ptr_base,
351
            $dereferencer,
352
            $zend_type_reader,
353
            $memory_locations,
354
            $context_pools,
355
            $memory_limit_error_details,
356
        );
357
358
        $defined_classes_context = $this->collectClassTable(
359
            $class_table,
360
            $cg->map_ptr_base,
361
            $dereferencer,
362
            $zend_type_reader,
363
            $memory_locations,
364
            $context_pools,
365
        );
366
367
        $global_constants_context = $this->collectGlobalConstants(
368
            $zend_constants,
369
            $cg->map_ptr_base,
370
            $dereferencer,
371
            $zend_type_reader,
372
            $memory_locations,
373
            $context_pools,
374
        );
375
376
        $objects_store_context = $this->collectObjectsStore(
377
            $eg->objects_store,
378
            $cg->map_ptr_base,
379
            $dereferencer,
380
            $zend_type_reader,
381
            $memory_locations,
382
            $context_pools,
383
        );
384
385
        if ($memory_limit_error_details and !is_null($this->memory_limit_error_function_context)) {
386
            $call_frames_context = $this->collectRealCallStackOnMemoryLimitViolation(
387
                $this->memory_limit_error_function_context,
388
                $memory_limit_error_details->max_challenge_depth,
389
                $call_frames_context,
390
                $eg,
391
                $cg->map_ptr_base,
392
                $dereferencer,
393
                $zend_type_reader,
394
                $memory_locations,
395
                $context_pools,
396
            );
397
        }
398
399
        $top_reference_context = new TopReferenceContext(
400
            $call_frames_context,
401
            $global_variables_context,
402
            $defined_functions_context,
403
            $defined_classes_context,
404
            $global_constants_context,
405
            $included_files_context,
406
            $interned_strings_context,
407
            $objects_store_context,
408
        );
409
410
        return new CollectedMemories(
411
            $chunk_memory_locations,
412
            $huge_memory_locations,
413
            $vm_stack_memory_locations,
414
            $compiler_arena_memory_locations,
415
            $cached_chunks_size,
416
            $memory_locations,
417
            $top_reference_context,
418
            $memory_get_usage_size,
419
            $memory_get_usage_real_size,
420
        );
421
    }
422
423
    public function collectZval(
424
        Zval $zval,
425
        int $map_ptr_base,
426
        Dereferencer $dereferencer,
427
        ZendTypeReader $zend_type_reader,
428
        MemoryLocations $memory_locations,
429
        ContextPools $context_pools
430
    ): ?ReferenceContext {
431
        if ($zval->isArray()) {
432
            assert(!is_null($zval->value->arr));
433
            return $this->collectZendArrayPointer(
434
                $zval->value->arr,
435
                $map_ptr_base,
436
                $memory_locations,
437
                $dereferencer,
438
                $zend_type_reader,
439
                $context_pools,
440
            );
441
        } elseif ($zval->isObject()) {
442
            assert(!is_null($zval->value->obj));
443
            return $this->collectZendObjectPointer(
444
                $zval->value->obj,
445
                $map_ptr_base,
446
                $memory_locations,
447
                $dereferencer,
448
                $zend_type_reader,
449
                $context_pools,
450
            );
451
        } elseif ($zval->isString()) {
452
            assert(!is_null($zval->value->str));
453
            return $this->collectZendStringPointer(
454
                $zval->value->str,
455
                $memory_locations,
456
                $dereferencer,
457
                $context_pools,
458
            );
459
        } elseif (
460
            $zval->isBool()
461
            or $zval->isLong()
462
            or $zval->isDouble()
463
            or $zval->isNull()
464
        ) {
465
            return match ($zval->getType()) {
466
                'IS_TRUE' => new ScalarValueContext(true),
467
                'IS_FALSE' => new ScalarValueContext(false),
468
                'IS_LONG' => new ScalarValueContext($zval->value->lval),
469
                'IS_DOUBLE' => new ScalarValueContext($zval->value->dval),
470
                'IS_NULL' => new ScalarValueContext(null),
471
            };
472
        } elseif ($zval->isReference()) {
473
            assert(!is_null($zval->value->ref));
474
            return $this->collectPhpReferencePointer(
475
                $zval->value->ref,
476
                $map_ptr_base,
477
                $memory_locations,
478
                $dereferencer,
479
                $zend_type_reader,
480
                $context_pools,
481
            );
482
        } elseif ($zval->isResource()) {
483
            assert(!is_null($zval->value->res));
484
            return $this->collectResourcePointer(
485
                $zval->value->res,
486
                $memory_locations,
487
                $dereferencer,
488
                $context_pools,
489
            );
490
        } elseif ($zval->isIndirect()) {
491
            $zval = $dereferencer->deref(
492
                $zval->value->getAsPointer(Zval::class, $zend_type_reader->sizeOf('zval'))
493
            );
494
            return $this->collectZval(
495
                $zval,
496
                $map_ptr_base,
497
                $dereferencer,
498
                $zend_type_reader,
499
                $memory_locations,
500
                $context_pools,
501
            );
502
        }
503
        return null;
504
    }
505
506
    /** @param Pointer<ZendResource> $pointer */
507
    public function collectResourcePointer(
508
        Pointer $pointer,
509
        MemoryLocations $memory_locations,
510
        Dereferencer $dereferencer,
511
        ContextPools $context_pools
512
    ): ResourceContext {
513
        if ($memory_locations->has($pointer->address)) {
514
            $memory_location = $memory_locations->get($pointer->address);
515
            if ($memory_location instanceof ZendResourceMemoryLocation) {
516
                return $context_pools
517
                    ->resource_context_pool
518
                    ->getContextForLocation($memory_location)
519
                ;
520
            }
521
        }
522
        $resource = $dereferencer->deref($pointer);
523
        $memory_location = ZendResourceMemoryLocation::fromZendReference($resource);
524
        $memory_locations->add($memory_location);
525
        return $context_pools
526
            ->resource_context_pool
527
            ->getContextForLocation($memory_location)
528
        ;
529
    }
530
531
532
    /** @param Pointer<ZendReference> $pointer */
533
    public function collectPhpReferencePointer(
534
        Pointer $pointer,
535
        int $map_ptr_base,
536
        MemoryLocations $memory_locations,
537
        Dereferencer $dereferencer,
538
        ZendTypeReader $zend_type_reader,
539
        ContextPools $context_pools
540
    ): PhpReferenceContext {
541
        if ($memory_locations->has($pointer->address)) {
542
            $memory_location = $memory_locations->get($pointer->address);
543
            if ($memory_location instanceof ZendReferenceMemoryLocation) {
544
                return $context_pools
545
                    ->php_reference_context_pool
546
                    ->getContextForLocation($memory_location)
547
                ;
548
            }
549
        }
550
        $php_reference = $dereferencer->deref($pointer);
551
        $memory_location = ZendReferenceMemoryLocation::fromZendReference($php_reference);
552
        $memory_locations->add($memory_location);
553
        $php_referencecontext = $context_pools
554
            ->php_reference_context_pool
555
            ->getContextForLocation($memory_location)
556
        ;
557
        $zval_context = $this->collectZval(
558
            $php_reference->val,
559
            $map_ptr_base,
560
            $dereferencer,
561
            $zend_type_reader,
562
            $memory_locations,
563
            $context_pools,
564
        );
565
        if (!is_null($zval_context)) {
566
            $php_referencecontext->add('referenced', $zval_context);
567
        }
568
        return $php_referencecontext;
569
    }
570
571
    /** @param Pointer<ZendArray> $pointer */
572
    public function collectZendArrayPointer(
573
        Pointer $pointer,
574
        int $map_ptr_base,
575
        MemoryLocations $memory_locations,
576
        Dereferencer $dereferencer,
577
        ZendTypeReader $zend_type_reader,
578
        ContextPools $context_pools
579
    ): ArrayHeaderContext {
580
        if ($memory_locations->has($pointer->address)) {
581
            $memory_location = $memory_locations->get($pointer->address);
582
            if ($memory_location instanceof ZendArrayMemoryLocation) {
583
                return $context_pools
584
                    ->array_context_pool
585
                    ->getContextForLocation($memory_location)
586
                ;
587
            }
588
        }
589
        $array = $dereferencer->deref($pointer);
590
        return $this->collectZendArray(
591
            $array,
592
            $map_ptr_base,
593
            $dereferencer,
594
            $zend_type_reader,
595
            $memory_locations,
596
            $context_pools,
597
        );
598
    }
599
600
    /** @param Pointer<ZendObject> $pointer */
601
    public function collectZendObjectPointer(
602
        Pointer $pointer,
603
        int $map_ptr_base,
604
        MemoryLocations $memory_locations,
605
        Dereferencer $dereferencer,
606
        ZendTypeReader $zend_type_reader,
607
        ContextPools $context_pools
608
    ): ObjectContext {
609
        if ($memory_locations->has($pointer->address)) {
610
            $memory_location = $memory_locations->get($pointer->address);
611
            if ($memory_location instanceof ZendArrayTableOverheadMemoryLocation) {
612
                unset($memory_location);
613
            } else {
614
                assert($memory_location instanceof ZendObjectMemoryLocation);
615
                return $context_pools
616
                    ->object_context_pool
617
                    ->getContextForLocation($memory_location)
618
                    ;
619
            }
620
        }
621
        $obj = $dereferencer->deref($pointer);
622
        return $this->collectZendObject(
623
            $obj,
624
            $map_ptr_base,
625
            $dereferencer,
626
            $zend_type_reader,
627
            $memory_locations,
628
            $context_pools,
629
        );
630
    }
631
632
    /** @param Pointer<ZendString> $pointer */
633
    public function collectZendStringPointer(
634
        Pointer $pointer,
635
        MemoryLocations $memory_locations,
636
        Dereferencer $dereferencer,
637
        ContextPools $context_pools
638
    ): StringContext {
639
        if ($memory_locations->has($pointer->address)) {
640
            $memory_location = $memory_locations->get($pointer->address);
641
            if ($memory_location instanceof ZendArrayTableOverheadMemoryLocation) {
642
                $memory_location = null;
643
            } else {
644
                assert($memory_location instanceof ZendStringMemoryLocation);
645
            }
646
        }
647
        if (!isset($memory_location)) {
648
            $str = $dereferencer->deref($pointer);
649
            $memory_location = ZendStringMemoryLocation::fromZendString(
650
                $str,
651
                $dereferencer,
652
            );
653
            $memory_locations->add($memory_location);
654
        }
655
        assert($memory_location instanceof ZendStringMemoryLocation);
656
        return $context_pools
657
            ->string_context_pool
658
            ->getContextForLocation($memory_location)
659
        ;
660
    }
661
662
    public function collectCallFrames(
663
        ZendExecutorGlobals $eg,
664
        int $map_ptr_base,
665
        Dereferencer $dereferencer,
666
        ZendTypeReader $zend_type_reader,
667
        MemoryLocations $memory_locations,
668
        ContextPools $context_pools,
669
    ): CallFramesContext {
670
        $call_frames_context = new CallFramesContext();
671
        if (is_null($eg->current_execute_data)) {
672
            return $call_frames_context;
673
        }
674
        $execute_data = $dereferencer->deref($eg->current_execute_data);
675
        foreach ($execute_data->iterateStackChain($dereferencer) as $key => $execute_data) {
676
            $call_frame_context = $this->collectCallFrame(
677
                $execute_data,
678
                $map_ptr_base,
679
                $dereferencer,
680
                $zend_type_reader,
681
                $memory_locations,
682
                $context_pools,
683
            );
684
            $call_frames_context->add((string)$key, $call_frame_context);
685
        }
686
        return $call_frames_context;
687
    }
688
689
    public function collectRealCallStackOnMemoryLimitViolation(
690
        UserFunctionDefinitionContext $memory_limit_error_function_context,
691
        int $max_challenge_depth,
692
        CallFramesContext $call_frames_context,
693
        ZendExecutorGlobals $eg,
694
        int $map_ptr_base,
695
        Dereferencer $dereferencer,
696
        ZendTypeReader $zend_type_reader,
697
        MemoryLocations $memory_locations,
698
        ContextPools $context_pools,
699
    ): CallFramesContext {
700
        $op_array_address = $memory_limit_error_function_context->getOpArrayAddress();
701
702
        if (is_null($eg->vm_stack)) {
703
            return $call_frames_context;
704
        }
705
        if (is_null($eg->vm_stack_top)) {
706
            return $call_frames_context;
707
        }
708
709
        $last_vm_stack = $dereferencer->deref($eg->vm_stack);
710
        $root_vm_stack = $last_vm_stack->getRootStack($dereferencer);
711
        if (is_null($root_vm_stack->top)) {
712
            return $call_frames_context;
713
        }
714
715
        $first_stack = true;
716
        foreach ($last_vm_stack->iterateStackChain($dereferencer) as $vm_stack) {
717
            if ($first_stack) {
718
                $first_stack = false;
719
                $stack_end_address = $eg->vm_stack_top->address;
720
            } else {
721
                if (is_null($vm_stack->end)) {
722
                    break;
723
                }
724
                $stack_end_address = $vm_stack->end->address;
725
            }
726
            $materialized_vm_stack = $vm_stack->materializeAsPointerArray(
727
                $dereferencer,
728
                $stack_end_address
729
            );
730
            foreach ($materialized_vm_stack->getReverseIteratorAsInt() as $key => $value) {
731
                if ($value !== $op_array_address) {
732
                    continue;
733
                }
734
                $pointer_address = $key * 8 + $materialized_vm_stack->getPointer()->address - 24;
735
                Log::debug('candidate frame found', ['frame_address' => $pointer_address]);
736
                $frame_candidate = new Pointer(
737
                    ZendExecuteData::class,
738
                    $pointer_address,
739
                    $zend_type_reader->sizeOf('zend_execute_data')
740
                );
741
                try {
742
                    $execute_data_candidate = $dereferencer->deref($frame_candidate);
743
                    $root_execute_data_candidate = $execute_data_candidate->getRootFrame(
744
                        $dereferencer,
745
                        $max_challenge_depth,
746
                    );
747
                    if ($root_vm_stack->top->address !== $root_execute_data_candidate->getPointer()->address) {
748
                        continue;
749
                    }
750
                    Log::debug('root candidate frame found', ['frame_address' => $root_vm_stack->top->address]);
751
                    $frame_start = count($call_frames_context->getLinks());
752
                    foreach ($execute_data_candidate->iterateStackChain($dereferencer) as $frame_no => $execute_data) {
753
                        $call_frame_context = $this->collectCallFrame(
754
                            $execute_data,
755
                            $map_ptr_base,
756
                            $dereferencer,
757
                            $zend_type_reader,
758
                            $memory_locations,
759
                            $context_pools,
760
                        );
761
                        $call_frames_context->add((string)($frame_no + $frame_start), $call_frame_context);
762
                    }
763
                    return $call_frames_context;
764
                } catch (\Throwable $e) {
765
                    Log::debug(
766
                        'failed to collect real call stack from this candidate',
767
                        [
768
                            'exception' => $e,
769
                            'frame_address' => $pointer_address
770
                        ]
771
                    );
772
                    continue;
773
                }
774
            }
775
        }
776
        return $call_frames_context;
777
    }
778
779
    public function collectCallFrame(
780
        ZendExecuteData $execute_data,
781
        int $map_ptr_base,
782
        Dereferencer $dereferencer,
783
        ZendTypeReader $zend_type_reader,
784
        MemoryLocations $memory_locations,
785
        ContextPools $context_pools,
786
    ): CallFrameContext {
787
        $function_name = $execute_data->getFullyQualifiedFunctionName(
788
            $dereferencer,
789
            $zend_type_reader,
790
        );
791
792
        $lineno = -1;
793
        if ($execute_data->opline !== null and !$execute_data->isInternalCall($dereferencer)) {
794
            $opline = $dereferencer->deref($execute_data->opline);
795
            $lineno = $opline->lineno;
796
        }
797
798
        $header_memory_location = CallFrameHeaderMemoryLocation::fromZendExecuteData(
799
            $execute_data,
800
        );
801
        $call_frame_context = new CallFrameContext(
802
            $function_name,
803
            $lineno,
804
        );
805
        $variable_table_memory_location = CallFrameVariableTableMemoryLocation::fromZendExecuteData(
806
            $execute_data,
807
            $dereferencer
808
        );
809
        $memory_locations->add($variable_table_memory_location);
810
        $memory_locations->add($header_memory_location);
811
812
        if ($execute_data->hasThis()) {
813
            $this_context = $this->collectZval(
814
                $execute_data->This,
815
                $map_ptr_base,
816
                $dereferencer,
817
                $zend_type_reader,
818
                $memory_locations,
819
                $context_pools,
820
            );
821
            if (!is_null($this_context)) {
822
                $call_frame_context->add('this', $this_context);
823
            }
824
        }
825
826
        $has_local_variables = false;
827
        $variable_table_context = new CallFrameVariableTableContext();
828
        $local_variables_iterator = $execute_data->getVariables($dereferencer, $zend_type_reader);
829
        foreach ($local_variables_iterator as $name => $value) {
830
            $local_variable_context = $this->collectZval(
831
                $value,
832
                $map_ptr_base,
833
                $dereferencer,
834
                $zend_type_reader,
835
                $memory_locations,
836
                $context_pools,
837
            );
838
            if (!is_null($local_variable_context)) {
839
                $variable_table_context->add($name, $local_variable_context);
840
                $has_local_variables = true;
841
            }
842
        }
843
        if ($has_local_variables) {
844
            $call_frame_context->add('local_variables', $variable_table_context);
845
        }
846
847
        if ($execute_data->hasSymbolTable() and !is_null($execute_data->symbol_table)) {
848
            $symbol_table_context = $this->collectZendArrayPointer(
849
                $execute_data->symbol_table,
850
                $map_ptr_base,
851
                $memory_locations,
852
                $dereferencer,
853
                $zend_type_reader,
854
                $context_pools,
855
            );
856
            $call_frame_context->add('symbol_table', $symbol_table_context);
857
        }
858
        if ($execute_data->hasExtraNamedParams() and !is_null($execute_data->extra_named_params)) {
859
            $extra_named_params_context = $this->collectZendArrayPointer(
860
                $execute_data->extra_named_params,
861
                $map_ptr_base,
862
                $memory_locations,
863
                $dereferencer,
864
                $zend_type_reader,
865
                $context_pools,
866
            );
867
            $call_frame_context->add('extra_named_params', $extra_named_params_context);
868
        }
869
        return $call_frame_context;
870
    }
871
872
    public function collectGlobalVariables(
873
        ZendArray $array,
874
        int $map_ptr_base,
875
        Dereferencer $dereferencer,
876
        ZendTypeReader $zend_type_reader,
877
        MemoryLocations $memory_locations,
878
        ContextPools $context_pools
879
    ): GlobalVariablesContext {
880
        return GlobalVariablesContext::fromArrayContext(
881
            $this->collectZendArray(
882
                $array,
883
                $map_ptr_base,
884
                $dereferencer,
885
                $zend_type_reader,
886
                $memory_locations,
887
                $context_pools,
888
            )
889
        );
890
    }
891
892
    public function collectZendArray(
893
        ZendArray $array,
894
        int $map_ptr_base,
895
        Dereferencer $dereferencer,
896
        ZendTypeReader $zend_type_reader,
897
        MemoryLocations $memory_locations,
898
        ContextPools $context_pools
899
    ): ArrayHeaderContext {
900
        $array_header_location = ZendArrayMemoryLocation::fromZendArray($array);
901
        $array_table_location = ZendArrayTableMemoryLocation::fromZendArray($array);
902
        $array_table_overhead_location = ZendArrayTableOverheadMemoryLocation::fromZendArrayAndUsedLocation(
903
            $array,
904
            $array_table_location
905
        );
906
907
        $memory_locations->add($array_header_location);
908
        $memory_locations->add($array_table_location);
909
        $memory_locations->add($array_table_overhead_location);
910
911
        $array_header_context = $context_pools
912
            ->array_context_pool
913
            ->getContextForLocation($array_header_location)
914
        ;
915
        $array_context = new ArrayElementsContext($array_table_location);
916
        $overhead_context = new ArrayPossibleOverheadContext($array_table_overhead_location);
917
918
        foreach ($array->getItemIteratorWithZendStringKeyIfAssoc($dereferencer) as $key => $zval) {
919
            $element_context = new ArrayElementContext();
920
            if ($key instanceof Pointer) {
921
                $key_context = $this->collectZendStringPointer(
922
                    $key,
923
                    $memory_locations,
924
                    $dereferencer,
925
                    $context_pools,
926
                );
927
                $zend_string = $dereferencer->deref($key);
928
                $key_string = $zend_string->toString($dereferencer);
929
                $element_context->add('key', $key_context);
930
            } else {
931
                $key_string = (string)$key;
932
            }
933
            $array_context->add($key_string, $element_context);
934
            $value_context = $this->collectZval(
935
                $zval,
936
                $map_ptr_base,
937
                $dereferencer,
938
                $zend_type_reader,
939
                $memory_locations,
940
                $context_pools,
941
            );
942
            if (!is_null($value_context)) {
943
                $element_context->add('value', $value_context);
944
            }
945
        }
946
        $array_header_context->add('possible_unused_area', $overhead_context);
947
        $array_header_context->add('array_elements', $array_context);
948
        return $array_header_context;
949
    }
950
951
    public function collectZendObject(
952
        ZendObject $object,
953
        int $map_ptr_base,
954
        Dereferencer $dereferencer,
955
        ZendTypeReader $zend_type_reader,
956
        MemoryLocations $memory_locations,
957
        ContextPools $context_pools
958
    ): ObjectContext {
959
        $object_location = ZendObjectMemoryLocation::fromZendObject(
960
            $object,
961
            $dereferencer,
962
            $zend_type_reader,
963
        );
964
        $object_handlers_memory_location = ZendObjectHandlersMemoryLocation::fromZendObject(
965
            $object,
966
            $zend_type_reader,
967
        );
968
        $memory_locations->add($object_location);
969
        $memory_locations->add($object_handlers_memory_location);
970
971
        $object_context = $context_pools
972
            ->object_context_pool->getContextForLocation(
973
                $object_location,
974
            )
975
        ;
976
        $object_handlers_context = $context_pools
977
            ->object_context_pool
978
            ->getHandlersContextForLocation(
979
                $object_handlers_memory_location,
980
            )
981
        ;
982
        $object_context->add('object_handlers', $object_handlers_context);
983
984
        $properties_exists = false;
985
        $object_properties_context = new ObjectPropertiesContext();
986
        $properties_iterator = $object->getPropertiesIterator(
987
            $dereferencer,
988
            $zend_type_reader,
989
        );
990
        foreach ($properties_iterator as $name => $property) {
991
            assert(is_string($name));
992
            $property_context = $this->collectZval(
993
                $property,
994
                $map_ptr_base,
995
                $dereferencer,
996
                $zend_type_reader,
997
                $memory_locations,
998
                $context_pools,
999
            );
1000
            if (!is_null($property_context)) {
1001
                $object_properties_context->add($name, $property_context);
1002
                $properties_exists = true;
1003
            }
1004
        }
1005
        if ($properties_exists) {
1006
            $object_context->add('object_properties', $object_properties_context);
1007
        }
1008
1009
        if (
1010
            !is_null($object->properties)
1011
            and !is_null($object->ce)
1012
            and !$object->isEnum($dereferencer)
1013
        ) {
1014
            $dynamic_properties_context = $this->collectZendArray(
1015
                $dereferencer->deref($object->properties),
1016
                $map_ptr_base,
1017
                $dereferencer,
1018
                $zend_type_reader,
1019
                $memory_locations,
1020
                $context_pools,
1021
            );
1022
            $object_context->add('dynamic_properties', $dynamic_properties_context);
1023
        }
1024
1025
        assert(!is_null($object->ce));
1026
        $class_entry = $dereferencer->deref($object->ce);
1027
        if ($class_entry->getClassName($dereferencer) === 'Closure') {
1028
            $closure_context = $this->collectClosure(
1029
                $dereferencer->deref(
1030
                    ZendClosure::getPointerFromZendObjectPointer(
1031
                        $object->getPointer(),
1032
                        $zend_type_reader,
1033
                    ),
1034
                ),
1035
                $map_ptr_base,
1036
                $dereferencer,
1037
                $zend_type_reader,
1038
                $memory_locations,
1039
                $context_pools,
1040
            );
1041
            $object_context->add('closure', $closure_context);
1042
        }
1043
1044
        return $object_context;
1045
    }
1046
1047
    public function collectClosure(
1048
        ZendClosure $zend_closure,
1049
        int $map_ptr_base,
1050
        Dereferencer $dereferencer,
1051
        ZendTypeReader $zend_type_reader,
1052
        MemoryLocations $memory_locations,
1053
        ContextPools $context_pools,
1054
    ): ClosureContext {
1055
        $closure_context = new ClosureContext();
1056
        $closure_context->add(
1057
            'func',
1058
            $this->collectZendFunctionPointer(
1059
                $zend_closure->func->getPointer(),
1060
                $map_ptr_base,
1061
                $dereferencer,
1062
                $zend_type_reader,
1063
                $memory_locations,
1064
                $context_pools,
1065
            )
1066
        );
1067
        $zval_context = $this->collectZval(
1068
            $zend_closure->this_ptr,
1069
            $map_ptr_base,
1070
            $dereferencer,
1071
            $zend_type_reader,
1072
            $memory_locations,
1073
            $context_pools,
1074
        );
1075
        if (!is_null($zval_context)) {
1076
            $closure_context->add(
1077
                'this_ptr',
1078
                $zval_context,
1079
            );
1080
        }
1081
        return $closure_context;
1082
    }
1083
1084
    public function collectFunctionTable(
1085
        ZendArray $array,
1086
        int $map_ptr_base,
1087
        Dereferencer $dereferencer,
1088
        ZendTypeReader $zend_type_reader,
1089
        MemoryLocations $memory_locations,
1090
        ContextPools $context_pools,
1091
        MemoryLimitErrorDetails $memory_limit_error_details = null,
1092
    ): DefinedFunctionsContext {
1093
        $array_header_location = ZendArrayMemoryLocation::fromZendArray($array);
1094
        $array_table_location = ZendArrayTableMemoryLocation::fromZendArray($array);
1095
        $array_table_overhead_location = ZendArrayTableOverheadMemoryLocation::fromZendArrayAndUsedLocation(
1096
            $array,
1097
            $array_table_location
1098
        );
1099
1100
        $memory_locations->add($array_header_location);
1101
        $memory_locations->add($array_table_location);
1102
        $memory_locations->add($array_table_overhead_location);
1103
1104
        $defined_functions_context = new DefinedFunctionsContext(
1105
            $array_header_location,
1106
            $array_table_location,
1107
        );
1108
1109
        foreach ($array->getItemIterator($dereferencer) as $function_name => $zval) {
1110
            assert(is_string($function_name));
1111
            assert(!is_null($zval->value->func));
1112
            $function_context = $this->collectZendFunctionPointer(
1113
                $zval->value->func,
1114
                $map_ptr_base,
1115
                $dereferencer,
1116
                $zend_type_reader,
1117
                $memory_locations,
1118
                $context_pools,
1119
                $memory_limit_error_details,
1120
            );
1121
            $defined_functions_context->add($function_name, $function_context);
1122
        }
1123
        return $defined_functions_context;
1124
    }
1125
1126
    /** @param Pointer<ZendFunction> $pointer */
1127
    public function collectZendFunctionPointer(
1128
        Pointer $pointer,
1129
        int $map_ptr_base,
1130
        Dereferencer $dereferencer,
1131
        ZendTypeReader $zend_type_reader,
1132
        MemoryLocations $memory_locations,
1133
        ContextPools $context_pools,
1134
        MemoryLimitErrorDetails $memory_limit_error_details = null,
1135
    ): FunctionDefinitionContext {
1136
        if ($memory_locations->has($pointer->address)) {
1137
            $memory_location = $memory_locations->get($pointer->address);
1138
            if ($memory_location instanceof ZendOpArrayHeaderMemoryLocation) {
1139
                return $context_pools
1140
                    ->user_function_definition_context_pool
1141
                    ->getContextForLocation($memory_location)
1142
                ;
1143
            }
1144
        }
1145
        $func = $dereferencer->deref($pointer);
1146
        return $this->collectZendFunction(
1147
            $func,
1148
            $map_ptr_base,
1149
            $dereferencer,
1150
            $zend_type_reader,
1151
            $memory_locations,
1152
            $context_pools,
1153
            $memory_limit_error_details,
1154
        );
1155
    }
1156
1157
    public function collectZendFunction(
1158
        ZendFunction $func,
1159
        int $map_ptr_base,
1160
        Dereferencer $dereferencer,
1161
        ZendTypeReader $zend_type_reader,
1162
        MemoryLocations $memory_locations,
1163
        ContextPools $context_pools,
1164
        MemoryLimitErrorDetails $memory_limit_error_details = null,
1165
    ): FunctionDefinitionContext {
1166
        if ($func->isUserFunction()) {
1167
            $function_definition_context = $this->collectUserFunctionDefinition(
1168
                $func,
1169
                $map_ptr_base,
1170
                $dereferencer,
1171
                $zend_type_reader,
1172
                $memory_locations,
1173
                $context_pools,
1174
                $memory_limit_error_details,
1175
            );
1176
        } else {
1177
            $function_definition_context = new InternalFunctionDefinitionContext();
1178
        }
1179
        if (!is_null($func->function_name)) {
1180
            $function_name_context = $this->collectZendStringPointer(
1181
                $func->function_name,
1182
                $memory_locations,
1183
                $dereferencer,
1184
                $context_pools,
1185
            );
1186
            $function_definition_context->add('name', $function_name_context);
1187
        }
1188
        return $function_definition_context;
1189
    }
1190
1191
    public function collectUserFunctionDefinition(
1192
        ZendFunction $func,
1193
        int $map_ptr_base,
1194
        Dereferencer $dereferencer,
1195
        ZendTypeReader $zend_type_reader,
1196
        MemoryLocations $memory_locations,
1197
        ContextPools $context_pools,
1198
        MemoryLimitErrorDetails $memory_limit_error_details = null,
1199
    ): UserFunctionDefinitionContext {
1200
        $function_name = $func->getFullyQualifiedFunctionName(
1201
            $dereferencer,
1202
            $zend_type_reader,
1203
        );
1204
        $op_array_header_memory_location = ZendOpArrayHeaderMemoryLocation::fromZendFunction(
1205
            $func,
1206
            $zend_type_reader,
1207
            $dereferencer,
1208
        );
1209
        $op_array_body_memory_location = ZendOpArrayBodyMemoryLocation::fromZendFunction(
1210
            $func,
1211
            $zend_type_reader,
1212
            $function_name
1213
        );
1214
        $memory_locations->add($op_array_header_memory_location);
1215
        $memory_locations->add($op_array_body_memory_location);
1216
        $function_definition_context = $context_pools
1217
            ->user_function_definition_context_pool
1218
            ->getContextForLocation($op_array_header_memory_location)
1219
        ;
1220
        $op_array_context = new OpArrayContext(
1221
            $op_array_header_memory_location,
1222
            $op_array_body_memory_location,
1223
        );
1224
        $function_definition_context->add('op_array', $op_array_context);
1225
1226
        if ($func->op_array->cache_size > 0) {
1227
            $runtime_cache_memory_location = RuntimeCacheMemoryLocation::fromZendOpArray(
1228
                $func->op_array,
1229
                $dereferencer,
1230
                $zend_type_reader,
1231
                $map_ptr_base,
1232
            );
1233
            if ($runtime_cache_memory_location->address !== 0) {
1234
                $memory_locations->add($runtime_cache_memory_location);
1235
                $run_time_cache_context = new RuntimeCacheContext($runtime_cache_memory_location);
1236
                $op_array_context->add('run_time_cache', $run_time_cache_context);
1237
            }
1238
        }
1239
1240
        if (!is_null($func->op_array->arg_info)) {
1241
            $arginfos_memory_location = ZendArgInfosMemoryLocation::fromZendOpArray(
1242
                $func->op_array,
1243
                $zend_type_reader,
1244
            );
1245
            $memory_locations->add($arginfos_memory_location);
1246
            $arginfos_context = new ArgInfosContext($arginfos_memory_location);
1247
            $op_array_context->add('arg_infos', $arginfos_context);
1248
            foreach ($func->op_array->iterateArgInfo($dereferencer, $zend_type_reader) as $arg_info) {
1249
                if (!is_null($arg_info->name)) {
1250
                    $arg_info_context = new ArgInfoContext();
1251
                    $arg_info_name_context = $this->collectZendStringPointer(
1252
                        $arg_info->name,
1253
                        $memory_locations,
1254
                        $dereferencer,
1255
                        $context_pools,
1256
                    );
1257
                    $arg_info_name = $dereferencer
1258
                        ->deref($arg_info->name)
1259
                        ->toString($dereferencer)
1260
                    ;
1261
                    $arg_info_context->add('name', $arg_info_name_context);
1262
                    $arginfos_context->add($arg_info_name, $arg_info_context);
1263
                }
1264
            }
1265
        }
1266
1267
        if (!is_null($func->op_array->doc_comment)) {
1268
            $doc_comment_context = $this->collectZendStringPointer(
1269
                $func->op_array->doc_comment,
1270
                $memory_locations,
1271
                $dereferencer,
1272
                $context_pools,
1273
            );
1274
            $op_array_context->add('doc_comment', $doc_comment_context);
1275
        }
1276
1277
        if (!is_null($func->op_array->filename)) {
1278
            $file_name_context = $this->collectZendStringPointer(
1279
                $func->op_array->filename,
1280
                $memory_locations,
1281
                $dereferencer,
1282
                $context_pools,
1283
            );
1284
            $op_array_context->add('filename', $file_name_context);
1285
        }
1286
1287
        if (!is_null($func->op_array->static_variables)) {
1288
            $static_variables_context = $this->collectZendArray(
1289
                $dereferencer->deref($func->op_array->static_variables),
1290
                $map_ptr_base,
1291
                $dereferencer,
1292
                $zend_type_reader,
1293
                $memory_locations,
1294
                $context_pools,
1295
            );
1296
            $op_array_context->add('static_variables', $static_variables_context);
1297
        }
1298
1299
        if (!is_null($func->op_array->vars)) {
1300
            $local_variable_name_table_location = LocalVariableNameTableMemoryLocation::fromZendOpArray(
1301
                $func->op_array
1302
            );
1303
            $memory_locations->add($local_variable_name_table_location);
1304
            $variable_name_table_context = new LocalVariableNameTableContext(
1305
                $local_variable_name_table_location
1306
            );
1307
            $op_array_context->add('variable_name_table', $variable_name_table_context);
1308
1309
            $variable_names_iterator = $func->op_array->getVariableNamesAsIteratorOfPointersToZendStrings(
1310
                $dereferencer,
1311
                $zend_type_reader,
1312
            );
1313
            foreach ($variable_names_iterator as $key => $variable_name) {
1314
                $variable_name_context = $this->collectZendStringPointer(
1315
                    $variable_name,
1316
                    $memory_locations,
1317
                    $dereferencer,
1318
                    $context_pools,
1319
                );
1320
                $variable_name_table_context->add((string)$key, $variable_name_context);
1321
            }
1322
        }
1323
1324
        if ($func->op_array->num_dynamic_func_defs > 0) {
1325
            $dynamic_func_defs_table_memory_location = DynamicFuncDefsTableMemoryLocation::fromZendOpArray(
1326
                $func->op_array,
1327
            );
1328
            $memory_locations->add($dynamic_func_defs_table_memory_location);
1329
            $dynamic_func_defs_context = new DynamicFuncDefsContext(
1330
                $dynamic_func_defs_table_memory_location
1331
            );
1332
            $dynamic_func_defs_iterator = $func->op_array->iterateDynamicFunctionDefinitions(
1333
                $dereferencer,
1334
                $zend_type_reader,
1335
            );
1336
            foreach ($dynamic_func_defs_iterator as $key => $dynamic_func_def) {
1337
                $dynamic_function_context = $this->collectZendFunctionPointer(
1338
                    $dynamic_func_def,
1339
                    $map_ptr_base,
1340
                    $dereferencer,
1341
                    $zend_type_reader,
1342
                    $memory_locations,
1343
                    $context_pools,
1344
                    $memory_limit_error_details,
1345
                );
1346
                $dynamic_func_defs_context->add((string)$key, $dynamic_function_context);
1347
            }
1348
            $op_array_context->add('dynamic_function_definitions', $dynamic_func_defs_context);
1349
        }
1350
1351
        if (!is_null($memory_limit_error_details)) {
1352
            if (
1353
                $function_definition_context->isThisContext(
1354
                    $memory_limit_error_details->file,
1355
                    $memory_limit_error_details->line,
1356
                )
1357
            ) {
1358
                if (
1359
                    is_null($this->memory_limit_error_function_context)
1360
                    or $function_definition_context->isClosureOf($this->memory_limit_error_function_context)
1361
                ) {
1362
                    $this->memory_limit_error_function_context = $function_definition_context;
1363
                }
1364
            }
1365
        }
1366
        return $function_definition_context;
1367
    }
1368
1369
    public function collectClassConstantsTable(
1370
        ZendArray $array,
1371
        int $map_ptr_base,
1372
        Dereferencer $dereferencer,
1373
        ZendTypeReader $zend_type_reader,
1374
        MemoryLocations $memory_locations,
1375
        ContextPools $context_pools
1376
    ): ClassConstantsContext {
1377
        $array_table_location = ZendArrayTableMemoryLocation::fromZendArray($array);
1378
        $array_table_overhead_location = ZendArrayTableOverheadMemoryLocation::fromZendArrayAndUsedLocation(
1379
            $array,
1380
            $array_table_location
1381
        );
1382
        $memory_locations->add($array_table_location);
1383
        $memory_locations->add($array_table_overhead_location);
1384
        $class_constants_context = new ClassConstantsContext($array_table_location);
1385
1386
        $array_iterator = $array->getItemIteratorWithZendStringKeyIfAssoc($dereferencer);
1387
        foreach ($array_iterator as $constant_name => $zval_or_ptr) {
1388
            assert($constant_name instanceof Pointer);
1389
            $constant_name_context = $this->collectZendStringPointer(
1390
                $constant_name,
1391
                $memory_locations,
1392
                $dereferencer,
1393
                $context_pools,
1394
            );
1395
            $zend_string = $dereferencer->deref($constant_name);
1396
            $constant_name_string = $zend_string->toString($dereferencer);
1397
            $constant_context = new ClassConstantContext();
1398
            $class_constants_context->add($constant_name_string, $constant_context);
1399
            $constant_context->add('name', $constant_name_context);
1400
1401
            if ($zend_type_reader->isPhpVersionLowerThan(ZendTypeReader::V71)) {
1402
                $zval = $zval_or_ptr;
1403
            } else {
1404
                $class_constant_ptr = $zval_or_ptr->value->getAsPointer(
1405
                    ZendClassConstant::class,
1406
                    $zend_type_reader->sizeOf(ZendClassConstant::getCTypeName()),
1407
                );
1408
                $class_constant = $dereferencer->deref(
1409
                    $class_constant_ptr
1410
                );
1411
                $memory_location = ZendClassConstantMemoryLocation::fromZendClassConstant(
1412
                    $class_constant,
1413
                );
1414
                $memory_locations->add($memory_location);
1415
                $zval = $class_constant->value;
1416
                $info_context = new ClassConstantInfoContext($memory_location);
1417
                $constant_context->add('info', $info_context);
1418
            }
1419
            $value_context = $this->collectZval(
1420
                $zval,
1421
                $map_ptr_base,
1422
                $dereferencer,
1423
                $zend_type_reader,
1424
                $memory_locations,
1425
                $context_pools,
1426
            );
1427
            if (!is_null($value_context)) {
1428
                $constant_context->add('value', $value_context);
1429
            }
1430
        }
1431
1432
        return $class_constants_context;
1433
    }
1434
1435
    public function collectClassTable(
1436
        ZendArray $array,
1437
        int $map_ptr_base,
1438
        Dereferencer $dereferencer,
1439
        ZendTypeReader $zend_type_reader,
1440
        MemoryLocations $memory_locations,
1441
        ContextPools $context_pools,
1442
        ?MemoryLimitErrorDetails $memory_limit_error_details = null,
1443
    ): DefinedClassesContext {
1444
        $defined_classes_context = new DefinedClassesContext();
1445
        foreach ($array->getItemIterator($dereferencer) as $class_name => $zval) {
1446
            assert(!is_null($zval->value->ce));
1447
            $class_definition_context = $this->collectClassDefinitionPointer(
1448
                $zval->value->ce,
1449
                $map_ptr_base,
1450
                $dereferencer,
1451
                $zend_type_reader,
1452
                $memory_locations,
1453
                $context_pools,
1454
                $memory_limit_error_details,
1455
            );
1456
            if (!is_null($class_definition_context)) {
1457
                $defined_classes_context->add((string)$class_name, $class_definition_context);
1458
            }
1459
        }
1460
        return $defined_classes_context;
1461
    }
1462
1463
    /** @param Pointer<ZendClassEntry> $pointer */
1464
    private function collectClassDefinitionPointer(
1465
        Pointer $pointer,
1466
        int $map_ptr_base,
1467
        Dereferencer $dereferencer,
1468
        ZendTypeReader $zend_type_reader,
1469
        MemoryLocations $memory_locations,
1470
        ContextPools $context_pools,
1471
        ?MemoryLimitErrorDetails $memory_limit_error_details = null,
1472
    ): ?ClassDefinitionContext {
1473
        if ($memory_locations->has($pointer->address)) {
1474
            return null;
1475
        }
1476
        $class_entry = $dereferencer->deref($pointer);
1477
        return $this->collectClassDefinition(
1478
            $class_entry,
1479
            $map_ptr_base,
1480
            $dereferencer,
1481
            $zend_type_reader,
1482
            $memory_locations,
1483
            $context_pools,
1484
            $memory_limit_error_details,
1485
        );
1486
    }
1487
1488
    private function collectClassDefinition(
1489
        ZendClassEntry $class_entry,
1490
        int $map_ptr_base,
1491
        Dereferencer $dereferencer,
1492
        ZendTypeReader $zend_type_reader,
1493
        MemoryLocations $memory_locations,
1494
        ContextPools $context_pools,
1495
        ?MemoryLimitErrorDetails $memory_limit_error_details = null,
1496
    ): ClassDefinitionContext {
1497
        $class_definition_context = new ClassDefinitionContext($class_entry->isInternal());
1498
        $memory_location = ZendClassEntryMemoryLocation::fromZendClassEntry($class_entry);
1499
        $memory_locations->add($memory_location);
1500
        $class_entry_context = new ClassEntryContext($memory_location);
1501
        $class_definition_context->add('class_entry', $class_entry_context);
1502
1503
        $class_name_context = $this->collectZendStringPointer(
1504
            $class_entry->name,
1505
            $memory_locations,
1506
            $dereferencer,
1507
            $context_pools,
1508
        );
1509
        $class_definition_context->add('name', $class_name_context);
1510
1511
        if (!$class_entry->isInternal()) {
1512
            if (!is_null($class_entry->info->user->filename)) {
1513
                $file_name_context = $this->collectZendStringPointer(
1514
                    $class_entry->info->user->filename,
1515
                    $memory_locations,
1516
                    $dereferencer,
1517
                    $context_pools,
1518
                );
1519
                $class_definition_context->add('filename', $file_name_context);
1520
            }
1521
1522
            if (!is_null($class_entry->info->user->doc_comment)) {
1523
                $doc_comment_context = $this->collectZendStringPointer(
1524
                    $class_entry->info->user->doc_comment,
1525
                    $memory_locations,
1526
                    $dereferencer,
1527
                    $context_pools,
1528
                );
1529
                $class_definition_context->add('doc_comment', $doc_comment_context);
1530
            }
1531
        }
1532
1533
        if (
1534
            $class_entry->default_static_members_count > 0
1535
            and !is_null($class_entry->static_members_table)
1536
        ) {
1537
            $static_members_table_memory_location = StaticMembersTableMemoryLocation::fromZendClassEntry(
1538
                $class_entry,
1539
                $zend_type_reader,
1540
                $dereferencer,
1541
                $map_ptr_base,
1542
            );
1543
            $memory_locations->add($static_members_table_memory_location);
1544
            $static_properties_context = new ClassStaticPropertiesContext(
1545
                $static_members_table_memory_location
1546
            );
1547
            $static_property_iterator = $class_entry->getStaticPropertyIterator(
1548
                $dereferencer,
1549
                $zend_type_reader,
1550
                $map_ptr_base,
1551
            );
1552
            foreach ($static_property_iterator as $name => $value) {
1553
                $static_property_context = $this->collectZval(
1554
                    $value,
1555
                    $map_ptr_base,
1556
                    $dereferencer,
1557
                    $zend_type_reader,
1558
                    $memory_locations,
1559
                    $context_pools,
1560
                );
1561
                if (!is_null($static_property_context)) {
1562
                    $static_properties_context->add($name, $static_property_context);
1563
                }
1564
            }
1565
            $class_definition_context->add('static_properties', $static_properties_context);
1566
        }
1567
1568
        $properties_info_context = $this->collectPropertiesInfo(
1569
            $class_entry,
1570
            $dereferencer,
1571
            $zend_type_reader,
1572
            $memory_locations,
1573
            $context_pools,
1574
        );
1575
        $class_definition_context->add('property_info', $properties_info_context);
1576
1577
        if (!is_null($class_entry->default_properties_table)) {
1578
            $default_properties_table_memory_location = DefaultPropertiesTableMemoryLocation::fromZendClassEntry(
1579
                $class_entry,
1580
            );
1581
            $memory_locations->add($default_properties_table_memory_location);
1582
            $default_properties_context = new DefaultPropertiesTableContext(
1583
                $default_properties_table_memory_location
1584
            );
1585
            $class_definition_context->add('default_properties', $default_properties_context);
1586
        }
1587
1588
        if (!is_null($class_entry->default_static_members_table)) {
1589
            $default_static_members_memory_location = DefaultStaticMembersTableMemoryLocation::fromZendClassEntry(
1590
                $class_entry,
1591
            );
1592
            $memory_locations->add($default_static_members_memory_location);
1593
            $default_static_properties_context = new DefaultStaticPropertiesContext(
1594
                $default_static_members_memory_location
1595
            );
1596
            $class_definition_context->add('default_static_properties', $default_static_properties_context);
1597
        }
1598
1599
        $methods_context = $this->collectFunctionTable(
1600
            $class_entry->function_table,
1601
            $map_ptr_base,
1602
            $dereferencer,
1603
            $zend_type_reader,
1604
            $memory_locations,
1605
            $context_pools,
1606
            $memory_limit_error_details,
1607
        );
1608
        $class_definition_context->add('methods', $methods_context);
1609
1610
        $class_constants_context = $this->collectClassConstantsTable(
1611
            $class_entry->constants_table,
1612
            $map_ptr_base,
1613
            $dereferencer,
1614
            $zend_type_reader,
1615
            $memory_locations,
1616
            $context_pools,
1617
        );
1618
        $class_definition_context->add('constants', $class_constants_context);
1619
1620
        return $class_definition_context;
1621
    }
1622
1623
    private function collectPropertiesInfo(
1624
        ZendClassEntry $class_entry,
1625
        Dereferencer $dereferencer,
1626
        ZendTypeReader $zend_type_reader,
1627
        MemoryLocations $memory_locations,
1628
        ContextPools $context_pools
1629
    ): PropertiesInfoContext {
1630
        $memory_location = ZendArrayTableMemoryLocation::fromZendArray($class_entry->properties_info);
1631
        $memory_locations->add($memory_location);
1632
1633
        $properties_info_context = new PropertiesInfoContext($memory_location);
1634
1635
        foreach ($class_entry->iteratePropertyInfo($dereferencer, $zend_type_reader) as $key => $property_info) {
1636
            $property_info_memory_location = ZendPropertyInfoMemoryLocation::fromZendPropertyInfo(
1637
                $property_info,
1638
            );
1639
            $memory_locations->add($property_info_memory_location);
1640
            $property_info_context = new PropertyInfoContext($property_info_memory_location);
1641
            if (!is_null($property_info->name)) {
1642
                $property_info_name_context = $this->collectZendStringPointer(
1643
                    $property_info->name,
1644
                    $memory_locations,
1645
                    $dereferencer,
1646
                    $context_pools,
1647
                );
1648
                $property_info_context->add('name', $property_info_name_context);
1649
            }
1650
            if (!is_null($property_info->doc_comment)) {
1651
                $property_info_doc_comment_context = $this->collectZendStringPointer(
1652
                    $property_info->doc_comment,
1653
                    $memory_locations,
1654
                    $dereferencer,
1655
                    $context_pools,
1656
                );
1657
                $property_info_context->add('doc_comment', $property_info_doc_comment_context);
1658
            }
1659
            $properties_info_context->add($key, $property_info_context);
1660
        }
1661
        return $properties_info_context;
1662
    }
1663
1664
    private function collectGlobalConstants(
1665
        ZendArray $array,
1666
        int $map_ptr_base,
1667
        Dereferencer $dereferencer,
1668
        ZendTypeReader $zend_type_reader,
1669
        MemoryLocations $memory_locations,
1670
        ContextPools $context_pools
1671
    ): GlobalConstantsContext {
1672
        $memory_location = ZendArrayTableMemoryLocation::fromZendArray($array);
1673
        $memory_locations->add($memory_location);
1674
1675
        $global_constants_context = new GlobalConstantsContext($memory_location);
1676
        foreach ($array->getItemIterator($dereferencer) as $constant_name => $zval) {
1677
            assert(is_string($constant_name));
1678
            $zend_constant = $dereferencer->deref(
1679
                $zval->value->getAsPointer(
1680
                    ZendConstant::class,
1681
                    $zend_type_reader->sizeOf(ZendConstant::getCTypeName()),
1682
                )
1683
            );
1684
            $zend_constant_memory_location = ZendConstantMemoryLocation::fromZendConstant(
1685
                $zend_constant
1686
            );
1687
            $constant_context = new GlobalConstantContext($zend_constant_memory_location);
1688
            $global_constants_context->add($constant_name, $constant_context);
1689
1690
            if (!is_null($zend_constant->name)) {
1691
                $constant_name_context = $this->collectZendStringPointer(
1692
                    $zend_constant->name,
1693
                    $memory_locations,
1694
                    $dereferencer,
1695
                    $context_pools,
1696
                );
1697
                $constant_context->add('name', $constant_name_context);
1698
            }
1699
1700
            $value_context = $this->collectZval(
1701
                $zend_constant->value,
1702
                $map_ptr_base,
1703
                $dereferencer,
1704
                $zend_type_reader,
1705
                $memory_locations,
1706
                $context_pools,
1707
            );
1708
            if (!is_null($value_context)) {
1709
                $constant_context->add('value', $value_context);
1710
            }
1711
        }
1712
        return $global_constants_context;
1713
    }
1714
1715
    private function collectIncludedFiles(
1716
        ZendArray $included_files,
1717
        Dereferencer $dereferencer,
1718
        MemoryLocations $memory_locations,
1719
        ContextPools $context_pools
1720
    ): IncludedFilesContext {
1721
        $array_table_location = ZendArrayTableMemoryLocation::fromZendArray($included_files);
1722
        $included_files_context = new IncludedFilesContext($array_table_location);
1723
1724
        $memory_locations->add($array_table_location);
1725
1726
        $iterator = $included_files->getItemIteratorWithZendStringKeyIfAssoc($dereferencer);
1727
        foreach ($iterator as $filename => $_) {
1728
            assert($filename instanceof Pointer);
1729
            $raw_string = $dereferencer->deref($filename)->toString($dereferencer);
1730
            $included_file_context = $this->collectZendStringPointer(
1731
                $filename,
1732
                $memory_locations,
1733
                $dereferencer,
1734
                $context_pools,
1735
            );
1736
            $included_files_context->add($raw_string, $included_file_context);
1737
        }
1738
        return $included_files_context;
1739
    }
1740
1741
    private function collectInternedStrings(
1742
        ZendArray $interned_string,
1743
        int $map_ptr_base,
1744
        Dereferencer $dereferencer,
1745
        ZendTypeReader $zend_type_reader,
1746
        MemoryLocations $memory_locations,
1747
        ContextPools $context_pools
1748
    ): ArrayHeaderContext {
1749
        return $this->collectZendArray(
1750
            $interned_string,
1751
            $map_ptr_base,
1752
            $dereferencer,
1753
            $zend_type_reader,
1754
            $memory_locations,
1755
            $context_pools,
1756
        );
1757
    }
1758
1759
    private function collectObjectsStore(
1760
        ZendObjectsStore $objects_store,
1761
        int $map_ptr_base,
1762
        Dereferencer $dereferencer,
1763
        ZendTypeReader $zend_type_reader,
1764
        MemoryLocations $memory_locations,
1765
        ContextPools $context_pools
1766
    ): ObjectsStoreContext {
1767
        $objects_store_memory_location = ObjectsStoreMemoryLocation::fromZendObjectsStore(
1768
            $objects_store,
1769
        );
1770
        $objects_store_context = new ObjectsStoreContext($objects_store_memory_location);
1771
        $memory_locations->add($objects_store_memory_location);
1772
1773
        assert($objects_store->object_buckets instanceof Pointer);
1774
        $buckets = $dereferencer->deref($objects_store->object_buckets);
1775
        $bucket_iterator = $buckets->getIteratorOfPointersTo(
1776
            ZendObject::class,
1777
            $zend_type_reader,
1778
        );
1779
1780
        foreach ($bucket_iterator as $key => $bucket) {
1781
            if ($key === 0) {
1782
                continue;
1783
            }
1784
            if ($bucket->address & 1) {
1785
                continue;
1786
            }
1787
            if ($bucket->address === 0) {
1788
                continue;
1789
            }
1790
            if ($key >= $objects_store->top) {
1791
                break;
1792
            }
1793
            $objects_store_bucket_context = $this->collectZendObjectPointer(
1794
                $bucket,
1795
                $map_ptr_base,
1796
                $memory_locations,
1797
                $dereferencer,
1798
                $zend_type_reader,
1799
                $context_pools,
1800
            );
1801
            $objects_store_context->add((string)$key, $objects_store_bucket_context);
1802
        }
1803
        return $objects_store_context;
1804
    }
1805
}
1806