NullPointerException at java.lang.String.length(St

2019-04-16 05:04发布

问题:

I'm completely riddled with the following stacktrace... Looks like it is caused by the String instance which has null char array internally. Putting aside reflection, is there any "legal" way to get such String instance in java?

Caused by: java.lang.NullPointerException: null
    at java.lang.String.length(String.java:611) ~[na:1.8.0_31]
    at org.apache.commons.lang.StringUtils.isEmpty(StringUtils.java:195) ~[commons-lang-2.6.jar:2.6]

回答1:

If by legal you mean by using the constructors and methods exposed by the String API, then, no, it is not possible to reproduce such an exception.

There are ways to instantiate classes that will skip constructors and initializers. sun.misc.Unsafe provides such a utility, allocateInstance.

public static void main(String[] args) throws Exception {
    String string = (String) getUnsafe().allocateInstance(String.class);
    System.out.println(string.length());
}

@SuppressWarnings("restriction")
private static Unsafe getUnsafe() {
    try {
        Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");
        singleoneInstanceField.setAccessible(true);
        return (Unsafe) singleoneInstanceField.get(null);
    } catch (Exception e) {
    }
    return null;
}

In this case, the value field of String will remain null and the NullPointerException will occur when invoking length().

Similarly, some proxying libraries that use byte code manipulation can omit an invocation to super() when creating proxy subclasses, effectively skipping initialization. Here's a related question where mocking failed to properly initialize an ArrayList's backing array.



回答2:

Also see for reports of an npe on the same line in String. - NullPointerException from within String is confusing - java Strings odd behavior with collator - https://twitter.com/s1m0nw/status/829728992907448326

There's a String(char[] value, boolean shared) package protected constructor that does not do a null check.

My guess that this is used in combination with String intern, so not called directly by your code.

One hypothetical scenario here could be multithreading in combination with String intern. The value field in String is final but not volatile. This may lead to weird issues early in it's lifecycle.