Puzzles Lib [Forge & Fabric]

Puzzles Lib [Forge & Fabric]

77M Downloads

[Bug]: PuzzlesUtil.loadServiceProvider uses context classloader

embeddedt opened this issue ยท 3 comments

commented

Mod Loader (Required)

Forge

Minecraft Version (Required)

1.19.2

Mod Version (Required)

4.4.0

Notes (Required)

If PuzzlesUtil.loadServiceProvider is invoked from the common ForkJoinPool (e.g. as a result of another mod using this to perform some task), it will fail to find the service class. This is because the ForkJoinPool's context classloader is not set to be the Knot/FML class loader, which means it cannot correctly load any new vanilla/mod classes. It will only work reliably with classes that were already loaded. In the Prominence modpack, this resulted in a crash when the right combination of mods were in use to trigger this scenario. ๐Ÿ˜†

Here is the relevant portion of the stacktrace:

Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.NullPointerException: Failed to load service for fuzs.diagonalfences.client.core.ClientAbstractions [in thread "ForkJoinPool.commonPool-worker-2"]
	at fuzs.puzzleslib.util.PuzzlesUtil.lambda$loadServiceProvider$0(PuzzlesUtil.java:135)
	at java.base/java.util.Optional.orElseThrow(Optional.java:403)
	at fuzs.puzzleslib.util.PuzzlesUtil.loadServiceProvider(PuzzlesUtil.java:135)
	at fuzs.diagonalfences.client.core.ClientAbstractions.<clinit>(ClientAbstractions.java:12)
	at fuzs.diagonalfences.client.model.MultipartAppender.rotateMultipartSegment(MultipartAppender.java:106)
	at fuzs.diagonalfences.client.model.RotatedVariant.method_4753(RotatedVariant.java:31)
	at net.minecraft.class_1088.handler$jee000$modernfix$getOrLoadBakedModelDynamic(class_1088.java:1047)
	at net.minecraft.class_1088.method_15878(class_1088.java)
	at net.minecraft.class_807.method_4753(class_807.java:77)
	at net.minecraft.class_816.method_4753(class_816.java:90)
	at net.minecraft.class_1088.handler$jee000$modernfix$getOrLoadBakedModelDynamic(class_1088.java:1047)
	at net.minecraft.class_1088.method_15878(class_1088.java)
	at org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider.get(DynamicBakedModelProvider.java:112)
	at org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider.get(DynamicBakedModelProvider.java:25)
	at java.base/java.util.Map.getOrDefault(Map.java:671)
	at net.minecraft.class_1092.method_4742(class_1092.java:38)
	at net.minecraft.class_773.method_3335(class_773.java:542)
	at net.minecraft.class_776.method_3349(class_776.java:91)
	at net.minecraft.class_4970$class_4971$class_3752.redirect$jkb000$moreculling$shouldDoShapeCache(class_4970.java:2211)
	at net.minecraft.class_4970$class_4971$class_3752.<init>(class_4970.java:1106)
	at net.minecraft.class_4970$class_4971.method_26200(class_4970.java:709)
	at net.minecraft.class_4970$class_4971.generateCache(class_4970.java:7672)
	at net.minecraft.class_4970$class_4971.handler$jgg000$modernfix$generateCacheLithium3(class_4970.java:7710)
	at net.minecraft.class_4970$class_4971.getAllFlags(class_4970.java)
	at net.minecraft.class_2826.addToFlagCount(class_2826.java:598)
	at net.minecraft.class_2826.md918784$lithium$lambda$calculateLithiumCounts$1$1(class_2826.java:579)
	at net.minecraft.class_2841.handler$ike000$lithium$count(class_2841.java:1146)
	at net.minecraft.class_2841.method_21732(class_2841.java)
	at net.minecraft.class_2826.calculateLithiumCounts(class_2826.java:579)
	at net.minecraft.class_2826.md918784$lithium$lambda$tryInitializeCountsByFlag$0$2(class_2826.java:572)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1760)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

A simple solution to this problem is to provide an explicit classloader to use, e.g. change ServiceLoader.load(clazz) to ServiceLoader.load(clazz, PuzzlesUtil.class.getClassLoader()) and ensure PuzzlesUtil is referenced somewhere during the mod loading process so that it's already loaded by the time something calls loadServiceProvider.

latest.log (Optional)

No response

commented

Thanks for this! So service providers are basially used everyhwere throughout my code, when would be a good place to load the ServiceLoader class then, like what's the earliest I could do? Maybe in a IMixinConfigPlugin?

commented

Yeah, that should be more than early enough.

commented

Fixed now in all affected Puzzles Lib versions (1.18.2-1.19.4), thanks again for reporting!