MantisBT - Xdebug
View Issue Details
0001530XdebugCode Coveragepublic2018-03-02 14:362018-12-04 19:36
andrewnicols 
derick 
normalmajoralways
resolvedno change required 
MacOSMacOS10.13.3
2.6.0 
 
MacOS
7.2.0-7.2.4
0001530: Last line in a foreach always marked as covered
The last code line in a foreach test is always marked as covered, even if not covered.
<?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();
Reported on https://github.com/sebastianbergmann/php-code-coverage/issues/589 [^] but I think this is actually an xdebug issue.
No tags attached.
? bug01530.inc (107) 2018-03-02 14:52
https://bugs.xdebug.org/file_download.php?file_id=422&type=bug
? bug01530.phpt (574) 2018-03-02 14:52
https://bugs.xdebug.org/file_download.php?file_id=423&type=bug
Issue History
2018-03-02 14:36andrewnicolsNew Issue
2018-03-02 14:52andrewnicolsFile Added: bug01530.inc
2018-03-02 14:52andrewnicolsFile Added: bug01530.phpt
2018-03-02 14:52andrewnicolsNote Added: 0004599
2018-03-03 11:55derickNote Added: 0004600
2018-03-03 11:55derickAssigned To => derick
2018-03-03 11:55derickStatusnew => confirmed
2018-03-03 11:58derickNote Added: 0004601
2018-09-20 08:37derickTarget Version => 2.7.0dev
2018-09-20 08:38derickStatusconfirmed => acknowledged
2018-09-20 08:38derickResolutionopen => suspended
2018-09-20 08:38derickTarget Version2.7.0dev =>
2018-12-04 19:36derickNote Added: 0004747
2018-12-04 19:36derickStatusacknowledged => resolved
2018-12-04 19:36derickResolutionsuspended => no change required

Notes
(0004599)
andrewnicols   
2018-03-02 14:52   
It seems that it's only foreach loops which are affected. Neither for, nor while loops seem to have this issue.
(0004600)
derick   
2018-03-03 11:55   
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.
(0004601)
derick   
2018-03-03 11:58   
The PHP issue is: https://bugs.php.net/bug.php?id=76046 [^]
(0004747)
derick   
2018-12-04 19:36   
This issue is fixed in PHP for PHP 7.2.14 and 7.3.0:
- https://bugs.php.net/bug.php?id=76046 [^]
- https://github.com/php/php-src/commit/d6595f276fff44aa5d1d2dde7238d540a267d0dd [^]