[infer][java] prevent the closeable as resource approach to report resource leak when close() throws an exception

Summary:
@public
Previously, if the close() method was throwing an exception, then code overriding the file attribute with a mem attribute would be skipped, resulting in reporting a wrong resource leak. This diff fixes this.

Test Plan: Added new end-to-end tests which would previously have been failing
master
jrm 10 years ago
parent ea3e614cce
commit 2125bfdad9

@ -1160,10 +1160,11 @@ and add_constraints_on_actuals_by_ref prop actuals_by_ref callee_pname =
(** execute a call for an unknown or scan function *)
and call_unknown_or_scan is_scan cfg pdesc tenv pre path
ret_ids ret_type_option actual_pars callee_pname loc =
let remove_resource_att prop =
let remove_file_attribute prop =
let do_exp p (e, t) =
let do_attribute q = function
| Sil.Aresource _ as res ->
| Sil.Aresource res_action as res
when res_action.Sil.ra_res = Sil.Rfile ->
Prop.remove_attribute res q
| _ -> q in
list_fold_left do_attribute p (Prop.get_exp_attributes p e) in
@ -1175,7 +1176,7 @@ and call_unknown_or_scan is_scan cfg pdesc tenv pre path
| _ -> false)
actual_pars in
(* in Java, assume that skip functions close resources passed as params *)
let pre' = if !Sil.curr_language = Sil.Java then remove_resource_att pre else pre in
let pre' = if !Sil.curr_language = Sil.Java then remove_file_attribute pre else pre in
let pre'' = add_constraints_on_retval pdesc pre' ret_ids ret_type_option callee_pname in
let pre''' = add_constraints_on_actuals_by_ref pre'' actuals_by_ref callee_pname in
if is_scan (* if scan function, don't mark anything with undef attributes *)

@ -661,6 +661,7 @@ let method_invocation context loc pc var_opt cn ms sil_obj_opt expr_list invoke_
let set_file_attr =
let set_builtin = Sil.Const (Sil.Cfun SymExec.ModelBuiltins.__set_file_attribute) in
Sil.Call ([], set_builtin, [exp], loc, Sil.cf_default) in
(* Exceptions thrown in the constructor should prevent adding the resource attribute *)
call_instrs @ [set_file_attr]
(* remove file attribute when calling the close method of a subtype of Closeable *)
@ -669,7 +670,9 @@ let method_invocation context loc pc var_opt cn ms sil_obj_opt expr_list invoke_
let set_mem_attr =
let set_builtin = Sil.Const (Sil.Cfun SymExec.ModelBuiltins.__set_mem_attribute) in
Sil.Call ([], set_builtin, [exp], loc, Sil.cf_default) in
call_instrs @ [set_mem_attr]
(* Exceptions thrown in the close method should not prevent the resource from being *)
(* considered as closed *)
[set_mem_attr] @ call_instrs
| _ -> call_instrs in

@ -11,17 +11,19 @@ import java.io.StringReader;
public class CloseableAsResourceExample {
native boolean star();
class LocalException extends IOException {
}
class SomeResource implements Closeable {
native boolean isValid();
void doSomething() throws LocalException {
if (!isValid()) {
if (!star()) {
throw new LocalException();
}
}
public void close() {}
}
@ -50,15 +52,15 @@ public class CloseableAsResourceExample {
res.close();
} // should report a resource leak
class Res implements Closeable {
public Res() {
class Resource implements Closeable {
public Resource() {
}
public void close() {}
}
class Wrapper implements Closeable {
Res mR;
public Wrapper(Res r) {
Resource mR;
public Wrapper(Resource r) {
mR = r;
}
public void close() {
@ -67,19 +69,19 @@ public class CloseableAsResourceExample {
}
class Sub extends Wrapper {
public Sub(Res r) {
public Sub(Resource r) {
super(r);
}
}
void closingWrapper() {
Res r = new Res();
Resource r = new Resource();
Sub s = new Sub(r);
s.close();
}
void notClosingWrapper() {
Sub s = new Sub(new Res());
Sub s = new Sub(new Resource());
s.mR.close();
} // should report a resource leak
@ -115,4 +117,23 @@ public class CloseableAsResourceExample {
}
}
class ResourceWithException implements Closeable {
public void close() throws IOException {
if (star()) {
throw new IOException();
}
}
}
void noLeakwithExceptionOnClose() throws IOException {
ResourceWithException res = new ResourceWithException();
res.close();
}
void noLeakWithCloseQuietlyAndExceptionOnClose() {
ResourceWithException res = new ResourceWithException();
Utils.closeQuietly(res);
}
}

Loading…
Cancel
Save