Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Calling overridable methods from the clone() method is insecure. First, a malicious subclass may could override the method and affect the behavior of the clone() method. Second, a trusted subclass can could observe (and potentially modify) the cloned object in a partially initialized state before its construction has concluded. ConsequentlyIn either case, the subclass can 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 rule MET05-J. Ensure that constructors do not call overridable methods.

...

This noncompliant code example shows two classes, BadClone CloneExample and Sub. The class BadClone 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 BadCloneCloneExample.clone(), and the other comes from Sub.clone(). Consequently, the values of the cookies are never get their values initialized, while their the domains are initialized twice.

...

Code Block
bgColor#FFcccc
class CloneExample implements Cloneable {
  HttpCookie[] cookies;

  CloneExample(HttpCookie[] c) {
    cookies = c;
  }

  public Object clone() throws CloneNotSupportedException {
    final CloneExample clone = (CloneExample) super.clone();
    clone.doSomething(); // Invokes overridable method
    clone.cookies = clone.deepCopy();
    return clone;
  }

  void doSomething() { // Overridable
    for (int i = 0; i < cookies.length; i++) {
      cookies[i].setValue("" + i);
    }
  }

  HttpCookie[] deepCopy() {
    if (cookies == null) {
      throw new NullPointerException();
    }

    // deep copy
    HttpCookie[] cookiesCopy = new HttpCookie[cookies.length];

    for (int i = 0; i < cookies.length; i++) {
      // Manually create a copy of each element in array
      cookiesCopy[i] = (HttpCookie) cookies[i].clone();
    }
    return cookiesCopy;
  }
}

class Sub extends CloneExample {
  Sub(HttpCookie[] c) {
    super(c);
  }

  public Object clone() throws CloneNotSupportedException {
    final Sub clone = (Sub) super.clone();
    clone.doSomething();
    return clone;
  }

  void doSomething() { // Erroneously executed
    for (int i = 0;i < cookies.length; i++) {
      cookies[i].setDomain(i + ".foo.com");
    }
  }

  public static void main(String[] args)
      throws CloneNotSupportedException {
    HttpCookie[] hc = new HttpCookie[20];
    for (int i = 0 ; i < hc.length; i++){
      hc[i] = new HttpCookie("cookie" + i,"" + i);
    }
    CloneExample bc = new Sub(hc);
    bc.clone();
  }
}

...

Automated Detection

Automated detection appears to be is straightforward.

Bibliography

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="76a4f21af30c38de-300aaa51-4dd04d46-bf839877-c0db16b6592acb2e9f41e7ca"><ac:plain-text-body><![CDATA[

[[Bloch 2008

AA. Bibliography#Bloch 08]]

Item 11: . Override clone judiciously

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="1112e5335a0c8421-73a73600-4da94850-bb08b34b-66f56beeb50b6163dfe313fc"><ac:plain-text-body><![CDATA[

[[Gong 2003

AA. Bibliography#Gong 03]]

 

]]></ac:plain-text-body></ac:structured-macro>

...