Summary: We get the wrong answer on most of them for now, but that is expected Reviewed By: ngorogiannis Differential Revision: D5429242 fbshipit-source-id: 4899079master
parent
4d7742fd68
commit
72e778d094
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 201y - present Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package codetoanalyze.java.checkers;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
@ThreadSafe
|
||||
public class Escape {
|
||||
|
||||
private Obj mField;
|
||||
private static Obj sGlobal;
|
||||
|
||||
// this can race with unsafe writes to mField.f
|
||||
public synchronized Object racyRead1() {
|
||||
return mField.f;
|
||||
}
|
||||
|
||||
// this can race with unsafe writes to mField.f
|
||||
public synchronized Object racyRead2() {
|
||||
return sGlobal.f;
|
||||
}
|
||||
|
||||
public void FN_fieldEscapeBad() {
|
||||
Obj o = new Obj();
|
||||
synchronized(this) {
|
||||
mField = o;
|
||||
}
|
||||
o.f = new Object(); // not safe
|
||||
}
|
||||
|
||||
public void FN_globalEscapeBad() {
|
||||
Obj o = new Obj();
|
||||
synchronized (Escape.class) {
|
||||
sGlobal = o;
|
||||
}
|
||||
o.f = new Object(); // not safe
|
||||
}
|
||||
|
||||
public synchronized void escapeInCallee(Obj o) {
|
||||
mField = o;
|
||||
}
|
||||
|
||||
public void FN_escapeInCalleeBad() {
|
||||
Obj o = new Obj();
|
||||
escapeInCallee(o);
|
||||
o.f = new Object();
|
||||
}
|
||||
|
||||
public void aliasOk() {
|
||||
Obj o = new Obj(); // though there's two pointers to this address, neither escapes
|
||||
Obj alias = o;
|
||||
o.f = null;
|
||||
alias.f = null;
|
||||
}
|
||||
|
||||
public void nonAliasReadOk() {
|
||||
Obj o = new Obj();
|
||||
String s = o + "a";
|
||||
o.f = null; // ok
|
||||
}
|
||||
|
||||
public void FN_escapeViaAliasBad1() {
|
||||
Obj o = new Obj();
|
||||
Obj alias = o;
|
||||
escapeInCallee(alias);
|
||||
o.f = null; // bad
|
||||
alias.f = null; // bad
|
||||
}
|
||||
|
||||
public void FN_escapeViaAliasBad2() {
|
||||
Obj o = new Obj();
|
||||
Obj alias = o;
|
||||
escapeInCallee(o);
|
||||
o.f = null; // bad
|
||||
alias.f = null; // bad
|
||||
}
|
||||
|
||||
public Obj id(Obj o) {
|
||||
return o;
|
||||
}
|
||||
|
||||
public void FN_aliasViaReturnBad1() {
|
||||
Obj o = new Obj();
|
||||
Obj alias = id(o);
|
||||
escapeInCallee(alias);
|
||||
o.f = null; // bad
|
||||
alias.f = null; // bad
|
||||
}
|
||||
|
||||
public void FN_aliasViaReturnBad2() {
|
||||
Obj o = new Obj();
|
||||
Obj alias = id(o);
|
||||
escapeInCallee(o);
|
||||
o.f = null; // bad
|
||||
alias.f = null; // bad
|
||||
}
|
||||
|
||||
private void twoParamsOneEscapes(Obj o1, Obj o2) {
|
||||
synchronized (Escape.class) {
|
||||
sGlobal = o1;
|
||||
}
|
||||
o1.f = null; // only safe if o1/o2 not aliased
|
||||
}
|
||||
|
||||
public void FN_aliasedParamsBad() {
|
||||
Obj o = new Obj();
|
||||
twoParamsOneEscapes(o, o); // should report racy write in callee
|
||||
o.f = null; // bad
|
||||
}
|
||||
|
||||
public void nonAliasedParamsOk() {
|
||||
Obj o1 = new Obj();
|
||||
Obj o2 = new Obj();
|
||||
twoParamsOneEscapes(o1, o2);
|
||||
o2.f = null; // ok
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
class Leaky {
|
||||
|
||||
Leaky mLeak;
|
||||
Object mField;
|
||||
Object sGlobal;
|
||||
|
||||
public Leaky() {
|
||||
mLeak = this;
|
||||
}
|
||||
|
||||
public void FN_leakyConstructorBad() {
|
||||
Leaky l = new Leaky();
|
||||
synchronized (Leaky.class) {
|
||||
sGlobal = l.mLeak; // oops, this leaks l
|
||||
}
|
||||
l.mField = 1; // bad
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in new issue