View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0002438 | Xdebug | Code Coverage | public | 2026-09-25 09:25 | 2026-10-01 06:47 |
| Reporter | sebastian | Assigned To | |||
| Priority | normal | Severity | major | Reproducibility | always |
| Status | new | Resolution | open | ||
| Product Version | 3.6.0alpha1 | ||||
| Summary | 0002438: XDEBUG_CC_UNUSED no longer reports lines of unexecuted functions in files compiled before xdebug_start_code_coverage() | ||||
| Description | With Xdebug 3.6.0alpha1, xdebug_get_code_coverage() no longer reports lines of functions (methods) that were not executed when the file declaring them was compiled before xdebug_start_code_coverage(XDEBUG_CC_UNUSED) was called. Such lines are reported with -1 by Xdebug 3.5.3 (current stable), and they are still reported by 3.6.0alpha1 when the file is compiled after code coverage was started. This affects PHPUnit / php-code-coverage: unexecuted lines disappear from the coverage data instead of being reported as "not executed". This was found because phpcov's test suite started to fail in CI once setup-php installed Xdebug 3.6.0alpha1. | ||||
| Steps To Reproduce | ReproducerExample.php:
test.php:
Run:
Results1) Example.php compiled AFTER xdebug_start_code_coverage() (php test.php after) Xdebug 3.5.3:
Xdebug 3.6.0alpha1:
=> identical 2) Example.php compiled BEFORE xdebug_start_code_coverage() (php test.php before) Xdebug 3.5.3:
Xdebug 3.6.0alpha1:
=> lines 11 and 12 (body of the unexecuted method notCalled()) are missing | ||||
| Additional Information | Expected result: Lines 11 and 12 are reported as -1 (not executed), as with Xdebug 3.5.3, regardless of whether the file was compiled before or after code coverage collection was started. Actual result: With Xdebug 3.6.0alpha1, lines of functions that were not executed are missing from the result when the file was compiled before xdebug_start_code_coverage() was called. | ||||
| Tags | No tags attached. | ||||
| Operating System | |||||
| PHP Version | 8.5.0-8.5.4 | ||||
|
|
I built 3.5.3 and 3.6.0alpha1 from source and compared them. The change comes from c3dafbb349 ("Fixed issue 0001674"). In 3.5.3, xdebug_code_coverage_start_of_function() calls xdebug_prefill_code_coverage(). Besides the function being entered, that function also analyses everything added to CG(function_table) and CG(class_table) since the previous call. In 3.6.0alpha1, xdebug_code_coverage_start_of_function() calls prefill_from_oparray() for the function being entered only. The function and class tables are now only analysed in xdebug_coverage_compile_file(), so functions and methods that were compiled before xdebug_start_code_coverage() are only analysed if some file is compiled while code coverage is active. This makes the result depend on unrelated code. Adding <code> (any file will do) right after xdebug_start_code_coverage(XDEBUG_CC_UNUSED) in the "before" case of the reproducer brings lines 11 and 12 back with 3.6.0alpha1: <code> The same applies to methods of an anonymous class that was declared before xdebug_start_code_coverage() was called: 3.5.3 reports their lines as not executed, 3.6.0alpha1 does not report them. If reporting code that was compiled before code coverage collection started is meant to keep working, a cheap fix might be to also run the function and class table part of xdebug_prefill_code_coverage() in xdebug_start_code_coverage() when XDEBUG_CC_UNUSED is set, and/or in xdebug_get_code_coverage(). Because of prefill_function_count and prefill_class_count, that part only looks at entries added since it last ran. The result would then no longer depend on whether, and when, some file is compiled. A second behaviour change is related: xdebug_stop_code_coverage() no longer discards the analysis (scrub_runtime() only clears the runtime data). Every later xdebug_get_code_coverage() call therefore returns every file that was ever analysed, and files that were not executed since the last xdebug_start_code_coverage() are included with all their lines as -1: <code> With 3.5.3, the third result is empty. PHPUnit starts and stops code coverage for every test, so with 3.6.0alpha1 the result for a test grows with the number of files loaded before it. For 400 tests that each load one more class, the results contain 80,200 files in total instead of 400. xdebug_get_code_coverage() itself is still fast, but processing this data on our side doubled the time spent in php-code-coverage in that benchmark. If this is intended, it would be good to document it. |