warning on guarded-by writes

Differential Revision: D3390055

fbshipit-source-id: 1c68fcd
master
Sam Blackshear 9 years ago committed by Facebook Github Bot 6
parent b1e3d994bd
commit b940c4dfac

@ -618,7 +618,6 @@ let prop_iter_add_hpred_footprint_to_prop pname tenv prop (lexp, typ) inst =
let add_guarded_by_constraints prop lexp pdesc = let add_guarded_by_constraints prop lexp pdesc =
let excluded_guardedby_string str = let excluded_guardedby_string str =
str = "ui_thread" in (* don't warn on @GuardedBy("ui_thread") *) str = "ui_thread" in (* don't warn on @GuardedBy("ui_thread") *)
let sigma = Prop.get_sigma prop in
let extract_guarded_by_str item_annot = let extract_guarded_by_str item_annot =
let annot_extract_guarded_by_str (annot, _) = let annot_extract_guarded_by_str (annot, _) =
if Annotations.annot_ends_with annot Annotations.guarded_by if Annotations.annot_ends_with annot Annotations.guarded_by
@ -658,7 +657,7 @@ let add_guarded_by_constraints prop lexp pdesc =
None) None)
sigma in sigma in
(* warn if the access to [lexp] is not protected by the [guarded_by_fld_str] lock *) (* warn if the access to [lexp] is not protected by the [guarded_by_fld_str] lock *)
let enforce_guarded_access accessed_fld guarded_by_str prop = let enforce_guarded_access_ accessed_fld guarded_by_str prop =
(* return true if [pdesc] has an annotation that matches [guarded_by_str] *) (* return true if [pdesc] has an annotation that matches [guarded_by_str] *)
let proc_has_matching_annot pdesc guarded_by_str = let proc_has_matching_annot pdesc guarded_by_str =
let proc_signature = let proc_signature =
@ -716,21 +715,25 @@ let add_guarded_by_constraints prop lexp pdesc =
lock in the current prop). so just be silent. *) lock in the current prop). so just be silent. *)
(); ();
prop in prop in
let enforce_guarded_access fld typ prop =
match get_guarded_by_fld_str fld typ with
| Some guarded_by_fld_str -> enforce_guarded_access_ fld guarded_by_fld_str prop
| None -> prop in
let check_fld_locks typ prop_acc (fld, strexp) = match strexp with let check_fld_locks typ prop_acc (fld, strexp) = match strexp with
| Sil.Eexp (exp, _) when Sil.exp_equal exp lexp -> | Sil.Eexp (exp, _) when Sil.exp_equal exp lexp -> enforce_guarded_access fld typ prop_acc
begin | _ -> prop_acc in
match get_guarded_by_fld_str fld typ with
| Some guarded_by_fld_str -> enforce_guarded_access fld guarded_by_fld_str prop_acc
| None -> prop_acc (* field not annotated; proceed as normal *)
end
| _ ->
prop_acc in
let hpred_check_flds prop_acc = function let hpred_check_flds prop_acc = function
| Sil.Hpointsto (_, Estruct (flds, _), Sizeof (typ, _, _)) -> | Sil.Hpointsto (_, Estruct (flds, _), Sizeof (typ, _, _)) ->
IList.fold_left (check_fld_locks typ) prop_acc flds IList.fold_left (check_fld_locks typ) prop_acc flds
| _ -> | _ ->
prop_acc in prop_acc in
IList.fold_left hpred_check_flds prop sigma match lexp with
| Sil.Lfield (_, fld, typ) ->
(* check for direct access to field annotated with @GuardedBy *)
enforce_guarded_access fld typ prop
| _ ->
(* check for access via alias *)
IList.fold_left hpred_check_flds prop (Prop.get_sigma prop)
(** Add a pointsto for [root(lexp): typ] to the iterator and to the (** Add a pointsto for [root(lexp): typ] to the iterator and to the
footprint, if it's compatible with the allowed footprint footprint, if it's compatible with the allowed footprint
@ -1261,7 +1264,8 @@ let rearrange ?(report_deref_errors=true) pdesc tenv lexp typ prop loc
if report_deref_errors then check_dereference_error pdesc prop nlexp (State.get_loc ()); if report_deref_errors then check_dereference_error pdesc prop nlexp (State.get_loc ());
let pname = Cfg.Procdesc.get_proc_name pdesc in let pname = Cfg.Procdesc.get_proc_name pdesc in
let prop' = let prop' =
if Config.csl_analysis && !Config.footprint && Procname.is_java pname if Config.csl_analysis && !Config.footprint && Procname.is_java pname &&
not (Procname.is_constructor pname || Procname.is_class_initializer pname)
then add_guarded_by_constraints prop lexp pdesc then add_guarded_by_constraints prop lexp pdesc
else prop in else prop in
match Prop.prop_iter_create prop' with match Prop.prop_iter_create prop' with

@ -40,23 +40,54 @@ public class GuardedByExample {
@GuardedBy("ui_thread") @GuardedBy("ui_thread")
Object t = new Object(); Object t = new Object();
private static Object sLock = new Object();
@GuardedBy("sLock")
static Object sFld;
static {
// don't warn on class initializer
sFld = new Object();
}
public GuardedByExample() {
// don't warn on reads or writes of Guarded fields in constructor
f.toString();
g = new Object();
}
void readFBad() { void readFBad() {
this.f.toString(); this.f.toString();
} }
void writeFBad() {
this.f = new Object();
}
void readFBadWrongLock() { void readFBadWrongLock() {
synchronized (mOtherLock) { synchronized (mOtherLock) {
this.f.toString(); // f is supposed to be protected by mLock this.f.toString(); // f is supposed to be protected by mLock
} }
} }
void writeFBadWrongLock() {
synchronized (mOtherLock) {
this.f = new Object(); // f is supposed to be protected by mLock
}
}
void readFAfterBlockBad() { void readFAfterBlockBad() {
synchronized (mLock) { synchronized (mLock) {
} }
this.f.toString(); this.f.toString();
} }
void writeFAfterBlockBad() {
synchronized (mLock) {
}
this.f = new Object();
}
@GuardedBy("mOtherLock") @GuardedBy("mOtherLock")
void readFBadWrongAnnotation() { void readFBadWrongAnnotation() {
this.f.toString(); this.f.toString();
@ -67,20 +98,34 @@ public class GuardedByExample {
this.f.toString(); this.f.toString();
} }
synchronized void synchronizedMethodOk() { synchronized void synchronizedMethodReadOk() {
this.g.toString(); this.g.toString();
} }
synchronized void synchronizedMethodWriteOk() {
this.g = new Object();
}
void readFOkSynchronized() { void readFOkSynchronized() {
synchronized (mLock) { synchronized (mLock) {
this.f.toString(); this.f.toString();
} }
} }
synchronized void synchronizedMethodBad() { void writeFOkSynchronized() {
synchronized (mLock) {
this.f = new Object();
}
}
synchronized void synchronizedMethodReadBad() {
this.f.toString(); // f is supposed to be protected by mLock, not this this.f.toString(); // f is supposed to be protected by mLock, not this
} }
synchronized void synchronizedMethodWriteBad() {
this.f = new Object(); // f is supposed to be protected by mLock, not this
}
void readGFromCopyBad() { void readGFromCopyBad() {
synchronized (this) { synchronized (this) {
mCopyOfG = g; // these are ok: access of g guarded by this mCopyOfG = g; // these are ok: access of g guarded by this
@ -89,6 +134,13 @@ public class GuardedByExample {
mCopyOfG.toString(); // should be an error; unprotected access to pt(g) mCopyOfG.toString(); // should be an error; unprotected access to pt(g)
} }
void reassignCopyOk() {
synchronized (this) {
mCopyOfG = g; // these are ok: access of g guarded by this
}
mCopyOfG = new Object(); // ok; this doesn't change the value of g
}
void readHBad() { void readHBad() {
synchronized (mLock) { // h is not protected by mLock synchronized (mLock) { // h is not protected by mLock
this.h.toString(); this.h.toString();

@ -41,10 +41,14 @@ public class GuardedByTest {
throws IOException, InterruptedException, InferException { throws IOException, InterruptedException, InferException {
String[] methods = { String[] methods = {
"readFBad", "readFBad",
"writeFBad",
"readFBadWrongLock", "readFBadWrongLock",
"writeFBadWrongLock",
"readFAfterBlockBad", "readFAfterBlockBad",
"writeFAfterBlockBad",
"readFBadWrongAnnotation", "readFBadWrongAnnotation",
"synchronizedMethodBad", "synchronizedMethodReadBad",
"synchronizedMethodWriteBad",
"readGFromCopyBad", "readGFromCopyBad",
"readHBad", "readHBad",
"readHBadSynchronizedMethodShouldntHelp", "readHBadSynchronizedMethodShouldntHelp",

Loading…
Cancel
Save