forbidden-apis: static method hiding produces false positives when original method is forbidden

Consider the following code (contrived example, but simplest I could find in a hurry that anyone can try using only JDK methods w/o needing third-party libs) …

import java.util.BitSet;
public class Main {
    public static final long[] data = new long[] {1, 2, 3, 4};
    
    public static void main(String[] args) {
        System.out.println(X.valueOf(data).toString());  // Line 6
        System.out.println(Y.valueOf(data).toString());  // Line 7
        System.out.println((new Z()).go());
    }

    public static class X extends BitSet { }

    public static class Y extends X {
        public static BitSet valueOf(long[] longs) {
            return new BitSet();
        }
    }

    public static class Z extends Y {
        public String go() {
            return valueOf(data).toString();            // Line 21
        }
    }
}

Let’s see what happens when we tell forbidden-apis we don’t want our code to use Bitset.valueOf(...)

hossman@slate:~/tmp/fapi-bug$ cat sigs.txt 
java.util.BitSet#valueOf(**)
hossman@slate:~/tmp/fapi-bug$ java -jar forbiddenapis-3.6.jar -d . -f sigs.txt 
Scanning for classes to check...
Reading API signatures: /home/hossman/tmp/fapi-bug/sigs.txt
Loading classes to check...
Scanning classes for violations...
ERROR: Forbidden method invocation: java.util.BitSet#valueOf(**)
ERROR:   in Main$Z (Main.java:21)
ERROR: Forbidden method invocation: java.util.BitSet#valueOf(**)
ERROR:   in Main (Main.java:6)
ERROR: Forbidden method invocation: java.util.BitSet#valueOf(**)
ERROR:   in Main (Main.java:7)
ERROR: Scanned 4 class file(s) for forbidden API invocations (in 0.06s), 3 error(s).
ERROR: Check for forbidden API calls failed, see log.

It correctly identified that line 6 is “bad” for it’s “Forbidden method invocation”, but the errors reported for Lines 6 & 21 are false positives – those lines do not invoke Bitset.valueOf(...), they invoke Y.valueOf(...), which hides the static method with the same name provided by Y’s ancestor class…

hossman@slate:~/tmp/fapi-bug$ java Main 
{0, 65, 128, 129, 194}
{}
{}

About this issue

  • Original URL
  • State: closed
  • Created 8 months ago
  • Comments: 27 (23 by maintainers)

Commits related to this issue

Most upvoted comments

no no, this is a nice to have. no urgency needed.

I did see it. But I still think maybe forbiddenapis shouldn’t try to play JVM here - if a static method doesn’t exist at its target class, something is wrong - classes are stale and this should perhaps produce a warning (javac should never produce such bytecode because it always resolves static call to a concrete class).

Yes, if you scan your own compiled classes the output of javac should be “uptodate”. Elasticserach uses forbiddenapis also to scan JAR files on unknown source which might be very outdated.

Anyways, I think the simplest / only thing to change is: If method call is static (invokestatic or MethodHandle with tag H_INVOKESTATIC) it should stop at first found method.

Btw., the same apples for fields.