Calling overridable methods from the
clone() method is insecure. First, a malicious subclass could override the method and affect the behavior of the
clone() method. Second, a trusted subclass could observe (and potentially modify) the cloned object in a partially initialized state before its construction has concluded. In either case, the subclass could leave the clone, the object being cloned, or both in an inconsistent state. Consequently,
clone() methods may invoke only methods that are final or private.
This rule is closely related to MET05-J. Ensure that constructors do not call overridable methods.
Noncompliant Code Example
This noncompliant code example shows two classes,
Sub. The class
CloneExample calls an overridable method
doSomething(). The overridden method sets the value of the cookies; the overriding method sets the values of the domain names. The
doSomething() method of the subclass
Sub is erroneously executed twice at runtime because of polymorphism. The first invocation comes from
CloneExample.clone(), and the other comes from
Sub.clone(). Consequently, the values of the cookies are never initialized, whereas the domains are initialized twice.
Furthermore, the subclass not only sees the clone in an inconsistent state but also modifies the clone in a manner that creates inconsistent copies. This is because the
deepCopy() method occurs after the call to the
doSomething() method, and the overriding
doSomething() implementation erroneously modifies the object.
When an overridable method is invoked on a shallow copy of the object, the original object is also modified.
This compliant solution declares both the
doSomething() and the
deepCopy() methods final, preventing overriding of these methods:
Alternative solutions that prevent invocation of overridden methods include declaring these methods private or final or declaring the class containing these methods final.
MET06-J-EX0: It is permitted to call a superclass's method via
super.method(...), since such calls will not be dynamically dispatched to methods defined by a subclass. In fact, calling
super.clone() is expected behavior.
Calling overridable methods on the clone under construction can expose class internals to malicious code or violate class invariants by exposing the clone to trusted code in a partially initialized state, affording the opportunity to corrupt the state of the clone, the object being cloned, or both.
Automated detection is straightforward.