Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Published by Scroll Versions from space CSHARP and version Publish

...

Dont print
Code Block
languageql
titleQuery: PossibleLossOfPrecision.ql
collapsetrue
/**
 * @name Possible loss of precision
 * @description Dividing or multiplying integral expressions and converting the result to a
 *              floating-point value may result in a loss of precision.
 * @kind problem
 * @problem.severity error
 * @precision high
 * @id cs/loss-of-precision
 * @tags reliability
 *       correctness
 *       external/cwe/cwe-190
 *       external/cwe/cwe-192
 *       external/cwe/cwe-197
 *       external/cwe/cwe-681
 */

import csharp

/** Holds if `e` is converted to type `t` which is a `float` or a `decimal`. */
predicate convertedToFloatOrDecimal(Expr e, Type t) {
  exists(CastExpr cast |
    cast.getExpr() = e and
    t = cast.getType()
  |
    t instanceof FloatingPointType or
    t instanceof DecimalType
  )
  or
  exists(BinaryArithmeticOperation op |
    op.getAnOperand() = e and
    convertedToFloatOrDecimal(op, t)
  |
    op instanceof AddExpr or
    op instanceof SubExpr or
    op instanceof MulExpr
  )
}

/** Holds if `div` is an exact integer division. */
predicate exactDivision(DivExpr div) {
  exists(int numerator, int denominator |
    numerator = div.getNumerator().stripCasts().getValue().toInt() and
    denominator = div.getDenominator().stripCasts().getValue().toInt() and
    numerator % denominator = 0
  )
}

/** An expression that may result in a loss of precision. */
abstract class LossOfPrecision extends Expr {
  Type convertedType;

  LossOfPrecision() {
    getType() instanceof IntegralType and
    convertedToFloatOrDecimal(this, convertedType)
  }

  /** Gets the alert message. */
  abstract string getMessage();
}

/** A division expression that may result in a loss of precision. */
class DivLossOfPrecision extends LossOfPrecision, DivExpr {
  DivLossOfPrecision() { not exactDivision(this) }

  override string getMessage() { result = "Possible loss of precision: any fraction will be lost." }
}

/** Holds if `e` is a constant multiplication that does not overflow. */
predicate small(MulExpr e) {
  exists(float lhs, float rhs, float res, IntegralType t |
    lhs = e.getLeftOperand().stripCasts().getValue().toFloat() and
    rhs = e.getRightOperand().stripCasts().getValue().toFloat() and
    lhs * rhs = res and
    t = e.getType() and
    not res < t.minValue() and
    not res > t.maxValue()
  )
}

/** A multiplication expression that may result in a loss of precision. */
class MulLossOfPrecision extends LossOfPrecision, MulExpr {
  MulLossOfPrecision() { not small(this) }

  override string getMessage() {
    result =
      "Possible overflow: result of integer multiplication cast to " +
        convertedType.toStringWithTypes() + "."
  }
}

from LossOfPrecision e
select e, e.getMessage()

...

Htmlcomment
hiddentrue
hashconfluence_uploader_hash:de0fb3630201fc5e591c81b1fff1d9b46272d22dffd3dfe258c28d3522977cfd603bcf78023e0cbd