Problem/Motivation

#2989734: PHP 7.3 compatibility made Drupal 8 pass on PHP 7.3 but we introduced some workarounds to overcome differences in PHP 7.3.

The workarounds are:

  • Drupal\KernelTests\Core\Entity\EntityQueryTest does not use list()
  • PrivateTempStore had to use DependencySerializationTrait - whilst the fix is correct we should work out what has changed in PHP's serialize()
  • BrowserTestBase::getDrupalSettings() had to change to use $this->getSession()->getPage()->getContent() instead of $this->getSession()->getPage()->getHtml() in order for it to work

Proposed resolution

Fix the tests or work out why this is happening.

Remaining tasks

User interface changes

None

API changes

None

Data model changes

None

CommentFileSizeAuthor
#42 3001920-42.patch7 KBtacituseu
#40 3001920-40.patch6.68 KBtacituseu
#36 3001920-36.patch8.17 KBtacituseu
#31 3001920-31.patch7.45 KBtacituseu
#29 3001920-28.patch7.47 KBtacituseu
#27 3001920-27.patch7.38 KBtacituseu
#26 3001920-26.patch6.88 KBtacituseu
#18 3001920-18.patch8.03 KBtacituseu
#17 3001920-17.patch8.39 KBtacituseu
#16 3001920-16.patch8.2 KBtacituseu
#15 3001920-14.drupal.PHP-73-compatibility-part-2.patch7.64 KBmikelutz
#14 3001920-14.drupal.PHP-73-compatibility-part-2.patch8.14 KBmikelutz
#13 3001920-12.drupal.PHP-73-compatibility-part-2.patch7.84 KBmikelutz
#12 3001920-12.drupal.PHP-73-compatibility-part-2.patch7.79 KBmikelutz
#11 3001920-10.drupal.PHP-73-compatibility-part-2.patch7.8 KBmikelutz
#10 3001920-10.drupal.PHP-73-compatibility-part-2.patch8.09 KBmikelutz
#9 3001920-8.drupal.PHP-73-compatibility-part-2.patch8.1 KBmikelutz
#8 3001920-8.drupal.PHP-73-compatibility-part-2.patch7.96 KBmikelutz
#7 3001920-6.drupal.PHP-73-compatibility-part-2.patch7.93 KBmikelutz
#6 3001920-6.drupal.PHP-73-compatibility-part-2.patch7.83 KBmikelutz
#4 3001920-4.drupal.PHP-73-compatibility-part-2.patch7.76 KBmikelutz
#4 3001920-4.drupal.PHP-73-compatibility-part-2.patch7.76 KBmikelutz
#3 3001920-3.drupal.PHP-73-compatibility-part-2.patch7.07 KBmikelutz
#2 3001920-2.drupal.PHP-73-compatibility-part-2.patch2.48 KBmikelutz
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

alexpott created an issue. See original summary.

mikelutz’s picture

For MigrationPluginManagerTest, 7.2 and 7.3 are producing different results around the array_multisort call in Drupal\migrate\Plugin\MigrationPluginManager::buildDependencyMigration at line 211

The test tests the order of migrations after sorting them so dependent migrations run first. The broken test is asserting that an set of migrations that do not depend on each other are migrated in a specific order. In this case, the order doesn't actually matter, and the array_multisort call is made with both weighted at 0 (correctly). By the documentation "If two members compare as equal, their relative order in the sorted array is undefined." @see http://php.net/manual/en/function.array-multisort.php. Therefore it isn't correct to test that these particular migrations end up in this particular order.

In fact, if I xdebug pause right before the array_multisort is executed in 7.2 and resume, I get them in a different order and the test fails.

mikelutz’s picture

I'm throwing a few things against the testbot. Mixing the patch from part one for my own sanity.

mikelutz’s picture

I feel silly tracking down heisingbugs, but... is it the hasTranslation check, or the just the assertion causing the test to pass...

The Migration failure I was able to duplicate in a docker container - no xdebug, but I could at least poke at it with variable dumps. I haven't been able to replicate the EntityQueryTest issue though.

alexpott’s picture

