In Java, arrays are objects and support object methods such as Object.equals()
. However, arrays do not support any methods besides those provided by Object
. Consequently, using Object.equals()
on any array compares only array references, not their contents. Programmers who wish to compare the contents of two arrays must use the static two-argument Arrays.equals()
method. This method considers two arrays equivalent if both arrays contain the same number of elements, and all corresponding pairs of elements in the two arrays are equivalent, according to Object.equals()
. In other words, two arrays are equal if they contain equivalent elements in the same order. To test for reference equality, use the reference equality operators, ==
and !=
.
Because the effect of using Object.equals()
to compare two arrays is often misconstrued as content equality, and because a better alternative exists in the use of reference equality operators, the use of the Object.equals()
method to compare two arrays is disallowed.
Noncompliant Code Example
This noncompliant code example uses the Object.equals()
method to compare two arrays:
int[] arr1 = new int[20]; // Initialized to 0 int[] arr2 = new int[20]; // Initialized to 0 System.out.println(arr1.equals(arr2)); // Prints false
Compliant Solution
This compliant solution compares the content of two arrays using the two-argument Arrays.equals()
method:
int[] arr1 = new int[20]; // Initialized to 0 int[] arr2 = new int[20]; // Initialized to 0 System.out.println(Arrays.equals(arr1, arr2)); // Prints true
Compliant Solution
This compliant solution compares the array references using the reference equality operators ==
:
int[] arr1 = new int[20]; // Initialized to 0 int[] arr2 = new int[20]; // Initialized to 0 System.out.println(arr1 == arr2); // Prints false
Risk Assessment
Using the equals()
method or relational operators with the intention of comparing array contents produces incorrect results, which can lead to vulnerabilities.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
EXP02-J | Low | Likely | Low | P9 | L2 |
Automated Detection
Static detection of calls to Object.equals()
is straightforward. However, it is not always possible to statically resolve the class of a method invocation's target. Consequently, it may not always be possible to determine when Object.equals()
is invoked for an array type.
Tool | Version | Checker | Description |
---|---|---|---|
CodeSonar | 8.1p0 | JAVA.COMPARE.EQ | Should Use equals() Instead of == (Java) |
Coverity | 7.5 | BAD_EQ | Implemented |
Parasoft Jtest | 2024.1 | CERT.EXP02.UEIC | Do not use '==' or '!=' to compare objects |
SonarQube | 9.9 | S2159 | Silly equality checks should not be made |
9 Comments
Robert Seacord
This rule appears to suggest that any use of the equals() method on Array objects should be diagnosed. Is this what we were after?
David Svoboda
Yes. I suppose there are cases where you do want to use == on two Array objects, to see if they are references to the same object. While such code could be legit, I'd want the code to have a comment saying somewhere that this usage (over Arrays.equals()) is not an accident.
Robert Seacord
Does the Coverity Prevent Version 5.0 BAD_EQflag use of the Object.equals() method to compare two arrays?
David Svoboda
I think the answer to your question is 'No'. It is a statistical checker, so it will flag code where you do one type of equality lots and the other a little, and it thinks you're being inconsistent.
Reference: (not sure this is the authoritative) https://lhcb-coverity.cern.ch:8443/docs/checker_ref.html#static_java_checker_BAD_EQ
Yozo TODA
automated detection section says
it should be corrected as
Object.equals(...)
.or, how about "one argument version of
equals(...)
?I'm not sure if it can be described as "straightforward" to derive which method of the class is actually invoked...
David Svoboda
I've tweaked that sentence.
The only difficulty in static analysis is determing which method actually gets invoked. It is easy to tell that a call to a non-static equals() method occurs. But since the actual type of object is known only at runtime, which equals() method is called is harder. Fortunately we don't care about that; we are satisfied with knowing that Object.equals() (or a subclass's non-static equals() method) was invoked.
It's also easy to determine the declared type of an object. So we can see if Object.equals() was invoked on an array without running the program. We can also tell statically if == was used on an array. This rule prohibits both.
Robert Seacord
I think part of the point of Yozo TODA's comment is that we don't need to statically detect
Array.equals
() because it is the compliant solution. I'm going to edit accordingly.Ahmed Shah
Automated detection section says:
Static detection of calls to to
Object.equals()
Should it be:
Static detection of calls to
Object.equals()
David Svoboda
fixed, thanks