StringBuilder: ArrayIndexOutOfBoundsException - java

We're experiencing a strange issue with WebSphere 7/ IBM JDK 6, where one of the nodes has some initialization issue.
We have some code which calls InitialContext.lookup and on this node we're getting sometimes the following exception:
Caused by: java.lang.ArrayIndexOutOfBoundsException
at java.lang.String.getChars(String.java:666)
at java.lang.StringBuilder.append(StringBuilder.java:207)
at javax.naming.spi.NamingManager.getURLContext(NamingManager.java:646)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:422)
at javax.naming.InitialContext.lookup(InitialContext.java:436)
[...]
We had a look at the source code of javax.naming.spi.NamingManager.getURLContext:
public static Context getURLContext(String schema, Hashtable<?, ?> envmt)
throws NamingException {
if (null == schema || 0 == schema.length() || null == envmt) {
return null;
}
// obtain pkg prefixes from hashtable
String pkgPrefixes[] = EnvironmentReader
.getFactoryNamesFromEnvironmentAndProviderResource(envmt, null,
Context.URL_PKG_PREFIXES);
for (String element : pkgPrefixes) {
// create factory instance
ObjectFactory factory;
String clsName = element + "." //$NON-NLS-1$
+ schema + "." //$NON-NLS-1$
+ schema + "URLContextFactory"; //$NON-NLS-1$
[...]
Line 646 is the enhanced for-loop, but the next statement is a String concatenation and is probably replaced with a StringBuilder by the compiler.
We did some quick unit tests on StringBuilder but couldn't provoke an ArrayIndexOutOfBoundsException.
How can an ArrayIndexOutOfBoundsException be thrown here and how can we avoid it?
Edit:
We are using the following java version:
java version "1.6.0"
Java(TM) SE Runtime Environment (build pxa6460sr9fp2ifix-20110913_02(SR9 FP2+IV03622+IZ99243))
IBM J9 VM (build 2.4, JRE 1.6.0 IBM J9 2.4 Linux amd64-64 jvmxa6460sr9-20110912_90359 (JIT enabled, AOT enabled)
J9VM - 20110912_090359
JIT - r9_20101028_17488ifx31
GC - 20101027_AA)
JCL - 20110727_04

This is a known bug of the JIT compiler of the IBM JVM. The workaround seems to be the exclusion of getChars from the JIT compilation:
-Xjit:exclude={ProgramClass.callStringGetChars*}
See IZ78413: JIT-COMPILED STRING.GETCHARS THROWS UNEXPECTED ARRAYINDEXOUTOFBO UNDSEXCEPTION for reference.

The code above seems to return null if you pass a null environment hashtable.
This makes me wonder if you are instantiating InitialContext with an argument of some sort.
If the code above is indeed the source, passing a null environment hashtable will short-circuit getURLContext() to return null prior to the string concatenation loop.
Can you try new InitialContext() or new InitialContext(null) if you do not need to specify JNDI environment vars (e.g. use default JNDI env)?

Related

What is a valid UUID?

I generate UUIDs, and valid them against a Regex in my code; I just ran into problems that confused me
Here is the code that generates UUIDs (in a mongodb context)
import java.util.UUID;
... ...
Document setOnInsert = new Document(Params.sender, UUID.randomUUID())
.append(Params.userDevice, userDevice)
.append(Params.hostId,"");
This is the code of validating an UUID; I had copied the Regex from this post
static final Pattern UUID = Pattern.compile("([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})");
public static boolean isUUID(String uuid){
if(uuid == null){
return false;
}else{
return UUID.matcher(uuid).matches();
}
}
and below are the 2 UUIDs that I have problems with
aa4aaa2c-c6ca-d5f5-b8b2-0b5c78ee2cb7
b24dd64c-de6b-5bf6-6283-aa2167cc93a7
These two UUIDs had been generated by the code mentioned above; the validating method (isUUID()) judged them as invalid in my latest debug; yet I posted these UUIDs to an online validator , and it says ok
This is my system information
wjz#bj:~$ java -version
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
wjz#bj:~$
wjz#bj:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.1 LTS
Release: 16.04
Codename: xenial
wjz#bj:~$
Some background: I had been working on jdk 1.8.0_111; these UUIDs had been generated then, and had no problems. then I upgraded to 1.8.0_121 today, and run into this problem...
So my question is: Whether the above mentioned UUIDs are correct or wrong? who to believe, the generator or the validation
My suggestion is, do not reinvent the wheel.
Basically, if you generate the ids with UUID.randomUUID(), there is no need to validate them.
If you are anyway curious that they might get manipulated manually.
You can just use UUID.fromString(yourUUID) and catch the IllegalArgumentExcepetion and the NumberFormatException that might be thrown.
Throws IllegalArgumentExcepetion:
If name does not conform to the string representation as described in toString()
Furthermore, you can check behind, if the UUID got converted correctly with
UUID id = UUID.fromString(yourUUID);
if(id.toString().equals(yourUUID){
//success
}
You can use UUID.randomUUID() which will generate a valid UUID, you dont need the regx.
Had a look at some other SO answers, other languages ..., and here is a pure Java solution which handles v4 cases (as used by default in Java 8):
UUID myUuid = UUID.fromString(uuidStr); // Step 1, throws errors !
... myUuid.version() == 4 // Step 2, check for the version you desire
See: https://docs.oracle.com/javase/9/docs/api/java/util/UUID.html#version--
Here is an example of a perfectly valid UUID string but version 1:
public static void main(final String[] args) {
final UUID myUuid = UUID.fromString("61614667-d279-11e7-a5ac-f941ac8dfc39");
System.out.println(myUuid.version()); // Prints 1, not 4 !
}
To try out more v4 UUIDs use UUID.randomUUID() or online:
https://www.uuidgenerator.net/version4
Note: UUID.randomUUID() of Java will work well see How good is Java's UUID.randomUUID?
Security note:
Static factory to retrieve a type 4 (pseudo randomly generated) UUID.
The UUID is generated using a cryptographically strong pseudo random
number generator
There are several aspects:
Total UUID length
Characters used
Valid size of groups (between dashes)
Lower case or upper case
Valid version
Valid variant
Nil allowed
To have a code example, see the UUID validator implementation I recently added to Apache Commons Validator. It's not yet been merged, but you can vote for it here: https://github.com/apache/commons-validator/pull/68

Strange NPE when iterating over result of ClassLoader.getResources()

I would assume that the following code is safe, nevertheless I am getting an NPE while invoking hasMoreElements(). Any ideas what might be wrong?
I should add that I am using Java 1.7.0_55-b13 on Windows, 64 bit.
final List<URL> urls = new ArrayList<URL>();
final String plUri = "META-INF/plugin.xml";
Enumeration<URL> urlsEn =
Thread.currentThread().getContextClassLoader().getResources(pluginsUri);
if (urlsEn != null) {
while (urlsEn.hasMoreElements()) { // NPE happens here
final URL u = urlsEn.nextElement();
urls.add(u);
}
}
Stack trace:
java.lang.NullPointerException
at sun.misc.MetaIndex.mayContain(MetaIndex.java:243)
at sun.misc.URLClassPath$JarLoader.getResource(URLClassPath.java:830)
at sun.misc.URLClassPath$2.next(URLClassPath.java:273)
at sun.misc.URLClassPath$2.hasMoreElements(URLClassPath.java:283)
at java.lang.ClassLoader$2.hasMoreElements(ClassLoader.java:1322)
at sun.misc.CompoundEnumeration.next(CompoundEnumeration.java:45)
at sun.misc.CompoundEnumeration.hasMoreElements(CompoundEnumeration.java:54)
at sun.misc.CompoundEnumeration.next(CompoundEnumeration.java:45)
at sun.misc.CompoundEnumeration.hasMoreElements(CompoundEnumeration.java:54)
at com.github.jochen.afw.core.guice.GuiceComponentFactoryBuilder.getComponentUrls(GuiceComponentFactoryBuilder.java:256)
at com.github.jochen.afw.core.guice.GuiceComponentFactoryBuilder.build(GuiceComponentFactoryBuilder.java:160)
at com.github.jochen.afw.core.guice.GuiceComponentFactoryBuilderTest.testSuccessfullConfiguration(GuiceComponentFactoryBuilderTest.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
....
I hate to suggest your problem is something so simple, but could pluginsUri be null here? At least in your code snippet, you create a plUri variable but then pass in an unmentioned pluginsUri to ClassLoader.getResources().
From your stack trace, searching for "URLClassPath null pointer exception" uncovered this question which looks to be the same stack trace. In their case the argument to getResources() is clearly null.
Looking at the Java 7 codebase, we see that MetaIndex:243 is:
if (entry.startsWith(conts[i])) {
And entry could be null at this line. Looking higher up the stack, entry looks to be the name argument you passed to ClassLoader.getResources().
This SSCCE:
public class ClassLoaderNPE {
public static void main(String[] args) throws IOException {
Enumeration<URL> urls = ClassLoader.getSystemClassLoader().getResources(null);
System.out.println(urls.hasMoreElements());
}
}
replicates your stack trace (in Java 8, no less):
$ java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
$ java -cp . ClassLoaderNPE
Exception in thread "main" java.lang.NullPointerException
at sun.misc.MetaIndex.mayContain(MetaIndex.java:242)
at sun.misc.URLClassPath$JarLoader.getResource(URLClassPath.java:995)
at sun.misc.URLClassPath$2.next(URLClassPath.java:288)
at sun.misc.URLClassPath$2.hasMoreElements(URLClassPath.java:298)
at java.lang.ClassLoader$2.hasMoreElements(ClassLoader.java:1278)
at sun.misc.CompoundEnumeration.next(CompoundEnumeration.java:45)
at sun.misc.CompoundEnumeration.hasMoreElements(CompoundEnumeration.java:54)
at sun.misc.CompoundEnumeration.next(CompoundEnumeration.java:45)
at sun.misc.CompoundEnumeration.hasMoreElements(CompoundEnumeration.java:54)
at ClassLoaderNPE.main(ClassLoaderNPE.java:9)
The JDK does not appear specify what happens if name is null. I've filed a bug to suggest fixing this behavior, or at least clarifying the documentation. I'll update this post if/when Oracle accepts the issue.
Update: The report is tracked as JDK-8136831, and has been fixed in Java 9.

Java check latest version programmatically

Goal: check java's version on a machine (I can get this from java -version). Compare it with latest available from java website
I would like to know if there is any way I can check for latest Java releases assuming that I have JRE/JDK installed on a machine.
If I can do this through Java itself, my solution would become platform independent. I could use java.net.URL class to send a request to Java website and get the HTML, however the response would be dynamic as Oracle can change their website and styles and possibly will have maintenance issues in long run.
I have looked at javatester.org, but I would not want it through an applet but through command line (which I can add to a script).
Through javacpl.exe, I can schedule periodic checks, but I would like to do it on demand.
The answer is actually quite simple. http://java.com/en/download/testjava.jsp issues a request to http://java.com/applet/JreCurrentVersion2.txt. That file currently contains a single version number: '1.7.0_11'...which is the latest and greatest, indeed.
Java code example
try (BufferedReader br = new BufferedReader(new InputStreamReader(new URL(
"http://java.com/applet/JreCurrentVersion2.txt").openStream()))) {
String fullVersion = br.readLine();
String version = fullVersion.split("_")[0];
String revision = fullVersion.split("_")[1];
System.out.println("Version " + version + " revision " + revision);
} catch (IOException e) {
// handle properly
}
Update 2014-03-20
Eventhough Java 8 was recently released http://java.com/applet/JreCurrentVersion2.txt currently still returns 1.7.0_51.
Update 2016-07-13
Looks like we need to come back to this every few months... Currently you need to scan http://java.com/en/download/installed8.jsp for a JavaScript variable latest8Version. So, you could run curl -s https://java.com/en/download/installed8.jsp | grep latest8Version.
Update 2018-08-19
http://javadl-esd-secure.oracle.com/update/baseline.version is another hot spot as mentioned in some other answer.
An URL very similar to the now defunct "JreCurrentVersion2.txt":
http://javadl-esd-secure.oracle.com/update/baseline.version
The contents of the link look like this:
1.8.0_111
1.7.0_121
1.6.0_131
1.5.0_99
1.4.2_43
You can easily parse the contents to find the latest JRE versions.
UPDATE: I don't recommend this method because this JRE is the one that has the Ask.com toolbar. You're better off downloading it yourself and distributing it yourself.
The jusched.exe program accesses the following URL to find out what versions are available. I think it's less likely to change because jusched is installed on millions of computers.
https://javadl-esd-secure.oracle.com/update/1.7.0/map-m-1.7.0.xml
Here is a snippet of what it returns for me:
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>
<java-update-map version="1.0">
<mapping>
<version>1.7.0_17</version>
<url>https://javadl-esd-secure.oracle.com/update/1.7.0/au-descriptor-1.7.0_25-b17.xml</url>
</mapping>
<mapping>
<version>1.7.0_21</version>
<url>https://javadl-esd-secure.oracle.com/update/1.7.0/au-descriptor-1.7.0_25-b17.xml</url>
</mapping>
</java-update-map>
To get the actual version that it is pointing to you have to fetch the above URL. Here is another snippet of what this XML looks like:
xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- XML file to be staged anywhere, and pointed to by map.xml file -->
<java-update>
<information version="1.0" xml:lang="en">
<caption>Java Update - Update Available</caption>
<title>Java Update Available</title>
<description>Java 7 Update 25 is ready to install. Installing Java 7 Update 25 might uninstall the latest Java 6 from your system. Click the Install button to update Java now. If you wish to update Java later, click the Later button.</description>
<moreinfo>http://java.com/moreinfolink</moreinfo>
<AlertTitle>Java Update Available</AlertTitle>
<AlertText>A new version of Java is ready to be installed.</AlertText>
<moreinfotxt>More information...</moreinfotxt>
<url>http://javadl.sun.com/webapps/download/GetFile/1.7.0_25-b17/windows-i586/jre-7u25-windows-i586-iftw.exe</url>
<version>1.7.0_25-b17</version>
<post-status>https://nometrics.java.com</post-status>
<cntry-lookup>http://rps-svcs.sun.com/services/countrylookup</cntry-lookup>
<predownload></predownload>
<options>/installmethod=jau FAMILYUPGRADE=1 SPWEB=http://javadl-esd.sun.com/update/1.7.0/sp-1.7.0_25-b17</options>
<urlinfo>24595ec7f861bc67e572f1e4ad3992441335e1a7</urlinfo>
</information>
</java-update>
The version tag contains the full version number.
You could parse the Java SE Downloads page to extract the Java versions.
That way, you get the version of both JDK6 and JDK7, which allows you to test your particular JDK (6 or 7) against the latest Oracle one.
(As opposed to the Free Java Download page, which only lists the JDK7)
Her is a crude script in Go, which you can compile on Windows, Unix, MacOs into a single independent executable, and use within a command line or a script:
package main
import (
"bytes"
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"os/exec"
"regexp"
)
type Jdk struct {
Url string
Ver string
update string
}
func main() {
resp, err := http.Get("http://www.oracle.com/technetwork/java/javase/downloads/index.html")
if err != nil {
fmt.Printf("Error on http Get: %v\n", err)
return
}
bodyb, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("QueriesForOwner: error in ReadAll: %v\n", err)
return
}
br := bytes.NewBuffer(bodyb)
jdkre, err := regexp.Compile(`h3[^\r\n]+(/technetwork/java/javase/downloads/(jdk(?:6|7)(?:u(\d+))?)-downloads-\d+\.html)`)
if err != nil {
fmt.Printf("extract: error in regexp compilation: %v\n", err)
return
}
jdks := jdkre.FindAllSubmatch(br.Bytes(), -1)
jdk7 := Jdk{string(jdks[0][4]), string(jdks[0][5]), string(jdks[0][6])}
jdk6 := Jdk{string(jdks[1][7]), string(jdks[1][8]), string(jdks[1][9])}
fmt.Printf("Jdk7: %v\nJdk6: %v\n", jdk7, jdk6)
jver, err := exec.Command("java", "-version").CombinedOutput()
if err != nil {
fmt.Printf("*ExitError from java -version:", err)
return
}
fmt.Println("JVer: '", string(jver), "'")
jverre, err := regexp.Compile(`1.(\d).\d(?:_(\d+))"`)
jvers := jverre.FindSubmatch(jver)
jj := string(jvers[0])
jv := string(jvers[1])
ju := string(jvers[2])
jdk := jdk6
if jv == "7" {
jdk = jdk7
}
if jdk.update != ju {
fmt.Println("Local JDK *NOT* up-to-date: you have ", jj, ", Oracle has ", jdk.Ver)
} else {
fmt.Println("Local JDK *up-to-date*: you have ", jj, ", equals to Oracle, which has", jdk.Ver)
}
}
Again, this is a crude script, oriented toward JDK, and you would need to adapt it to your specific need, making its output and exit status match what you need for your script.
On my (PC) workstation, it returns:
Jdk7: {/technetwork/java/javase/downloads/jdk7u9-downloads-1859576.html jdk7u9 9}
Jdk6: {/technetwork/java/javase/downloads/jdk6u37-downloads-1859587.html jdk6u37 37}
JVer: ' java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b05)
Java HotSpot(TM) Client VM (build 20.6-b01, mixed mode, sharing)
'
Local JDK *NOT* up-to-date: you have 1.6.0_31" , Oracle has jdk6u37
I don't know what information you are exactly looking for, but you can get some version information using
System.getProperty("java.version");
If this is not what you're looking for, check the other available properties here:
http://docs.oracle.com/javase/6/docs/api/java/lang/System.html#getProperties()
As for the latest available version, I guess you'd have to parse this site manually:
http://java.com/en/download/index.jsp
The latest version is on there, currently it's
Version 7 Update 9
You write that this is not what you want because "Oracle can change their website and styles". However, you want to find out the latest version of Java by accessing their service (website in this case). As long as you're not paying for this, they have no obligation to you, and can change the service whenever they want without your consent. And even when you're a paying customer, the best you can hope for is that they will inform you of upcoming changes, and your maintenance issues will remain.
Remember, it's THEIR service you want to use.
I have solved a similar issue some time ago with this groovy script (disclaimer: is somehow a "toy" script):
#Grapes([
#Grab(group='org.ccil.cowan.tagsoup', module='tagsoup', version='1.2.1')
])
def slurper = new XmlSlurper(new org.ccil.cowan.tagsoup.Parser())
def url = new URL("http://www.java.com/download/manual.jsp")
def html
url.withReader { reader ->
html = slurper.parse(reader)
}
def lastJava = html.body.div.div.div.strong.text()
println "Last available java version: ${lastJava}"
println "Currently installed java version: ${System.properties["java.version"]}"
It yields something like:
Last available java version:
Version 7 Update 9
Currently installed java version: 1.7.0_07
If you want to avoid maintenance issues due to changes to the page structure, maybe a better option is to search for a line containing "Version x Update y".
To get all system variables
Properties properties = System.getProperties();
System.out.println(properties);
Sample output, this might be different in your system depending on your OS and Java JDK/JRE version.
{
java.runtime.name = Java(TM) SE Runtime Environment,
sun.boot.library.path = C:\Program Files\Java\jdk1.8.0_31\jre\bin,
java.vm.version = 25.31-b07,
java.vm.vendor = Oracle Corporation,
java.vendor.url = http://java.oracle.com/,
path.separator = ;,
idea.launcher.port = 7534,
java.vm.name = Java HotSpot(TM) 64-Bit Server VM,
file.encoding.pkg = sun.io,
user.country = NP,
user.script = ,
sun.java.launcher = SUN_STANDARD,
sun.os.patch.level = ,
java.vm.specification.name = Java Virtual Machine Specification,
user.dir = C:\Users\...\roid,
java.runtime.version = 1.8.0_31-b13,
java.awt.graphicsenv = sun.awt.Win32GraphicsEnvironment,
java.endorsed.dirs = C:\Program Files\Java\jdk1.8.0_31\jre\lib\endorsed,
os.arch = amd64,
java.io.tmpdir = C:\Windows\TEMP\,
line.separator = ,
java.vm.specification.vendor = Oracle Corporation,
user.variant = ,
os.name = Windows 8.1,
sun.jnu.encoding = Cp1252,
java.library.path = C:\Program...roid,
java.specification.name = Java Platform API Specification,
java.class.version = 52.0,
sun.management.compiler = HotSpot 64-Bit Tiered Compilers,
os.version = 6.3,
user.home = C:\Users\Xxx,
user.timezone = Asia/Kathmandu,
java.awt.printerjob = sun.awt.windows.WPrinterJob,
file.encoding = UTF-8,
idea.launcher.bin.path = C:\Program Files (x86)\xxx\bin,
java.specification.version = 1.8,
java.class.path = C:\Program Files\Java\jdk1.8.0_31\jre\lib\charsets.jar;...,
user.name = Xxx,
java.vm.specification.version = 1.8,
sun.java.command = com.xxxx.ameras,
java.home = C:\Program Files\Java\jdk1.8.0_31\jre,
sun.arch.data.model = 64,
user.language = en,
java.specification.vendor = Oracle Corporation,
awt.toolkit = sun.awt.windows.WToolkit,
java.vm.info = mixed mode,
java.version = 1.8.0_31,
java.ext.dirs = C:\Program Files\Java\jdk1.8.0_31\jre\lib\ext;...,
java.vendor = Oracle Corporation,
file.separator = \,
java.vendor.url.bug = http://bugreport.sun.com/bugreport/,
sun.io.unicode.encoding = UnicodeLittle,
sun.cpu.endian = little,
sun.desktop = windows,
sun.cpu.isalist = amd64
}
Retrive only specific variable
String javaVersion = System.getProperty("java.version");
System.out.println(javaVersion);
Output
1.8.0_31
#MarcelStör's solution no longer works - the version in the file is 1.8.0_51, while the actual latest version is 1.8.0_91/92. If you go to the Java test page in Firefox or Chrome and open the development console you can get the variable latest8Version which currently is 1.8.0_91. This could be wrapped in a Selenium/Firefox solution, but is an incredibly hacky way of getting this information.
System.getProperty("java.vm.specification.version");
System.getProperty("java.version");

OutOfMemory error in toString when ISO-8859-1 encoding in SuSE Linux

I've been beating my head on this issue for a while. I'm taking a 27K encoded string (similar to URL encoding) and turning it back into a 9K "ISO-8859-1" plaintext string.
byte outarray[] = new byte[decoded_msg_length]; // 9K
byte inarray[];
try {
inarray = instring.getBytes("ISO-8859-1"); // eg: "ÀÀÀÚßÐÀÀÃÐéÙÓåäàÈÂÁÙÈ...."
inarray = null; // free up whatever memory possible.
// ... for loop decodes chunks of 4 bytes...
Runtime runtime = Runtime.getRuntime();
System.out.println("freeMemory1="+runtime.freeMemory()); // freeMemory1=86441120
// yes I've tried methods like new String( outarray, "ISO-8859-1" );, etc.
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byteStream.write(outarray);
outarray=null;
runtime.gc();
System.out.println("freeMemory2="+runtime.freeMemory()); //freeMemory2=133761568
// return new String(outarray,"ISO-8859-1"); // OutOfMemoryException thrown here
// return new String(outarray); // OutOfMemoryException thrown here too
return byteStream.toString("ISO-8859-1"); // OutOfMemoryException thrown here also
// sample output: "JOHN H SMITH 123 OAK ST..."
} catch( IOException ioe ) {
...
}
// Thrown exception:
Exception in thread "main" java.lang.OutOfMemoryError
at java.lang.StringCoding.decode(StringCoding.java:510)
at java.lang.String.<init>(String.java:232)
at java.io.ByteArrayOutputStream.toString(ByteArrayOutputStream.java:195)
...
It looks like I have plenty of memory. This same code runs fine with less than half as much free memory in Windows. I'm running this as a single standalone class. Anyone know of any Linux encoding issues with a JRE memory leak?
$ java -version
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build pxi32dev-20080315 (SR7))
IBM J9 VM (build 2.3, J2RE 1.5.0 IBM J9 2.3 Linux x86-32 j9vmxi3223-20080315 (JIT enabled)
J9VM - 20080314_17962_lHdSMr
JIT - 20080130_0718ifx2_r8
GC - 200802_08)
JCL - 20080314
The Java Heap Size may have a different default limit in your Linux environment vs Windows. You can check this via the Runtime.maxMemory() method.
http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Runtime.html#maxMemory()
If the limit is smaller under Linux you can increase it via the -Jmx command-line argument to java,
java -Xmx1024m YourClassNameHere
The 1024m will increase the size of the heap to 1GB, you can adjust the amount as needed. This is a max amount, your program may use much less.
I found the solution, though I'm not sure the exact reason why it occurs - most likely some internal static buffer variable. Even though the error throws at the toString, the fix was to resize decoded_msg_length to be the same as instring.
For some reason I have yet to fathom, instring.getBytes("ISO-8859-1") sets the size of the some internal buffer filled by byteStream.toString("ISO-8859-1"). Setting the decoded_msg_length size one byte short of that length causes Java to throw the error, even though there's nothing thread-unsafe, and I'm working with two different variables.
To top it off I can use CharsetDecoder and it'll still fail. I'll chalk it up to an OS JVM bug. Without that freakish fix, the code works fine in other OS's and JVMs.

JDK compiler error

Before anyone screams about EOL'ed JDK, I'd like to point out that my question is not about how to compile the following. There is a real question here and it's not about JDK 1.5 being EOL'ed...
The following under JDK 1.5, up to 1.5.0_22 (the last one I could find) produces on my system a compiler error:
private Object[] boozinga() {
boolean b = Math.abs(42) > 0;
Object[] res = new Object[1];
res[0] = b ? new int[1] : new String[1];
return res;
}
Changing the Math.abs(42) > 0 to true allows compilation.
Changing the ternary "assignment" to an if/else allows compilation.
Using JDK 1.6 allows compilation.
So I was wondering: is there something not legal in the above code under Java 1.5 and that is allowed under Java 1.6?
Does it crash for those of you that are under Java 1.5 too?
The crash says something like this:
An exception has occured in the
compiler (1.5.0_22). Please file a bug
at the Java Developer Connection
(http://java.sun.com/webapps/bugreport)
after checking the Bug Parade for
duplicates. Include your program and
the following diagnostic in your
report. Thank you.
I take it filling a bug report for an EOL'ed JDK is an exercice in futility but still, I'd still like to know if the above is valid Java 1.5 code or not.
I think it is legal. The evidence is that JDK 1.6.0_21 compiles it with options -source 1.5 -target 1.5. Can't you use JDK 1.6 with these options to compile and JRE 1.5 to run?
It crashes for me, too (JDK 1.5.0_12). It crashes for me even with:
public Object boozinga() {
boolean b = true;
Object res = b ? new int[1] : new String[1];
return res;
}
The difficulty for the compiler is that the type of b ? new int[1] : new String[1] is java.lang.Object & java.io.Serializable & java.lang.Cloneable.
The problem here is that the compiler has trouble to decide the type of the expression b ? new int[1] : new String[1]. I had something like this before (with 1.1.8 or 1.2, I think - but with a real error message, not a compiler crash), and then simply used a cast to help the compiler here.
res[0] = b ? (Object)new int[1] : new String[1];
I didn't look what the language specification says about this - but the compiler should never crash with an exception, it should give a real error message.

Categories

Resources