@mikelutz++ totally not silly. Thanks for doing this!

mikelutz’s picture

mikelutz’s picture

The more variations on this that I try, the more confused I get...

mikelutz’s picture

mikelutz’s picture

Is the heisingbug part of this due to using print_r with return set to TRUE in a test? According to the print_r docs , "When the return parameter is used, this function uses internal output buffering so it cannot be used inside an ob_start() callback function."

Because the only difference between #7 and #8 is the addition of the print_r to the end of the message in the assertTrue(FALSE) call. It shouldn't have possibly affected whether that assertion was ran...

Trying with serialize instead...

mikelutz’s picture

mikelutz’s picture

mikelutz’s picture

mikelutz’s picture

tacituseu’s picture

tacituseu’s picture

tacituseu’s picture

:D
Take a pick: b8ffa370.

mikelutz’s picture

Nice find. I figured it was a php bug, but I couldn't find it. I really wish it had occurred to me that I could cut down the test suite too. I need to remember that trick.

This one was driving me nuts all day.

alexpott’s picture

So now we need to report a bug on PHP. I'll try to do that with instructions on how to recreate. Testing with opcache on locally shows me that the problem might occur in Symfony/Yaml and sure enough running its tests on PHP 7.3 with opcache enabled fail. Which is great because this is much easier for PHP devs to reproduce. See https://bugs.php.net/bug.php?id=76933

tacituseu’s picture

Not sure about it being fixed by bug #76711 as it was committed on Sep 20 and the testbot's environment says:
PHP 7.3.0-dev (cli) (built: Sep 25 2018 18:34:07) ( NTS ).

alexpott’s picture

@tacituseu yeah I don't think this has been fixed at all. I was just describing my efforts. I was trying to see how https://hub.docker.com/r/drupalci/php-7.3.x-apache is actually built.

If someone can reproduce the bug we're seeing in simple code that'd be amazing.

tacituseu’s picture

@alexpott: I based it on drupalci_environments, but don't know what triggers the rebuilds.

alexpott’s picture

I've built PHP7.3 from src and confirmed we still have a problem against PHP7.3 HEAD so I've created a PHP bug report - https://bugs.php.net/bug.php?id=76937. Unfortunately I've still not been successful in creating a script that shows the issue without Drupal being around.

alexpott’s picture

