Crash when spawning a JVM inside of a UWP C++ Application - java

First of: I don't know if this problem is rather related to UWP and it's strange security settings or rather me mis-using JNI's Invocation
Anyhow, I use this code to spawn a jvm inside a c++ static library (With /ZW, so compiling for UWP, but disabling it doesn't change a thing).
The following code is based upon Oracle's Notes and openjdk's code (exeinvoke.c, launcher.c, ...):
void JVM4UWP::loadVM(string vmOptions[], int numOptions, int jni_version) {
/* Copy the VM Options */
options = new JavaVMOption[numOptions];
for (uint8_t i = 0; i < numOptions; i++) {
options[i].optionString = new char[vmOptions[i].length() + 1]; // \0 takes the additional byte
strncpy_s(options[i].optionString, vmOptions[i].length() + 1, vmOptions[i].c_str(), vmOptions[i].length() + 1);
}
//options[0].optionString = "-Djava.class.path=/usr/lib/java";
vm_args = new JavaVMInitArgs();
vm_args->version = jni_version;
vm_args->nOptions = numOptions;
vm_args->options = options;
vm_args->ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
JNI_CreateJavaVM(&jvm, (void**)&env, vm_args);
delete options;
/* invoke the Main.test method using the JNI */
jclass cls = env->FindClass("Main");
jmethodID mid = env->GetStaticMethodID(cls, "main", "(I)V");
env->CallStaticVoidMethod(cls, mid, 100);
/* We are done. */
jvm->DestroyJavaVM();
}
Now the problem with this is: I added #include <jni.h>, I added lib/jvm.lib as static library (taken from oracle's jdk), however it seems that something is still incomplete.
When I run the application, I get an error upon loadup (App::App of the sample UWP application isn't even run).
The console returns:
Das Programm "[1892] TestJVM.exe" wurde mit Code -1073741515 (0xc0000135) 'Es wurde keine abhängige DLL gefunden' beendet.
Loosely translated it's: Could find no dependant dll.
Now this reminds me of this MSDN Article. I have to admit that I don't fully understand it's contents. Especially since jvm.lib cannot have any Manifests. I tried to add jvm.dll, java.dll and jli.dll to the folder of the .exe but for some reason it still doesn't work.
Since the above code should work without dlls, I think it might be related to UWP, maybe even to my code:
My Setup currently is like this: I have the JVM4UWP static library which in-turn is linked statistically against jvm.lib. This Library is then included into the Demo UWP Project, which I am trying to execute.

Note that only subset of usual Windows APIs is available for uwp applications and I doubt that jvm is compatible with these restrictions. "lib/jvm.lib" might actually be an export library, not static library.
Also you probably might want to get familiar with Using a Win32 DLL in a Universal Windows Platform App.

It looks like JVM library is missing.
Take a look here for a sample where JVM is executed from C code:
http://jnicookbook.owsiak.org/recipe-no-027/
This sample is little bit more complex (it uses POSIX threads) but still, basics are the same.
Make sure that all libraries are on PATH so they can be loaded by either C++ or JVM.
Have fun with JNI!

Okay, so I made progress:
This Question, compiling for Win32 and the fact that you have to embed dll's so they are available, showed me that the jvm.dll was missing, even though I added it to the program's path. Using gflags as pointed out above shows you which dlls it's trying to load and where it tried to locate them.
Actually, you don't have to embed dll's for debugging purposes, but the dlls have to reside inside of the AppX Folder, instead of the Root folder (even though there is also an exe file there).
So since it's not mentioned elsewhere: When linking against jvm.lib, you still need the jvm.dll since this lib only seems to handle dynamic loading/wrapping/etc
Note that only subset of usual Windows APIs is available for uwp applications and I doubt that jvm is compatible with these restrictions.
Yes and no, I had a look at openJDKs Sourcecode and the Majority of it is only File Handling and such, so I guess the part which could require reworking is the Memory and Threading related things.
Anyhow I was expecting such errors rather as Access Violations since some OS imports are simply 0x0 (aka not found), so I could now what I have to change to make it UWP compatible.
I might also give recompiling the openJDK with /ZW a try, but it's a challenging task.
Using a Win32 DLL in a Universal Windows Platform App also tells that at least the static librarys seem to work as is, maybe one needs wrappers for the illegal API to link into the project.

Related

Get File Version of .exe in java on Linux

Question - Get File Version of .exe in java on Linux for some strange client.
Solution -
I used JNA library to read file version using Java. Given below code is running fine on windows platform but it is throwing below error on Linux docker image.
"Unable to load library 'version': Error loading shared library libversion.so: No such file or directory Error loading shared library libversion.so: No such file or directory Native library (linux-x86-64/libversion.so) not found in resource path..".
private String GetFileVersion(String filePath) {
File fileToCheck = new File(filePath);
short[] rtnData = new short[4];
int infoSize = Version.INSTANCE.GetFileVersionInfoSize(fileToCheck.getAbsolutePath(), null);
Pointer buffer = Kernel32.INSTANCE.LocalAlloc(WinBase.LMEM_ZEROINIT, infoSize);
try {
Version.INSTANCE.GetFileVersionInfo(fileToCheck.getAbsolutePath(), 0, infoSize, buffer);
IntByReference outputSize = new IntByReference();
PointerByReference pointer = new PointerByReference();
Version.INSTANCE.VerQueryValue(buffer, "\\", pointer, outputSize);
VerRsrc.VS_FIXEDFILEINFO fileInfoStructure = new VerRsrc.VS_FIXEDFILEINFO(pointer.getValue());
rtnData[0] = (short) (fileInfoStructure.dwFileVersionMS.longValue() >> 16);
rtnData[1] = (short) (fileInfoStructure.dwFileVersionMS.longValue() & 0xffff);
rtnData[2] = (short) (fileInfoStructure.dwFileVersionLS.longValue() >> 16);
rtnData[3] = (short) (fileInfoStructure.dwFileVersionLS.longValue() & 0xffff);
return String.format("%s.%s.%s.%s", rtnData[0], rtnData[1], rtnData[2], rtnData[3]);
} catch (Exception exception) {
return null;
} finally {
Kernel32.INSTANCE.GlobalFree(buffer);
}
}
I will start by answering the question that you asked, though I doubt it is what you actually need to know.
The types of different executable file formats are encoded in the first few bytes of the file. For example, ELF files (executables, shared libraries) are described in this Wikipedia page.
So there are a number of ways to find out what kind of executable in Java:
Write some code that reads the first few bytes and decodes the file header information, as per the format described in the Wikipedia link above.
Find an existing Java library that does this and work out how to do this. (Google for "java file magic library" and see what you can find.)
Read about the Linux file command and write some Java code to run file on each library and parse the output.
What I think you actually need to do is a bit different:
Locate the file or files in the file system that the Java is looking for: apparently libversion.so or linux-x86-64/libversion.so. (The file could well be a symlink. Follow it.)
Run file on each file to check that it is the right kind of library. They need to be 32 or 64 bit corresponding the JVM you are running, and the correct ABI and ISA for the platform.
Check that the files are where the JVM expects to find them. The JVM searches for libraries in directories listed in the "java.library.path" system property. You can (if necessary) set the path using a -Djava.library.path=... JVM option.
See "java.library.path – What is it and how to use" for more information on library loading.
(There is absolutely no need to do step 2 "from" or "in" Java.)
I think I have finally worked out what you are doing.
The Version you are using is actually coming from the package com.sun.jna.platform.win32. It is not part of the JNA library (jna.jar). I think it is actually part of jna-platform.jar. If I understand things correctly, that is the generated JNA adapter library for the Windows COM dlls.
If I have that correct, you would actually need the Windows COM native libraries compiled and built for the Linux platform to do what you are trying to do.
AFAIK, that's not possible.
So how could you make this work? Basically you need to do one of the following:
Look for an existing pure Java library for extracting the version information from a Windows ".exe" file. I don't think it is likely that you will find one.
Find the specification for the Windows ".exe" file format and write your own Java code to extract the version information. I haven't looked for the spec to see how much work it would be.
Then you rewrite the code that you added your question to use the alternative API.
The "libversion" file that I mentioned in my other answer is not relevant. It is something else. It is a red herring.

Building Go from source fails tests when run using Java's Runtime.getRuntime().exec()

This question is related to a previous question, here: Java Runtime.getRuntime().exec() appears to be overwriting $PATH
I am trying to build Go from source from inside a Java program. I can build it properly using Terminal, but Java's Runtime.getRuntime().exec() gets interesting results. I tried using ProcessBuilder, but could not get it to properly make Go. Using my current setup with exec(), it makes properly, but then fails two tests. Code snippet:
String[] envp = new String[4];
envp[0] = "CC=/usr/bin/clang";
envp[1] = "GOROOT_BOOTSTRAP=/usr/local/go";
envp[2] = "CGO_ENABLED=0";
envp[3] = "PATH=" + System.getenv().get("PATH");
Runtime.getRuntime().exec("./all.bash", envp, "$HOME/Desktop/go/src");
It runs properly and compiles properly, but when it gets to running the test suite, I get two errors:
--- FAIL: TestCurrent (0.00s)
user_test.go:24: Current: user: Current not implemented on darwin/amd64 (got &user.User{Uid:"502", Gid:"20", Username:"", Name:"", HomeDir:""})
FAIL
FAIL os/user 0.009s
and a much longer one that I won't paste here due to absurd length, but it comes down to:
panic: test timed out after 3m0s
...
FAIL runtime 180.056s
I haven't any idea why the former is failing, but for the runtime when I build from the Terminal, it says:
ok runtime 19.096s
So something is causing that to take absurd amounts of time. I did some googling, and heard that it might be fixed if I use ARM=5 as an environment variable, but that didn't change anything. Does anyone have any idea why these tests are failing when I build from Java as opposed to the Terminal?
Looking at the source code for the os/user package, it looks like the native user handling depends on having cgo enabled. If cgo=0 (your case), it will fall back to the USER and HOME environment variables.
source code in question
Try putting USER=whatever in your exec environment.
I'm afraid I'd need more information to diagnose the runtime issue.

Support for setting ACL in Linux

I understand from Java 7 onwards I can use a code like the below to set ACL for a file:
java.nio.file.Path file = Paths.get(filePath);
java.nio.file.attribute.GroupPrincipal joe = file.getFileSystem().getUserPrincipalLookupService()
.lookupPrincipalByGroupName(groupid);
AclFileAttributeView view = Files.getFileAttributeView(file, AclFileAttributeView.class);
java.nio.file.attribute.AclEntry entry = java.nio.file.attribute.AclEntry.newBuilder()
.setType(AclEntryType.ALLOW)
.setPrincipal(joe)
.setPermissions(aclEntryPermissions)
.build();
List<java.nio.file.attribute.AclEntry> acl = view.getAcl();
acl.add(entry);
view.setAcl(acl);
But this code wont run for Linux (runs fine for Windows and Solaris). And the reason seems to be because AclFileAttributeView is not supported in Linux.
My questions are:
Is there some version of Java where AclFileAttributeView is supported in Linux?
If answer to 1 is no, then can someone share a sample JNA code, or give me some pointers to the Native API I need to use in Linux, to get this running.
In effect I want the functionality similar to the setfacl and getfacl command lines.

Proguard obfuscated jar won't launch

I was having trouble running my obfuscated jar, I got the "Java Virtual Machine Launcher" message "A Java Exception has occurred" when I try to run it. (This error is a popup, not on the command line) I tried running from the command line and printing the stacktrace from the jvm console and didn't see any exceptions.
So I did a little troubleshooting: I disabled shrinking, obfuscating AND optimizing so that the output (should be) the same as the input. The output jar turned out to be a few KB less than the input. I extracted both jars, decompiled the .class files and compared the source of every single file and the MANIFEST.MF and they were all the same*!
I'm using ProGuard 4.10, JDK 1.7.0_25 x64 and Windows 8. I'm building a fairly elaborate JavaFX program and I believe I properly configured ProGuard- but that shouldn't matter anymore if shrinking, obfuscating and optimizing are all disabled, right? Here are the notes that ProGuard gives me:
Note: duplicate definition of library class [netscape.javascript.JSException]
Note: duplicate definition of library class [netscape.javascript.JSObject]
Note: com.javafx.main.Main accesses a field 'HKEY_LOCAL_MACHINE' dynamically
Note: com.javafx.main.Main accesses a field 'HKEY_LOCAL_MACHINE' dynamically
Note: com.javafx.main.Main accesses a declared method 'reset()' dynamically
Note: com.javafx.main.Main$2 accesses a field 'ERROR_MESSAGE' dynamically
When I first tried obfuscating, I skipped com.javafx.main.** but I still got those messages. Any help would be greatly appreciated. I had no problems running my jar before it processed by ProGuard. Thanks.
*EDIT: When doing a binary comparison, the manifest files differ (the original is longer) but doing an ASCII comparison both files are identical. All other files are completely identical. The difference between the two MANIFEST.MF files is PC vs. UNIX line breaks.
*EDIT2: I ran the file with the -jar option, and I did get an explicit exception!
java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
From com.javafx.main.Main here is the use of ERROR_MESSAGE and HKEY_LOCAL_MACHINE:
int ERROR_MESSAGE = ERROR_MESSAGE_Field.getInt(null);
Method showMessageDialogMethod = jOptionPaneClass.getMethod("showMessageDialog", new Class[] { componentClass, Object.class, String.class, Integer.TYPE });
showMessageDialogMethod.invoke(null, new Object[] { null, this.val$string, "JavaFX Launcher Error", new Integer(ERROR_MESSAGE) });
...
Field HKEY_LOCAL_MACHINE_Field = winRegistryClass.getField("HKEY_LOCAL_MACHINE");
int HKEY_LOCAL_MACHINE = HKEY_LOCAL_MACHINE_Field.getInt(null);
String path = (String)mGet.invoke(null, new Object[] { new Integer(HKEY_LOCAL_MACHINE), "Software\\Oracle\\JavaFX\\" + version, "Path" });
The jar was signed; I made an unsigned version and it obfuscated correctly!

Error message when trying to write a xlsx.-file with R

I try to save some R-dataframes into .xlsx-files using the write.xlsx function of the xlsx package like this
write.xlsx(tab,file="test",sheetName="testsheet",col.names=TRUE,row.names=FALSE,append=FALSE)
whereas the object tab is a data frame, as prooved here
> class(tab)
[1] "data.frame"
When I run the code I get the following error message
> write.xlsx(tab,file="test.xlsx",sheetName="testsheet",col.names=TRUE,row.names=FALSE,append=FALSE)
Fehler in .jcall("RJavaTools", "Z", "hasField", .jcast(x, "java/lang/Object"), :
RcallMethod: cannot determine object class
and I have no particular idea what the problem could be.
PS: I'm running R 2.14.1 in the StatET 2.0 plugin in Eclipse 3.7 on a 64bit machine.
When you work in Eclipse, you can start R using either rj - a Java terminal, or RTerm - the native R terminal.
If you are using the rj terminal and something doesn't work, try the same thing with RTerm.
I have never tried to figure out why, but a few things don't work properly in rj. This includes all use of RCOM as well as printing of the return value of system().
I use rj by default because I like the way it deals with help (amongst other benefits).
But if things don't work, I try it in RTerm. One day I'll have some spare time and I'll take it up with the author.
PS. I want to stress that I absolutely love StatET in Eclipse. These oddities or rj are very minor inconveniences in the grand scheme of things.
From my experience these kind of errors are produced when the standard rj package is installed instead of the one supplied bij the StatET developer.
Check the installation guide here:
http://www.walware.de/goto/statet
If you would happen to be using Debian or Ubuntu, you can also use the repository from OpenAnalytics to install StatET and the correct rj packages in one go.
http://deb.openanalytics.eu/howto.html
I had same problem. Two codes work with my problem:
FIRST) Convert vector to dataframe:
library(xlsx)
data <- data.frame(c(1,2,3))
write.xlsx(data, file = "C:/Users/Name/Downloads/data.xlsx")
SECOND) Use another library:
`# Using openxlsx package
library(openxlsx)
dataD1 <- data.frame(c(1,2,3))
write.xlsx(dataD1, "C:/Users/Name/Downloads/dataD1.xlsx")
I hope you have solved your problem.

Categories