diff --git a/infer/src/erlang/ErlangTranslator.ml b/infer/src/erlang/ErlangTranslator.ml index 9699b07ca..30b246f95 100644 --- a/infer/src/erlang/ErlangTranslator.ml +++ b/infer/src/erlang/ErlangTranslator.ml @@ -422,6 +422,13 @@ let rec translate_expression env {Ast.line; simple_expression} = | Literal (String s) -> let e = Exp.Const (Cstr s) in Block.make_load env ret_var e any + | Match {pattern; body} -> + let body_block = translate_expression {env with result= Present (Exp.Var ret_var)} body in + let pattern_block = translate_pattern env ret_var pattern in + let crash_node = Node.make_pattern_fail env in + pattern_block.exit_failure |~~> [crash_node] ; + let pattern_block = {pattern_block with exit_failure= crash_node} in + Block.all env [body_block; pattern_block] | Nil -> let fun_exp = Exp.Const (Cfun BuiltinDecl.__erlang_make_nil) in let instruction = Sil.Call ((ret_var, any), fun_exp, [], env.location, CallFlags.default) in diff --git a/infer/tests/codetoanalyze/erlang/nonmatch/issues.exp b/infer/tests/codetoanalyze/erlang/nonmatch/issues.exp index e90da4684..04bdcfa38 100644 --- a/infer/tests/codetoanalyze/erlang/nonmatch/issues.exp +++ b/infer/tests/codetoanalyze/erlang/nonmatch/issues.exp @@ -1,6 +1,13 @@ codetoanalyze/erlang/nonmatch/src/nonmatch.erl, assert_empty/1, 0, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [*** LATENT ***,no pattern match here] codetoanalyze/erlang/nonmatch/src/nonmatch.erl, assert_second_is_nil/1, 0, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [*** LATENT ***,no pattern match here] +codetoanalyze/erlang/nonmatch/src/nonmatch.erl, fp_match_test_c_Ok/0, 1, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [no pattern match here] +codetoanalyze/erlang/nonmatch/src/nonmatch.erl, fp_match_test_d_Ok/0, -31, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `tail/1`,no pattern match here] codetoanalyze/erlang/nonmatch/src/nonmatch.erl, list_match_test_a/0, -4, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `tail/1`,no pattern match here] codetoanalyze/erlang/nonmatch/src/nonmatch.erl, list_match_test_b/0, -8, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `assert_empty/1`,no pattern match here] codetoanalyze/erlang/nonmatch/src/nonmatch.erl, list_match_test_c/0, -12, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `assert_second_is_nil/1`,no pattern match here] +codetoanalyze/erlang/nonmatch/src/nonmatch.erl, match_test_b_Bad/0, 1, CONSTANT_ADDRESS_DEREFERENCE, no_bucket, WARNING, [in call to `two/0`,is the constant 2,assigned,returned,return from call to `two/0`,invalid access occurs here] +codetoanalyze/erlang/nonmatch/src/nonmatch.erl, match_test_b_Bad/0, 1, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [no pattern match here] +codetoanalyze/erlang/nonmatch/src/nonmatch.erl, match_test_e_Bad/0, -35, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `tail/1`,no pattern match here] +codetoanalyze/erlang/nonmatch/src/nonmatch.erl, match_test_g_Bad/0, 7, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `only_accepts_one/1`,no pattern match here] +codetoanalyze/erlang/nonmatch/src/nonmatch.erl, only_accepts_one/1, 0, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [*** LATENT ***,no pattern match here] codetoanalyze/erlang/nonmatch/src/nonmatch.erl, tail/1, 0, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [*** LATENT ***,no pattern match here] diff --git a/infer/tests/codetoanalyze/erlang/nonmatch/src/nonmatch.erl b/infer/tests/codetoanalyze/erlang/nonmatch/src/nonmatch.erl index e801ed2d0..0fa19c6eb 100644 --- a/infer/tests/codetoanalyze/erlang/nonmatch/src/nonmatch.erl +++ b/infer/tests/codetoanalyze/erlang/nonmatch/src/nonmatch.erl @@ -5,7 +5,18 @@ -module(nonmatch). --export([list_match_test_a/0, list_match_test_b/0, list_match_test_c/0]). +-export([ + list_match_test_a/0, + list_match_test_b/0, + list_match_test_c/0, + match_test_a_Ok/0, + match_test_b_Bad/0, + fp_match_test_c_Ok/0, + fp_match_test_d_Ok/0, + match_test_e_Bad/0, + match_test_f_Ok/0, + match_test_g_Bad/0 +]). tail([_ | Xs]) -> Xs. assert_empty([]) -> ok. @@ -26,3 +37,37 @@ list_match_test_c() -> assert_second_is_nil([1, [], 2]), assert_second_is_nil([1, []]), assert_second_is_nil([1, [2], 3]). + +match_test_a_Ok() -> + _X = two(). + +match_test_b_Bad() -> + [_ | _] = two(). + +% FP (T94492137) +fp_match_test_c_Ok() -> + [_X, _Y] = [1, 2]. + +% FP (T94492137) +fp_match_test_d_Ok() -> + [_ | Xs] = [1, 2], + tail(Xs). + +match_test_e_Bad() -> + [_ | Xs] = [1], + tail(Xs). + +match_test_f_Ok() -> + X = (Y = 1), + only_accepts_one(X), + only_accepts_one(Y). + +match_test_g_Bad() -> + X = 2, + only_accepts_one(X). + +%% internal +%% These functions are used to fool the compiler, which would warn if these were inlined. + +only_accepts_one(1) -> ok. +two() -> 2. diff --git a/infer/tests/codetoanalyze/erlang/topl/issues.exp b/infer/tests/codetoanalyze/erlang/topl/issues.exp index 06ea55d26..a28383f58 100644 --- a/infer/tests/codetoanalyze/erlang/topl/issues.exp +++ b/infer/tests/codetoanalyze/erlang/topl/issues.exp @@ -1,6 +1,7 @@ codetoanalyze/erlang/topl/src/topl_taint.erl, fp_test_f_Bad/0, 1, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [no pattern match here] codetoanalyze/erlang/topl/src/topl_taint.erl, fp_test_g_Ok/0, 1, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [no pattern match here] codetoanalyze/erlang/topl/src/topl_taint.erl, test_a_Bad/0, 0, TOPL_ERROR, no_bucket, ERROR, [call to source/0,call to sink/1] +codetoanalyze/erlang/topl/src/topl_taint.erl, test_c_Bad/0, 0, TOPL_ERROR, no_bucket, ERROR, [call to source/0,call to sink/1] codetoanalyze/erlang/topl/src/topl_taint.erl, test_d_Bad/0, 0, TOPL_ERROR, no_bucket, ERROR, [call to source/0,call to call_sink_indirectly/1,call to call_sink/1,call to sink/1] codetoanalyze/erlang/topl/src/topl_taint.erl, test_h_Bad/0, 0, TOPL_ERROR, no_bucket, ERROR, [call to dirty_if_argument_nil/1,call to source/0,call to sink/1] codetoanalyze/erlang/topl/src/topl_taint.erl, test_j_Bad/0, 1, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [no pattern match here] diff --git a/infer/tests/codetoanalyze/erlang/topl/src/topl_taint.erl b/infer/tests/codetoanalyze/erlang/topl/src/topl_taint.erl index 1b3209b68..a08c84d39 100644 --- a/infer/tests/codetoanalyze/erlang/topl/src/topl_taint.erl +++ b/infer/tests/codetoanalyze/erlang/topl/src/topl_taint.erl @@ -8,7 +8,7 @@ -export([ test_a_Bad/0, test_b_Ok/0, - fn_test_c_Bad/0, + test_c_Bad/0, test_d_Bad/0, test_e_Ok/0, fp_test_f_Bad/0, @@ -24,8 +24,7 @@ test_a_Bad() -> test_b_Ok() -> sink(1). -% FN because match not yet translated -fn_test_c_Bad() -> +test_c_Bad() -> X = source(), sink(X).