View Issue Details

IDProjectCategoryView StatusLast Update
0001530XdebugCode Coveragepublic2018-12-04 19:36
Reporterandrewnicols Assigned Toderick  
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionno change required 
PlatformMacOSOSMacOSOS Version10.13.3
Product Version2.6.0 
Summary0001530: Last line in a foreach always marked as covered
Description

The last code line in a foreach test is always marked as covered, even if not covered.

Steps To Reproduce

<?php

xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);

foreach (['a'] as $item) {
if (false) {
echo "Test\n";
echo "Test\n";
}
}

print_r(xdebug_get_code_coverage());
xdebug_stop_code_coverage();

Additional Information

Reported on https://github.com/sebastianbergmann/php-code-coverage/issues/589 but I think this is actually an xdebug issue.

TagsNo tags attached.
Attached Files
bug01530.inc (107 bytes)
bug01530.phpt (574 bytes)
Operating SystemMacOS
PHP Version7.2.0-7.2.4

Activities

andrewnicols

2018-03-02 14:52

reporter   ~0004599

It seems that it's only foreach loops which are affected. Neither for, nor while loops seem to have this issue.

derick

2018-03-03 11:55

administrator   ~0004600

Hi,

I've had a look at this, and it's not an Xdebug issue. In the PHP Code Coverage ticket you wrote it both affects PHPDBG and Xdebug, which already hinted at it being a PHP thing. Hardly ever do we use the same implementation, so it's really unlikely we'd both have the same bug.

With the script:

1 <?php
2 foreach (['a'] as $item) {
3 if (false) {
4 echo "Test\n";
5 echo "Test\n";
6 }
7 }
8 ?>

I found that PHP generates the following opcodes (without opcache enabled):

filename: /home/derick/dev/php/derickr-xdebug/tests/bug01530.inc
function name: (null)
number of ops: 12
compiled vars: !0 = $item
line #* E I O op fetch ext return operands

2 0 E > EXT_STMT
1 > FE_RESET_R $1 <array>, ->10
2 > > FE_FETCH_R $1, !0, ->10
3 3 > EXT_STMT
4 > JMPZ <false>, ->9
4 5 > EXT_STMT
6 ECHO 'Test%0A'
5 7 EXT_STMT
8 ECHO 'Test%0A'
9 > > JMP ->2
10 > FE_FREE $1
9 11 > RETURN 1

The foreach keyword is represented by opcode 1 and 2 (FE_RESET_R and FE_FETCH_R), and you see that they can both jump to opcode 10 (->10). It would do that if the loop is empty (FE_RESET_R) or exhausted (FE_FETCH_R). PHP has generated opcode 10 (FE_FREE) on line 5. Which is really not correct, as it should put it on line 7. It does this wrong for both PHP 7.0, 7.1 and 7.2.

I have filed a ticket on the PHP tracker. I'll leave this one open for a while so I don't forget to check whether PHP has fixed it.

derick

2018-03-03 11:58

administrator   ~0004601

The PHP issue is: https://bugs.php.net/bug.php?id=76046

derick

2018-12-04 19:36

administrator   ~0004747

This issue is fixed in PHP for PHP 7.2.14 and 7.3.0:

Issue History

Date Modified Username Field Change
2018-03-02 14:36 andrewnicols New Issue
2018-03-02 14:52 andrewnicols File Added: bug01530.inc
2018-03-02 14:52 andrewnicols File Added: bug01530.phpt
2018-03-02 14:52 andrewnicols Note Added: 0004599
2018-03-03 11:55 derick Note Added: 0004600
2018-03-03 11:55 derick Assigned To => derick
2018-03-03 11:55 derick Status new => confirmed
2018-03-03 11:58 derick Note Added: 0004601
2018-09-20 07:37 derick Target Version => 2.7.0dev
2018-09-20 07:38 derick Status confirmed => acknowledged
2018-09-20 07:38 derick Resolution open => suspended
2018-09-20 07:38 derick Target Version 2.7.0dev =>
2018-12-04 19:36 derick Note Added: 0004747
2018-12-04 19:36 derick Status acknowledged => resolved
2018-12-04 19:36 derick Resolution suspended => no change required