Skip to content

Commit

Permalink
Clean up after JVMs unable to delete temporary shared library files
Browse files Browse the repository at this point in the history
On Windows, File.deleteOnExit appears to be unable to delete our
temporary native library DLL files -- most likely because at the point
of deletion the process still has a reference to the loaded DLL, and
Windows doesn't allow deleting DLLs that are still referenced by a live
process.

Work around this limitation by deleting after the fact, i.e., clean up
old temp files when we know they should be deleted. Keep marker files in
the event that the library file cannot be deleted upon shutdown. Check
for these marker files upon starting a new VM using junixsocket, and
delete both the marker file and the associated shared library file.

The code is written in a way that it should also do the right thing on
other platforms, or at least fail silently.

#160
  • Loading branch information
kohlschuetter committed Aug 26, 2024
1 parent 173cc01 commit 51d3513
Showing 1 changed file with 72 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -167,13 +168,65 @@ private static final class ClasspathLibraryCandidate extends LibraryCandidate {
this.library = library;
}

/**
* Even though we ask the JVM to delete the library file upon VM exit, this may not be honored
* in all cases (crash, Windows, etc.)
*
* Therefore, we attempt to delete these files whenever another JVM using junixsocket starts up.
* This is simplified by keeping empty marker files next to the temporary shared library file.
*
* @param libDir The directory to check.
*/
@SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE")
private void deleteLibTmpDelFiles(File libDir) {
if (libDir == null) {
try {
File tempFile = File.createTempFile("libtmp", ".del");
libDir = tempFile.getParentFile();
tempFile.delete();
} catch (IOException e) {
return;
}
}
File[] filesToDelete = libDir.listFiles((File f) -> {
if (!f.isFile()) {
return false;
}
String name = f.getName();
return name.startsWith("libtmp") && name.endsWith(".del");
});
if (filesToDelete == null || filesToDelete.length == 0) {
return;
}

for (File f : filesToDelete) {
f.delete(); // NOPMD
String n = f.getName();
n = n.substring(0, n.length() - ".del".length());
File libFile = new File(f.getParentFile(), n);
libFile.delete(); // NOPMD
}
}

@Override
@SuppressWarnings("PMD.CognitiveComplexity")
synchronized String load() throws IOException, LinkageError {
if (libraryNameAndVersion == null) {
return null;
}

File libDir = TEMP_DIR;
File userHomeDir = new File(System.getProperty("user.home", "."));
File userDirOrNull = new File(System.getProperty("user.dir", "."));
if (userHomeDir.equals(userDirOrNull)) {
userDirOrNull = null;
}

deleteLibTmpDelFiles(libDir);
deleteLibTmpDelFiles(userHomeDir);
if (userDirOrNull != null) {
deleteLibTmpDelFiles(userDirOrNull);
}

for (int attempt = 0; attempt < 3; attempt++) {
File libFile;
Expand All @@ -200,19 +253,33 @@ synchronized String load() throws IOException, LinkageError {

switch (attempt) {
case 0:
libDir = new File(System.getProperty("user.home", "."));
libDir = userHomeDir;
break;
case 1:
libDir = new File(System.getProperty("user.dir", "."));
break;
if (userDirOrNull != null) {
libDir = userDirOrNull;
break;
}
// fall-through
default:
throw e;
}

continue;
} finally {
if (!libFile.delete()) {
libFile.deleteOnExit();
if (!libFile.delete() && libFile.exists()) {
libFile.deleteOnExit(); // keep this just in case the JVM gets smarter about DLL unloads

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
if (!libFile.delete() && libFile.exists()) {
File markerFile = new File(libFile.getParentFile(), libFile.getName() + ".del");
try {
Files.createFile(markerFile.toPath());
} catch (IOException | UnsupportedOperationException e) {
// ignore
}
}
}));
}
}

Expand Down

0 comments on commit 51d3513

Please sign in to comment.