diff --git a/infer/src/pulse/PulseFormula.ml b/infer/src/pulse/PulseFormula.ml index 89de14d4d..5d98babb8 100644 --- a/infer/src/pulse/PulseFormula.ml +++ b/infer/src/pulse/PulseFormula.ml @@ -647,6 +647,24 @@ module Term = struct zero | (BitShiftLeft (t1, t2) | BitShiftRight (t1, t2)) when is_zero t2 -> t1 + | BitShiftLeft (t', Const q) | BitShiftRight (t', Const q) -> ( + match Q.to_int q with + | None -> + (* overflows or otherwise undefined, propagate puzzlement *) + Const Q.undef + | Some i -> ( + if i >= 64 then (* assume 64-bit or fewer architecture *) zero + else if i < 0 then (* this is undefined, maybe we should report a bug here *) + Const Q.undef + else + let factor = Const Q.(of_int 1 lsl i) in + match[@warning "-8"] t with + | BitShiftLeft _ -> + simplify_shallow_ (Mult (t', factor)) + | BitShiftRight _ -> + simplify_shallow_ (Div (t', factor)) ) ) + | (BitShiftLeft (t1, t2) | BitShiftRight (t1, t2)) when is_zero t2 -> + t1 | And (t1, t2) when is_zero t1 || is_zero t2 -> (* [false ∧ t = t ∧ false = false] *) zero | And (t1, t2) when is_non_zero_const t1 -> diff --git a/infer/tests/codetoanalyze/cpp/pulse/values.cpp b/infer/tests/codetoanalyze/cpp/pulse/values.cpp index 283d30d85..5d428749a 100644 --- a/infer/tests/codetoanalyze/cpp/pulse/values.cpp +++ b/infer/tests/codetoanalyze/cpp/pulse/values.cpp @@ -155,3 +155,17 @@ void FP_ints_are_not_rationals_ok() { *p = 42; } } + +void shift_equal_mult_by_power_of_two_ok(int x) { + if (x << 1 != mult(2, x)) { + int* p = nullptr; + *p = 42; + } +} + +void shift_by_too_much_ok(int x) { + if (x << 64 != 0 || x >> 4000 != 0) { + int* p = nullptr; + *p = 42; + } +}