Skip to content

Fix UnSatisfiedLinkError when trying to load non-existent libraries - #47

Merged
pavly-gerges merged 15 commits into
masterfrom
fix-ule-load
Oct 8, 2026
Merged

pavly-gerges merged 15 commits into
masterfrom
fix-ule-load

Conversation

@pavly-gerges

Copy link
Copy Markdown
Member

This PR introduces LibraryNotFoundException as a guard against directly loading non-existent file regardless of whether they are actual binaries or corrupted files.

Furthermore, the PR introduces a way to antagonize the effect of initializing a FileOutputStream by the FileExtractor API that by default creates a blank file (or opaque file); bypassing the formerly mentioned "LibraryNotFoundException".

In addition, it also introduces an example that shows how to deal with broken features using FileExtractionListener interface.

@pavly-gerges pavly-gerges added enhancement New feature or request core Core API related stuff examples Stressful testing the functionalities labels Oct 4, 2026
@codacy-production

codacy-production Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 2 minor

Alerts:
⚠ 2 issues (≤ 0 issues of at least minor severity)

Results:
2 new issues

Category Results
Documentation 2 minor

View in Codacy

🟢 Metrics 140 complexity · 4 duplication

Metric Results
Complexity 140
Duplication 4

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@pavly-gerges

pavly-gerges commented Oct 4, 2026 •

Copy link
Copy Markdown
Member Author

@stephengold You shouldn't catch exceptions anymore, the standard way to deal with exceptions and errors thrown from the API is to use both NativeBinaryLoadingListener and the FileExtractionListener instead. This removes the burden of trying to identify which exception or error is thrown.

EDIT:
Diagnostics could be built upon examining the causative error/exception and the calling stack from these listeners. FileExtractionListener deals with the part that is responsible for locating and extracting the binary from the compression. (NB: there exists FileLocalizingListener; it appears that it is redundant at the NativeBinaryLoader level and its instance is subjected for removal).

Btw, it appears that the techdemos that demonstrate the library features using jolt-jni are broken. Will you please consider submitting a fix for them after this PR?

@stephengold

Copy link
Copy Markdown
Contributor

it appears that the techdemos that demonstrate the library features using jolt-jni are broken. Will you please consider submitting a fix for them after this PR?

Of course. I have many projects that use jSnapLoader. Can you be specific about which projects are broken and how they are broken?

@pavly-gerges

pavly-gerges commented Oct 5, 2026 •

Copy link
Copy Markdown
Member Author

it appears that the techdemos that demonstrate the library features using jolt-jni are broken. Will you please consider submitting a fix for them after this PR?

Of course. I have many projects that use jSnapLoader. Can you be specific about which projects are broken and how they are broken?

Please consider checking the output of the TestCpuFeatures example here on this GitHub runner workflow.

@stephengold

Copy link
Copy Markdown
Contributor

I reproduced the failure seen in the "Build and Test jSnapLoader" workflow on ubuntu-latest-19 on my local machine.
I stepped through the code in a debugger.

loadBinary() throws LibraryNotFoundException at NativeBinaryLoader.java:343 because exists() returns false because jarPath is null in NativeDynamicLibrary.java:150 .

protected void loadBinary(NativeDynamicLibrary library, LoadingCriterion loadingCriterion) throws Exception {
try {
if (!nativeDynamicLibrary.exists()) {
throw new LibraryNotFoundException("Library " + nativeDynamicLibrary.getExtractedLibrary() + " not found!");
}
System.load(library.getExtractedLibrary());

public boolean exists() {
if (jarPath == null || libraryFile == null || directoryPath == null) {
return false;
}
return new File(getExtractedLibrary()).exists();
}

I don't yet understand jSnapLoader well enough to submit a fix.

@pavly-gerges

Copy link
Copy Markdown
Member Author

I reproduced the failure seen in the "Build and Test jSnapLoader" workflow on ubuntu-latest-19 on my local machine.
I stepped through the code in a debugger.

loadBinary() throws LibraryNotFoundException at NativeBinaryLoader.java:343 because exists() returns false because jarPath is null in NativeDynamicLibrary.java:150 .

Sorry, I forgot that someone may try to load from a classpath. The jarPath has to be excluded from that validation.

@pavly-gerges

pavly-gerges commented Oct 7, 2026 •

Copy link
Copy Markdown
Member Author

@stephengold You shouldn't catch exceptions anymore, the standard way to deal with exceptions and errors thrown from the API is to use both NativeBinaryLoadingListener and the FileExtractionListener instead. This removes the burden of trying to identify which exception or error is thrown.

EDIT: Diagnostics could be built upon examining the causative error/exception and the calling stack from these listeners. FileExtractionListener deals with the part that is responsible for locating and extracting the binary from the compression. (NB: there exists FileLocalizingListener; it appears that it is redundant at the NativeBinaryLoader level and its instance is subjected for removal).

I re-examined the API, and decided to keep the exceptions and remove the failure functions; as the exceptions could create rate limiting or application end-points which terminate the process at a particular failure point detectable by the debuggers and JRE, unlike failure functions which are mute unless implemented...

Conclusion: the primary way to deal with errors is to catch the thrown exceptions. The only left-over failure function is the NativeBinaryLoadingListener#onLoadingFailure which is useful to extend anti-failure routines. However, not mandatory to implement.

@pavly-gerges
pavly-gerges merged commit dd0beff into master Oct 8, 2026
6 of 7 checks passed
@pavly-gerges

Copy link
Copy Markdown
Member Author

@stephengold I appreciate your contributions. Expect a release very soon.

@stephengold

Copy link
Copy Markdown
Contributor

Thanks. Prioer to the release, may I suggest a few other changes?

@pavly-gerges

Copy link
Copy Markdown
Member Author

Thanks. Prioer to the release, may I suggest a few other changes?

Sure. You may open new issues and let's discuss them.

@pavly-gerges
pavly-gerges deleted the fix-ule-load branch October 8, 2026 00:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Core API related stuff enhancement New feature or request examples Stressful testing the functionalities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NativeBinaryLoader.loadLibrary() fails silently if clean extraction fails

2 participants