There are other PHP7.3 bugs that Drupal's tests have uncovered that are not reported.

  1. +++ b/core/lib/Drupal/Core/TempStore/PrivateTempStore.php
    @@ -27,6 +28,7 @@
     class PrivateTempStore {
    +  use DependencySerializationTrait;
     
    

    There is some change in the serialize that has broken something. The bug exposes that we serialize far too much but it should still work.

  2. +++ b/core/tests/Drupal/Tests/BrowserTestBase.php
    @@ -677,7 +677,7 @@ protected function drupalGetHeader($name) {
    -    $html = $this->getSession()->getPage()->getHtml();
    +    $html = $this->getSession()->getPage()->getContent();
    

    I suspect that there is some PHP 7.3 bug here too.

tacituseu’s picture

Re #25: Checking first if they go away without opcache.
Edit: #25.2 went away.

tacituseu’s picture

Digging into #25.1.

alexpott’s picture

I've run Symfony's BrowserKit, Behat's Mink and MinkBrowserKitDriver tests on the latest PHP 7.3 dev with opcache enabled and there are no errors so it looks what ever is causing #25.2 is not tested by the stuff we're relying on :(

tacituseu’s picture

alexpott’s picture

@tacituseu I dumped the results of the serialization locally before whilst locally into that. It's not pretty. Good luck!

tacituseu’s picture

Not pretty indeed, tweaking it a bit to be able to compare to known good.

tacituseu’s picture

Good news is that for both good and bad run serialization looks the same (only timestamps and random strings differ), so the problem is in unserializer. Another good thing is that it is consistent as both MigrateUpgrade6Test and MigrateUpgrade7Test fail in the same place:

// fails at '@'
...s:13:"_route_params";a:6:
{s:25:"_drupal_request_sanitized";b:1;s:5:"_form";s:41:"\Drupal\migrate_drupal_ui\Form\ReviewForm";s:6:"_title";s:7:"Upgrade";s:13:"_route_object";r:1430;s:14:"_raw_variables";r:1477@;s:14:"_access_result";r:1480;}...

So it is a problem with processing object reference, I've no idea why, maybe it rings a bell somewhere.
PHP's commit log: var_unserializer.c.

tacituseu’s picture

Reconstructed (replaced references above 1430 with a dummy one) and trimmed var_dump up to the failing point:

// ... - trimmed, ??? - corrupted references causing error
$batch =
array(12) {
  ["sets"]=>
  array(1) {
    ...
  }
  ["has_form_submits"]=>
  bool(false)
  ["form_state"]=>
  object(Drupal\Core\Form\FormState)#3 (34) {
    [" * complete_form"]=>
    array(30) {
      ...
    }
    [" * build_info"]=>
    array(4) {
      ["args"]=>
      array(0) {
      }
      ["files"]=>
      array(0) {
      }
      ["callback_object"]=>
      object(Drupal\migrate_drupal_ui\Form\ReviewForm)#15 (15) {
        [" * migrations"]=>
        array(114) {
          ...
        }
        ...
        [" * store"]=>
        object(Drupal\Core\TempStore\PrivateTempStore)#44 (6) {
          [" * storage"]=>
          object(Drupal\Core\KeyValueStore\DatabaseStorageExpirable)#45 (5) {
            [" * table"]=>
            string(16) "key_value_expire"
            [" * collection"]=>
            string(35) "tempstore.private.migrate_drupal_ui"
            [" * _serviceIds"]=>
            array(2) {
              ["serializer"]=>
              string(26) "serialization.phpserialize"
              ["connection"]=>
              string(8) "database"
            }
            [" * _entityStorages"]=>
            array(0) {
            }
          }
          ...
          [" * requestStack"]=>
          object(Symfony\Component\HttpFoundation\RequestStack)#49 (3) {
            [" Symfony\Component\HttpFoundation\RequestStack requests"]=>
            array(2) {
              [0]=>
              object(Symfony\Component\HttpFoundation\Request)#50 (24) {
                ["attributes"]=>
                object(Symfony\Component\HttpFoundation\ParameterBag)#51 (2) {
                  [" * parameters"]=>
                  array(9) {
                    ["_drupal_request_sanitized"]=>
                    bool(true)
                    ["_form"]=>
                    string(41) "\Drupal\migrate_drupal_ui\Form\ReviewForm"
                    ["_title"]=>
                    string(7) "Upgrade"
                    ["_route"]=>
                    string(32) "migrate_drupal_ui.upgrade_review"
                    ["_route_object"]=>
                    object(Symfony\Component\Routing\Route)#52 (1) {
                    }
                    ["_raw_variables"]=>
                    object(Symfony\Component\HttpFoundation\ParameterBag)#53 (2) {
                      [" * parameters"]=>
                      array(0) {
                      }
                    }
                    ["_controller"]=>
                    string(32) "controller.form:getContentResult"
                    ["_access_result"]=>
                    object(Drupal\Core\Access\AccessResultAllowed)#54 (4) {
                      [" * cacheContexts"]=>
                      array(0) {
                      }
                      [" * cacheTags"]=>
                      array(0) {
                      }
                      [" * cacheMaxAge"]=>
                      int(0)
                    }
                    ["_route_params"]=>
                    array(6) {
                      ["_drupal_request_sanitized"]=>
                      bool(true)
                      ["_form"]=>
                      string(41) "\Drupal\migrate_drupal_ui\Form\ReviewForm"
                      ["_title"]=>
                      string(7) "Upgrade"
                      ["_route_object"]=>
                      object(Symfony\Component\Routing\Route)#52 (1) {
                      }
                      ["_raw_variables"]=>
                      object(???)#4 (4) {
                      }
                      ["_access_result"]=>
                      object(???)#4 (4) {
                      }
                    }
                  }
                }
                ...
              }
              ...
            }
            ...
          }
          ...
        }
        ...
      }
      ...
    }
    ...
  }
  ...
}
alexpott’s picture

