detect unchecked division operator

64 Views Asked by At

Basically I am writing a clang-tidy check to detect "bad" divisions where there is a division and the divisor was not checked with an assert() statement.

In the following example good_disvisor should pass the check as there is an assert checking it's equality to zero but bad_divisor should be detected and marked.

#include <cassert>

int main() {
    const double good_divisor = 0.3;
    assert(good_divisor != 0.0);
    double foo = 1.0 / good_divisor;

    const double bad_divisor = 0.3;
    double bar = 1.0 / bad_divisor;

    return 0;
}

So far my machers and check can only detect the divison opeartor but couldn't do much beyond it:

void UnsafeArithmeticCheck::registerMatchers(MatchFinder *Finder) {
  Finder->addMatcher(binaryOperator(hasOperatorName("/")).bind("div"), this);
}

void UnsafeArithmeticCheck::check(const MatchFinder::MatchResult &Result) {
  const auto *Binop = Result.Nodes.getNodeAs<BinaryOperator>("div");

  if (!Binop) {
    return;
  }

  diag(Binop->getExprLoc(), "found a division here", DiagnosticIDs::Note);

  auto rhs = Binop->getRHS();
  // now how do I check if this `rhs` is a variable and not an expression?
}

I think there are 3 steps missing still:

  1. to check if rhs from division operator is a variable (and not an expression). In my check I get it through Binop->getRHS() but I can't find an function to examine it's type
  2. to check if there is an asssert() prior to the DeclStmt (the father node of this divison operator)
  3. if there is such an assert(), then further check if there is a rhs != 0 in it (rhs was identified from step 1)

Can someone help me to complete this check?


Answering @Scott's question (what I hope to achieve that core.DivideZero can't not):

core.DivideZero simply couldn't detect code like below:

double foo(double x) {
    return x * 3 - 1;
}

int main() {
    double divisor = foo(0.3);
    double x = 1.0 / divisor;

    return 0;
}

And I hope my check can mark an error for:

    double divisor = foo(0.3);
    double x = 1.0 / divisor;

and wouldn't raise an error when assert() added:

    double divisor = foo(0.3);
    assert(divisor != 0);
    double x = 1.0 / divisor;
0

There are 0 best solutions below