MinecraftForge / ForgeGradle

Minecraft mod development framework used by Forge and FML for the gradle build system
GNU Lesser General Public License v2.1
526 stars 447 forks source link

MavenArtifactDownloader deadlocks when used from mapping channel provider. #886

Closed noeppi-noeppi closed 1 year ago

noeppi-noeppi commented 2 years ago

When MavenArtifactDownloader#_download is called with an artifact that is currently downloading, it waits on the other thread to complete the download. The problem is, that this is done inside the synchronized block.

This causes the waiting thread to hold the monitor of ACTIVE_DOWNLOADS indefinitely and blocks every other request for MavenArtifactDownloader. The problem arises if the artifact that currently is being downloaded is a generated artifact that relies on MavenArtifactDownloader to generate.

When does the issue occur in practise?

If a project has fg.deobf(...) dependencies, they'll be resolved together with the minecraft dependency. This causes both Deobfuscator#findMapping and MinecraftUserRepo#findMapping to be called in parallel, where both of them download the same mappings artifact through MavenArtifactDownloader.

The first call to MavenArtifactDownloader.download will start a mapping lookup through MCPRepo which calls the matching channel provider. The second call to MavenArtifactDownloader.download then waits for the download to complete which completely locks MavenArtifactDownloader for any artifact.

If the channel provider then uses MavenArtifactDownloader in its getMappingsFile method (which both builtin channel providers do), this can cause a deadlock.

As MavenArtifactDownloader#download calls happen very early in the builtin channel providers, it is unlikely, yet still possible for a deadlock to occur. Other 3rd party channel providers however, might call MavenArtifactDownloader#download later and do other stuff before, so they can become more prone for deadlocks.