Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible heap pollution via varargs parameter

I understand this occurs with Java 7 when using varargs with a generic type;

But my question is..

What exactly does Eclipse mean when it says "its use could potentially pollute the heap?"

And

How does the new @SafeVarargs annotation prevent this?

like image 632
hertzsprung Avatar asked Sep 17 '12 15:09

hertzsprung


2 Answers

Heap pollution is a technical term. It refers to references which have a type that is not a supertype of the object they point to.

List<A> listOfAs = new ArrayList<>(); List<B> listOfBs = (List<B>)(Object)listOfAs; // points to a list of As 

This can lead to "unexplainable" ClassCastExceptions.

// if the heap never gets polluted, this should never throw a CCE B b = listOfBs.get(0);  

@SafeVarargs does not prevent this at all. However, there are methods which provably will not pollute the heap, the compiler just can't prove it. Previously, callers of such APIs would get annoying warnings that were completely pointless but had to be suppressed at every call site. Now the API author can suppress it once at the declaration site.

However, if the method actually is not safe, users will no longer be warned.

like image 92
Ben Schulz Avatar answered Sep 23 '22 06:09

Ben Schulz


When you declare

public static <T> void foo(List<T>... bar) the compiler converts it to

public static <T> void foo(List<T>[] bar) then to

public static void foo(List[] bar)

The danger then arises that you'll mistakenly assign incorrect values into the list and the compiler will not trigger any error. For example, if T is a String then the following code will compile without error but will fail at runtime:

// First, strip away the array type (arrays allow this kind of upcasting) Object[] objectArray = bar;  // Next, insert an element with an incorrect type into the array objectArray[0] = Arrays.asList(new Integer(42));  // Finally, try accessing the original array. A runtime error will occur // (ClassCastException due to a casting from Integer to String) T firstElement = bar[0].get(0); 

If you reviewed the method to ensure that it doesn't contain such vulnerabilities then you can annotate it with @SafeVarargs to suppress the warning. For interfaces, use @SuppressWarnings("unchecked").

If you get this error message:

Varargs method could cause heap pollution from non-reifiable varargs parameter

and you are sure that your usage is safe then you should use @SuppressWarnings("varargs") instead. See Is @SafeVarargs an appropriate annotation for this method? and https://stackoverflow.com/a/14252221/14731 for a nice explanation of this second kind of error.

References:

  • http://docs.oracle.com/javase/7/docs/technotes/guides/language/non-reifiable-varargs.html
  • http://docs.oracle.com/javase/tutorial/java/generics/nonReifiableVarargsType.html#heap_pollution
like image 26
Gili Avatar answered Sep 22 '22 06:09

Gili