Issue tags: +PHP 7.3
Related issues: +#2989734: PHP 7.3 compatibility
alexpott’s picture

Title: PHP 7.3 compatibility part 2 » Investigate PHP 7.3 workarounds
Category: Bug report » Task
Issue summary: View changes
Priority: Critical » Normal

Drupal\Tests\migrate\Unit\MigrationPluginManagerTest is now fixed in #2989734: PHP 7.3 compatibility and we have a work-around for Drupal\KernelTests\Core\Entity\EntityQueryTest so this issue should now be about investigating the work-arounds introduced in that issue.

tacituseu’s picture

Checking what changes with DependencySerializationTrait.

alexpott’s picture

@tacituseu the services on the object will not be serialized - ie $this->lockBackend, $this->currentUser, $this->requestStack

tacituseu’s picture

I meant "in the structure of serialized string", the patches produce log under artifacts\run_tests.functional\phpunit-xml.

tacituseu’s picture

Exactly those mentioned in #37 :), the serialized string is 11K smaller after and the only references left in it are to the TranslatableMarkup of the submit button.

tacituseu’s picture

Re-testing #26 as it only disabled optimizations and not the whole Opcache.

tacituseu’s picture

@alexpott: Could do a bit search on opcache.optimization_level to pinpoint which pass is responsible for https://bugs.php.net/bug.php?id=76937 ? Might help tracking it down.

tacituseu’s picture

tacituseu’s picture

The additional fail in CommentCSSTest from #42 is due to race condition with mkdir() in BrowserHtmlDebugTrait::initBrowserOutputFile().

tacituseu’s picture

Looks like we hit #25.1 again.
@tim.plunkett tracked it down to https://bugs.php.net/bug.php?id=77302:

[2019-01-22 19:57 UTC] dmitry@php.net
7.2 and below are affected by the same problem.
The old versions don't fail, but silently produce incorrect result (not the same as was serialized).

That would explain why in #31 both on 7.2 and 7.3 serialized strings looked the same.

bojanz’s picture

We just fixed the serialization crash in Commerce by no longer using $this->logger in a serialized class: #3038430: Unable to checkout on php7.3.

If the logger was retrieved from LoggerChannelFactory, it can't be serialized, since it is invisible to DependencySerializationTrait.
Previously it would get silently corrupted, but PHP 7.3 changed that behavior.

The solution is to either store the factory service instead and retrieve the logger only when needed, or to define a channel-specific logger service, like core does:

  logger.channel.file:
    class: Drupal\Core\Logger\LoggerChannel
    factory: logger.factory:get
    arguments: ['file']
aspilicious’s picture

joachim’s picture

PHP bug https://bugs.php.net/bug.php?id=77302 is also rearing its head in the Oauth2 Server module, in #3049250: PHP 7.3 Session Handling Issue.

The problem there is basically that a request object can't survive serialization. This code produces an error:

  $request = \Drupal::request(); 
  $s = serialize($request);
  $u = unserialize($s);

Does the issue summary need to be updated for the object serialization problem?

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

jungle’s picture

Version: 8.8.x-dev » 8.9.x-dev

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

malaynayak’s picture

After upgrading to php 7.3 all the custom AJAX callbacks in some custom forms were failing due to php serialisation error:

Notice: unserialize(): Error at offset 28221 of 41088 bytes in Drupal\Component\Serialization\PhpSerialize::decode() (line 21 of /var/www/html/docroot/core/lib/Drupal/Component/Serialization/PhpSerialize.php)

As a quick fix we are patching the /core/lib/Drupal/Core/Form/FormCache.php class setCache function

if ($data = $form_state->getCacheableArray()) {
      // Patch for fixing the known issue of PHP 7.3 unserialize error.
      <strong>unset($data['build_info']);</strong>
      $this->keyValueExpirableFactory->get('form_state')->setWithExpire($form_build_id, $data, $expire);
}

It though resolved the issue, we need to know the actual root cause and fix for it. Any help would be appreciated.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

longwave’s picture

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

andypost’s picture

Status: Active » Closed (outdated)

I bet it outdated!