Skip to content

Commit

Permalink
GT-3146: Preventing Ghidra from launching with 32-bit Java (fixes Nat…
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanmkurtz committed Sep 12, 2019
1 parent d9da0f0 commit 0a3574d
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 37 deletions.
2 changes: 1 addition & 1 deletion DevGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The following is a list of dependencies, in no particular order.
This guide includes instructions for obtaining many of these at the relevant step(s).
You may not need all of these, depending on which portions you are building or developing.

* Java JDK 11 - Free long term support (LTS) versions of JDK 11 are provided by:
* Java JDK 11 (64-bit) - Free long term support (LTS) versions of JDK 11 are provided by:
- AdoptOpenJDK
- https://adoptopenjdk.net/releases.html?variant=openjdk11&jvmVariant=hotspot
- Amazon Corretto
Expand Down
9 changes: 5 additions & 4 deletions GhidraBuild/LaunchSupport/src/main/java/LaunchSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,11 @@ else if (max == 0) {
javaRange = min + "-" + max;
}

System.out.println("*******************************************************");
System.out.println("******************************************************************");
System.out.println(
javaName + " " + javaRange + " could not be found and must be manually chosen!");
System.out.println("*******************************************************");
javaName + " " + javaRange + " (" + javaConfig.getSupportedArchitecture() +
"-bit) could not be found and must be manually chosen!");
System.out.println("******************************************************************");

