Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generated code in autoload_real.php collision of hashes with multiple instances of composer (in 2.6.4, not present in 2.6.3) #11675

Closed
qrizly2 opened this issue Oct 5, 2023 · 15 comments

Comments

@qrizly2
Copy link

qrizly2 commented Oct 5, 2023

Output of composer diagnose:

Do not run Composer as root/super user! See https://getcomposer.org/root for details
Continue as root/super user [yes]? 
Checking platform settings: OK
Checking git settings: WARNING
Your git version (2.17.1) is too old and possibly will cause issues. Please upgrade to git 2.24 or above
Checking http connectivity to packagist: OK
Checking https connectivity to packagist: OK
Checking github.com rate limit: OK
Checking disk free space: OK
Checking pubkeys: 
Tags Public Key Fingerprint: 57815BA2 7E54DC31 7ECC7CC5 573090D0  87719BA6 8F3BB723 4E5D42D0 84A14642
Dev Public Key Fingerprint: 4AC45767 E5EC2265 2F0C1167 CBBB8A2B  0C708369 153E328C AD90147D AFE50952
OK
Checking composer version: You are not running the latest stable version, run `composer self-update` to update (2.6.3 => 2.6.4)
Composer version: 2.6.3
PHP version: 7.2.24
PHP binary path: /usr/bin/php7.2
OpenSSL version: OpenSSL 1.1.1  11 Sep 2018
cURL version: 7.58.0 libz 1.2.11 ssl OpenSSL/1.1.1
zip: extension present, unzip not available, 7-Zip not availabl

When I run this command:

composer du

I get the following output in file "vendor/composer/autoload_real.php"

<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInitd751713988987e9331980363e24189ce
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    /**
     * @return \Composer\Autoload\ClassLoader
     */
    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        spl_autoload_register(array('ComposerAutoloaderInitd751713988987e9331980363e24189ce', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
        spl_autoload_unregister(array('ComposerAutoloaderInitd751713988987e9331980363e24189ce', 'loadClassLoader'));

        require __DIR__ . '/autoload_static.php';
        call_user_func(\Composer\Autoload\ComposerStaticInitd751713988987e9331980363e24189ce::getInitializer($loader));

        $loader->register(true);

        return $loader;
    }
}

And I expected this to happen, when i run it for the second time: that the hash after "ComposerAutoloaderInit" will change.
It does this in 2.6.3, but will stay the same in 2.6.4

@qrizly2 qrizly2 changed the title Generated code in autoload_real.php collision of hashes (in 2.6.4, not present in 2.6.3) Generated code in autoload_real.php collision of hashes with mulitple instances of composer includes (in 2.6.4, not present in 2.6.3) Oct 5, 2023
@qrizly2 qrizly2 changed the title Generated code in autoload_real.php collision of hashes with mulitple instances of composer includes (in 2.6.4, not present in 2.6.3) Generated code in autoload_real.php collision of hashes with multiple instances of composer (in 2.6.4, not present in 2.6.3) Oct 5, 2023
@fredden
Copy link
Contributor

fredden commented Oct 5, 2023

@qrizly2 yes, this is a change in behaviour. This was introduced in #11663.
Please can you describe the problem that you are experiencing?

@drupol
Copy link
Contributor

drupol commented Oct 5, 2023

I'm also curious to learn more about the issue this is introducing.

@qrizly2
Copy link
Author

qrizly2 commented Oct 5, 2023

The problem is that the generated hash is always the same for any composer.json.
It does not matter if there are 0 packages inside (classmap only composer.json file) or when there are 100 packages inside.

So when you have 2 projects (both with a composer.json file) and you need to autoload just a few parts of the other project this is not possible anymore.

And yes normally you would extract the common classes and put those in a shared repository, but this is not feasible with how the application grew over a few decades time.

@fredden
Copy link
Contributor

fredden commented Oct 5, 2023

@qrizly2 please can you provide two example composer.json files whose content-hashes collide?

@drupol
Copy link
Contributor