File javaHomeDir = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
Expand Down Expand Up @@ -259,7 +260,7 @@ else if (!line.isEmpty()) {
}
System.out.println(
"Java version " + javaVersion + " is outside of supported range: [" +
javaRange + "]");
javaRange + " " + javaConfig.getSupportedArchitecture() + "-bit]");
}
catch (FileNotFoundException e) {
System.out.println(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ public int getMaxSupportedJava() {
return maxSupportedJava;
}

/**
* Gets the Java configuration's supported Java architecture. All supported Java
* configurations must have an architecture of <code>64</code>.
*
* @return The Java configuration's supported Java architecture (64).
*/
public int getSupportedArchitecture() {
return 64;
}

/**
* Gets the Java configuration's compiler compliance level that was used to build the
* associated installation.
Expand Down Expand Up @@ -161,6 +171,10 @@ public boolean isSupportedJavaHomeDir(File dir, JavaFilter javaFilter) {
* @return True if the given Java version is supported by this Java launch configuration.
*/
public boolean isJavaVersionSupported(JavaVersion javaVersion) {
if (javaVersion.getArchitecture() != getSupportedArchitecture()) {
return false;
}

int major = javaVersion.getMajor();
return major >= minSupportedJava &&
(maxSupportedJava == 0 || major <= maxSupportedJava);
Expand Down Expand Up @@ -229,29 +243,34 @@ public JavaVersion getJavaVersion(File javaHomeDir, JavaFilter javaFilter)
*/
private JavaVersion runAndGetJavaVersion(File javaExecutable)
throws ParseException, IOException {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(new String[] { javaExecutable.getAbsolutePath(), "-version" });
String version = "";
String arch = "";
Process proc = Runtime.getRuntime().exec(new String[] { javaExecutable.getAbsolutePath(),
"-XshowSettings:properties", "-version" });
try (BufferedReader reader =
new BufferedReader(new InputStreamReader(proc.getErrorStream()))) {
String line;
while ((line = reader.readLine()) != null) {
while ((version.isEmpty() || arch.isEmpty()) && (line = reader.readLine()) != null) {
line = line.trim();

// If the _JAVA_OPTIONS or JAVA_TOOL_OPTIONS environment variables are set, STDERR
// will start with "Picked up..." lines that need to be ignored so we can get to the
// java version line.
if (line.startsWith("Picked up")) {
continue;
}

String[] parts = line.split("\\s");
if (parts.length < 3) {
throw new ParseException("Failed to parse version: " + line, 0);
String searchString = "java.version = ";
if (line.startsWith(searchString)) {
version = line.substring(searchString.length());
}

searchString = "sun.arch.data.model = ";
if (line.startsWith(searchString)) {
arch = line.substring(searchString.length());
}
return new JavaVersion(parts[2]);
}
}
if (version.isEmpty()) {
throw new ParseException("Failed to find Java version", 0);
}
if (arch.isEmpty()) {
throw new ParseException("Failed to find Java architecture", 0);
}
return new JavaVersion(version, arch);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,29 @@

/**
* Class to more conveniently represent a Java version string.
* <p>
* Note: this class has a natural ordering that is inconsistent with equals
* (the <code>architecture</code> part of the version is disregarded in the
* {@link #compareTo(JavaVersion)} method).
*/
public class JavaVersion implements Comparable<JavaVersion> {

private int major;
private int minor;
private int patch;
private int arch;

/**
* Creates a new {@link JavaVersion} object from the given version string.
*
* @param version A version string.
* @throws ParseException if the version string failed to parse. The exception's
* message has more detailed information about why it failed.
* @param architecture An architecture string (32 or 64).
* @throws ParseException if the version or architecture string failed to parse.
* The exception's message has more detailed information about why it failed.
*/
public JavaVersion(String version) throws ParseException {
parse(version);
public JavaVersion(String version, String architecture) throws ParseException {
parseVersion(version);
parseArchitecture(architecture);
}

/**
Expand Down Expand Up @@ -64,12 +71,21 @@ public int getPatch() {
return patch;
}

/**
* Gets the architecture.
*
* @return The architecture.
*/
public int getArchitecture() {
return arch;
}

@Override
public String toString() {
if (major < 9) {
return String.format("1.%d.%d_%d", major, minor, patch);
return String.format("1.%d.%d_%d (%d-bit)", major, minor, patch, arch);
}
return String.format("%d.%d.%d", major, minor, patch);
return String.format("%d.%d.%d (%d-bit)", major, minor, patch, arch);
}

@Override
Expand Down Expand Up @@ -102,6 +118,7 @@ public int hashCode() {
result = prime * result + major;
result = prime * result + minor;
result = prime * result + patch;
result = prime * result + arch;
return result;
}

Expand All @@ -126,6 +143,9 @@ public boolean equals(Object obj) {
if (patch != other.patch) {
return false;
}
if (arch != other.arch) {
return false;
}
return true;
}

Expand All @@ -136,7 +156,7 @@ public boolean equals(Object obj) {
* @throws ParseException if the version string failed to parse. The exception's message
* has more detailed information about why it failed.
*/
private void parse(String version) throws ParseException {
private void parseVersion(String version) throws ParseException {
if (version == null) {
throw new ParseException("Version is null", 0);
}
Expand All @@ -155,26 +175,26 @@ private void parse(String version) throws ParseException {
}

String[] versionParts = version.split("[._]");
int firstValue = parse(versionParts[0], "first value");
int firstValue = parseVersionPart(versionParts[0], "first value");
if (firstValue == 1) {
// Follows the Java 8 and earlier format of 1.major.minor_patch
if (versionParts.length > 1) {
major = parse(versionParts[1], "major");
major = parseVersionPart(versionParts[1], "major");
if (versionParts.length > 2) {
minor = parse(versionParts[2], "minor");
minor = parseVersionPart(versionParts[2], "minor");
if (versionParts.length > 3) {
patch = parse(versionParts[3], "patch");
patch = parseVersionPart(versionParts[3], "patch");
}
}
}
}
else if (firstValue >= 9) {
// Follows the Java 9 and later format of major.minor.patch
major = parse(versionParts[0], "major");
major = parseVersionPart(versionParts[0], "major");
if (versionParts.length > 1) {
minor = parse(versionParts[1], "minor");
minor = parseVersionPart(versionParts[1], "minor");
if (versionParts.length > 2) {
patch = parse(versionParts[2], "patch");
patch = parseVersionPart(versionParts[2], "patch");
}
}
}
Expand All @@ -192,7 +212,7 @@ else if (firstValue >= 9) {
* @throws ParseException if the version part string failed to parse to a valid version part
* integer.
*/
private int parse(String versionPart, String versionPartName) throws ParseException {
private int parseVersionPart(String versionPart, String versionPartName) throws ParseException {
try {
int i = Integer.parseInt(versionPart);
if (i < 0) {
Expand All @@ -205,4 +225,19 @@ private int parse(String versionPart, String versionPartName) throws ParseExcept
0);
}
}

/**
* Parses the architecture integer out of the given architecture string.
*
* @param architecture An architecture string.
* @throws ParseException if the architecture string failed to parse.
*/
private void parseArchitecture(String architecture) throws ParseException {
try {
arch = Integer.parseInt(architecture);
}
catch (NumberFormatException e) {
throw new ParseException("Failed to parse architecture: " + architecture, 0);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class WindowsJavaFinder extends JavaFinder {
protected List<File> getJavaRootInstallDirs() {
List<File> javaRootInstallDirs = new ArrayList<>();
javaRootInstallDirs.add(new File("C:\\Program Files\\Java"));
javaRootInstallDirs.add(new File("C:\\Program Files\\Amazon Corretto"));
return javaRootInstallDirs;
}

Expand Down
6 changes: 3 additions & 3 deletions GhidraDocs/InstallationGuide.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ <h3>Hardware</h3>
</ul>
<h3>Software</h3>
<ul>
<li>Java 11 Runtime and Development Kit (JDK) (see <a href="#JavaNotes">Java Notes</a>)</li>
<li>Java 11 64-bit Runtime and Development Kit (JDK) (see <a href="#JavaNotes">Java Notes</a>)</li>
<ul>
<li>Free long term support (LTS) versions of JDK 11 are provided by:</li>
<ul>
Expand Down Expand Up @@ -406,7 +406,7 @@ <h2><a name="Development"></a>Ghidra Development</h2>
<p>(<a href="#top">Back to Top</a>)</p>

<h2><a name="Upgrading"></a>Upgrade Instructions</h2>
<h3><a name="GeneralUpgrade"</a>General Upgrade Instructions</h3>
<h3><a name="GeneralUpgrade"></a>General Upgrade Instructions</h3>
<ol>
<li>
<b><font color="red">!!!Important!!!</font> BACKUP YOUR OLD PROJECTS FIRST!!<font color="red">
Expand Down Expand Up @@ -436,7 +436,7 @@ <h3><a name="GeneralUpgrade"</a>General Upgrade Instructions</h3>
</li>
</ol>

<h3><a name="ServerUpgrade"</a>Server Upgrade Instructions</h3>
<h3><a name="ServerUpgrade"></a>Server Upgrade Instructions</h3>
<ul>
<li>
Please refer to the<i>&lt;GhidraInstallDir&gt;</i>/server/svrREADME.html file for details on
Expand Down

0 comments on commit 0a3574d

Please sign in to comment.