drupol commented Oct 5, 2023

I still do not understand the issue.

Basically, the only relevant change in the PR I submitted is this single line: https://github.com/composer/composer/pull/11663/files#diff-67d1dfefa9c7b1c7e0b04b07274628d812f82cd82fae635c0aeba643c02e8cd8R410

As you can see, instead of generating a random suffix, it uses the suffix from the composer.lock, if the composer.lock file exist.

I have troubles understanding a use case where this would create an issue.

@Seldaek
Copy link
Member

Seldaek commented Oct 6, 2023

If you're somehow calling the autoload dumper manually to generate different autoloaders for subsets of packages, even tho that would seem strange to me as autoloading really should mean there is no penalty to having lots of classes "available" at once, then make sure you set an autoloader-suffix in the config or pass $suffix to AutoloadGenerator::dump to ensure it's unique for each instance.

If it's not that, then as the others said I have no clue what you are doing and we'd need more infos :)

@qrizly2
Copy link
Author

qrizly2 commented Oct 6, 2023

In short we have the following structure:

image

with the content of the composer.json file of application-1:

{
  "autoloader-suffix": "A",
  "autoload": {
    "classmap": [
      "ProjectA/Model"
    ]
  }
}

with the content of the composer.json file of application-2:

{
  "autoloader-suffix": "B",
  "autoload": {
    "classmap": [
      "ProjectB/Model"
    ]
  }
}

and the content of application-3 index.php:

<?php

include_once __DIR__ .'/../application-1/vendor/autoload.php';
include_once __DIR__ .'/../application-2/vendor/autoload.php';

echo 'hi';

when you run index.php in appplication-3 this will generate the following error:

PHP Fatal error:  Cannot declare class ComposerAutoloaderInitd751713988987e9331980363e24189ce, because the name is already in use in /var/www/test/application-2/vendor/composer/autoload_real.php on line 5

@drupol
Copy link
Contributor

drupol commented Oct 6, 2023

Could you remove the composer.lock file from both application and regenerate it ? and try again?

@qrizly2
Copy link
Author

qrizly2 commented Oct 6, 2023

image

image

same result

@drupol
Copy link
Contributor

drupol commented Oct 6, 2023

Don't regenerate the autoloader, just remove the composer.lock and redo composer install.

@qrizly2
Copy link
Author

qrizly2 commented Oct 6, 2023

as you can see i already deleted it. but running composer install yields the same result

image

@fredden
Copy link
Contributor

fredden commented Oct 6, 2023

@qrizly2 have you set a "name" in your composer.json files? This forms part of the content-hash, so you'd get a different hash and therefore the collision goes away.

public static function getContentHash(string $composerFileContents): string
{
$content = JsonFile::parseJson($composerFileContents, 'composer.json');
$relevantKeys = [
'name',

@Seldaek
Copy link
Member

Seldaek commented Oct 6, 2023

"autoloader-suffix": "A"needs to be within a "config": { ... } block otherwise it's being ignored.

@Seldaek
Copy link
Member

Seldaek commented Oct 6, 2023

But indeed if you only have a composer.json like this:

{
  "autoload": {
    "classmap": [
      "ProjectA/Model"
    ]
  }
}

Then your composer.lock hash will be the same as the autoload config isn't part of the hash, and there are no dependencies. So if deleting the lock file you still get an empty one recreated when you run install. Anyway setting the prefix correctly in config should resolve it.

@qrizly2
Copy link
Author

qrizly2 commented Oct 6, 2023

Thank you. That seems to work, for completeness sake:

composer.json file for application-1:

{
  "config": {
    "autoloader-suffix": "A"
  },
  "autoload": {
    "classmap": [
      "ProjectA/Model"
    ]
  }
}

composer.json file for application-2:

{
  "config": {
    "autoloader-suffix": "B"
  },
  "autoload": {
    "classmap": [
      "ProjectB/Model"
    ]
  }
}

does not give anymore an error:
image

@qrizly2 qrizly2 closed this as completed Oct 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants