head	1.1;
branch	1.1.1;
access;
symbols
	netbsd-11-0-RC4:1.1.1.4
	netbsd-11-0-RC3:1.1.1.4
	netbsd-11-0-RC2:1.1.1.4
	netbsd-11-0-RC1:1.1.1.4
	perseant-exfatfs-base-20250801:1.1.1.4
	netbsd-11:1.1.1.4.0.10
	netbsd-11-base:1.1.1.4
	netbsd-10-1-RELEASE:1.1.1.4
	perseant-exfatfs-base-20240630:1.1.1.4
	perseant-exfatfs:1.1.1.4.0.8
	perseant-exfatfs-base:1.1.1.4
	netbsd-8-3-RELEASE:1.1.1.1
	netbsd-9-4-RELEASE:1.1.1.3
	netbsd-10-0-RELEASE:1.1.1.4
	netbsd-10-0-RC6:1.1.1.4
	netbsd-10-0-RC5:1.1.1.4
	netbsd-10-0-RC4:1.1.1.4
	netbsd-10-0-RC3:1.1.1.4
	netbsd-10-0-RC2:1.1.1.4
	netbsd-10-0-RC1:1.1.1.4
	netbsd-10:1.1.1.4.0.6
	netbsd-10-base:1.1.1.4
	netbsd-9-3-RELEASE:1.1.1.3
	cjep_sun2x:1.1.1.4.0.4
	cjep_sun2x-base:1.1.1.4
	cjep_staticlib_x-base1:1.1.1.4
	netbsd-9-2-RELEASE:1.1.1.3
	cjep_staticlib_x:1.1.1.4.0.2
	cjep_staticlib_x-base:1.1.1.4
	netbsd-9-1-RELEASE:1.1.1.3
	phil-wifi-20200421:1.1.1.4
	phil-wifi-20200411:1.1.1.4
	phil-wifi-20200406:1.1.1.4
	netbsd-8-2-RELEASE:1.1.1.1
	netbsd-9-0-RELEASE:1.1.1.3
	netbsd-9-0-RC2:1.1.1.3
	netbsd-9-0-RC1:1.1.1.3
	netbsd-9:1.1.1.3.0.2
	netbsd-9-base:1.1.1.3
	phil-wifi-20190609:1.1.1.3
	netbsd-8-1-RELEASE:1.1.1.1
	netbsd-8-1-RC1:1.1.1.1
	pgoyette-compat-merge-20190127:1.1.1.2.2.1
	pgoyette-compat-20190127:1.1.1.3
	pgoyette-compat-20190118:1.1.1.3
	pgoyette-compat-1226:1.1.1.3
	pgoyette-compat-1126:1.1.1.3
	pgoyette-compat-1020:1.1.1.3
	pgoyette-compat-0930:1.1.1.3
	pgoyette-compat-0906:1.1.1.3
	pgoyette-compat-0728:1.1.1.3
	clang-337282:1.1.1.3
	netbsd-8-0-RELEASE:1.1.1.1
	phil-wifi:1.1.1.2.0.4
	phil-wifi-base:1.1.1.2
	pgoyette-compat-0625:1.1.1.2
	netbsd-8-0-RC2:1.1.1.1
	pgoyette-compat-0521:1.1.1.2
	pgoyette-compat-0502:1.1.1.2
	pgoyette-compat-0422:1.1.1.2
	netbsd-8-0-RC1:1.1.1.1
	pgoyette-compat-0415:1.1.1.2
	pgoyette-compat-0407:1.1.1.2
	pgoyette-compat-0330:1.1.1.2
	pgoyette-compat-0322:1.1.1.2
	pgoyette-compat-0315:1.1.1.2
	pgoyette-compat:1.1.1.2.0.2
	pgoyette-compat-base:1.1.1.2
	clang-319952:1.1.1.2
	matt-nb8-mediatek:1.1.1.1.0.12
	matt-nb8-mediatek-base:1.1.1.1
	clang-309604:1.1.1.2
	perseant-stdc-iso10646:1.1.1.1.0.10
	perseant-stdc-iso10646-base:1.1.1.1
	netbsd-8:1.1.1.1.0.8
	netbsd-8-base:1.1.1.1
	prg-localcount2-base3:1.1.1.1
	prg-localcount2-base2:1.1.1.1
	prg-localcount2-base1:1.1.1.1
	prg-localcount2:1.1.1.1.0.6
	prg-localcount2-base:1.1.1.1
	pgoyette-localcount-20170426:1.1.1.1
	bouyer-socketcan-base1:1.1.1.1
	pgoyette-localcount:1.1.1.1.0.4
	pgoyette-localcount-20170320:1.1.1.1
	clang-294123:1.1.1.1
	bouyer-socketcan:1.1.1.1.0.2
	bouyer-socketcan-base:1.1.1.1
	clang-291444:1.1.1.1
	LLVM:1.1.1;
locks; strict;
comment	@// @;


1.1
date	2017.01.11.10.35.42;	author joerg;	state Exp;
branches
	1.1.1.1;
next	;
commitid	CNnUNfII1jgNmxBz;

1.1.1.1
date	2017.01.11.10.35.42;	author joerg;	state Exp;
branches
	1.1.1.1.4.1;
next	1.1.1.2;
commitid	CNnUNfII1jgNmxBz;

1.1.1.2
date	2017.08.01.19.35.17;	author joerg;	state Exp;
branches
	1.1.1.2.2.1
	1.1.1.2.4.1;
next	1.1.1.3;
commitid	pMuDy65V0VicSx1A;

1.1.1.3
date	2018.07.17.18.31.08;	author joerg;	state Exp;
branches;
next	1.1.1.4;
commitid	wDzL46ALjrCZgwKA;

1.1.1.4
date	2019.11.13.22.19.28;	author joerg;	state dead;
branches;
next	;
commitid	QD8YATxuNG34YJKB;

1.1.1.1.4.1
date	2017.01.11.10.35.42;	author pgoyette;	state dead;
branches;
next	1.1.1.1.4.2;
commitid	jjw7cAwgyKq7RfKz;

1.1.1.1.4.2
date	2017.03.20.06.52.42;	author pgoyette;	state Exp;
branches;
next	;
commitid	jjw7cAwgyKq7RfKz;

1.1.1.2.2.1
date	2018.07.28.04.33.23;	author pgoyette;	state Exp;
branches;
next	;
commitid	1UP1xAIUxv1ZgRLA;

1.1.1.2.4.1
date	2019.06.10.21.45.28;	author christos;	state Exp;
branches;
next	1.1.1.2.4.2;
commitid	jtc8rnCzWiEEHGqB;

1.1.1.2.4.2
date	2020.04.13.07.46.38;	author martin;	state dead;
branches;
next	;
commitid	X01YhRUPVUDaec4C;


desc
@@


1.1
log
@Initial revision
@
text
@//=== ConversionChecker.cpp -------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Check that there is no loss of sign/precision in assignments, comparisons
// and multiplications.
//
// ConversionChecker uses path sensitive analysis to determine possible values
// of expressions. A warning is reported when:
// * a negative value is implicitly converted to an unsigned value in an
//   assignment, comparison or multiplication.
// * assignment / initialization when source value is greater than the max
//   value of target
//
// Many compilers and tools have similar checks that are based on semantic
// analysis. Those checks are sound but have poor precision. ConversionChecker
// is an alternative to those checks.
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
#include "clang/AST/ParentMap.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"

using namespace clang;
using namespace ento;

namespace {
class ConversionChecker : public Checker<check::PreStmt<ImplicitCastExpr>> {
public:
  void checkPreStmt(const ImplicitCastExpr *Cast, CheckerContext &C) const;

private:
  mutable std::unique_ptr<BuiltinBug> BT;

  // Is there loss of precision
  bool isLossOfPrecision(const ImplicitCastExpr *Cast, CheckerContext &C) const;

  // Is there loss of sign
  bool isLossOfSign(const ImplicitCastExpr *Cast, CheckerContext &C) const;

  void reportBug(ExplodedNode *N, CheckerContext &C, const char Msg[]) const;
};
}

void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast,
                                     CheckerContext &C) const {
  // TODO: For now we only warn about DeclRefExpr, to avoid noise. Warn for
  // calculations also.
  if (!isa<DeclRefExpr>(Cast->IgnoreParenImpCasts()))
    return;

  // Don't warn for loss of sign/precision in macros.
  if (Cast->getExprLoc().isMacroID())
    return;

  // Get Parent.
  const ParentMap &PM = C.getLocationContext()->getParentMap();
  const Stmt *Parent = PM.getParent(Cast);
  if (!Parent)
    return;

  bool LossOfSign = false;
  bool LossOfPrecision = false;

  // Loss of sign/precision in binary operation.
  if (const auto *B = dyn_cast<BinaryOperator>(Parent)) {
    BinaryOperator::Opcode Opc = B->getOpcode();
    if (Opc == BO_Assign || Opc == BO_AddAssign || Opc == BO_SubAssign ||
        Opc == BO_MulAssign) {
      LossOfSign = isLossOfSign(Cast, C);
      LossOfPrecision = isLossOfPrecision(Cast, C);
    } else if (B->isRelationalOp() || B->isMultiplicativeOp()) {
      LossOfSign = isLossOfSign(Cast, C);
    }
  } else if (isa<DeclStmt>(Parent)) {
    LossOfSign = isLossOfSign(Cast, C);
    LossOfPrecision = isLossOfPrecision(Cast, C);
  }

  if (LossOfSign || LossOfPrecision) {
    // Generate an error node.
    ExplodedNode *N = C.generateNonFatalErrorNode(C.getState());
    if (!N)
      return;
    if (LossOfSign)
      reportBug(N, C, "Loss of sign in implicit conversion");
    if (LossOfPrecision)
      reportBug(N, C, "Loss of precision in implicit conversion");
  }
}

void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C,
                                  const char Msg[]) const {
  if (!BT)
    BT.reset(
        new BuiltinBug(this, "Conversion", "Possible loss of sign/precision."));

  // Generate a report for this bug.
  auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
  C.emitReport(std::move(R));
}

// Is E value greater or equal than Val?
static bool isGreaterEqual(CheckerContext &C, const Expr *E,
                           unsigned long long Val) {
  ProgramStateRef State = C.getState();
  SVal EVal = C.getSVal(E);
  if (EVal.isUnknownOrUndef() || !EVal.getAs<NonLoc>())
    return false;

  SValBuilder &Bldr = C.getSValBuilder();
  DefinedSVal V = Bldr.makeIntVal(Val, C.getASTContext().LongLongTy);

  // Is DefinedEVal greater or equal with V?
  SVal GE = Bldr.evalBinOp(State, BO_GE, EVal, V, Bldr.getConditionType());
  if (GE.isUnknownOrUndef())
    return false;
  ConstraintManager &CM = C.getConstraintManager();
  ProgramStateRef StGE, StLT;
  std::tie(StGE, StLT) = CM.assumeDual(State, GE.castAs<DefinedSVal>());
  return StGE && !StLT;
}

// Is E value negative?
static bool isNegative(CheckerContext &C, const Expr *E) {
  ProgramStateRef State = C.getState();
  SVal EVal = State->getSVal(E, C.getLocationContext());
  if (EVal.isUnknownOrUndef() || !EVal.getAs<NonLoc>())
    return false;
  DefinedSVal DefinedEVal = EVal.castAs<DefinedSVal>();

  SValBuilder &Bldr = C.getSValBuilder();
  DefinedSVal V = Bldr.makeIntVal(0, false);

  SVal LT =
      Bldr.evalBinOp(State, BO_LT, DefinedEVal, V, Bldr.getConditionType());

  // Is E value greater than MaxVal?
  ConstraintManager &CM = C.getConstraintManager();
  ProgramStateRef StNegative, StPositive;
  std::tie(StNegative, StPositive) =
      CM.assumeDual(State, LT.castAs<DefinedSVal>());

  return StNegative && !StPositive;
}

bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast,
                                        CheckerContext &C) const {
  // Don't warn about explicit loss of precision.
  if (Cast->isEvaluatable(C.getASTContext()))
    return false;

  QualType CastType = Cast->getType();
  QualType SubType = Cast->IgnoreParenImpCasts()->getType();

  if (!CastType->isIntegerType() || !SubType->isIntegerType())
    return false;

  if (C.getASTContext().getIntWidth(CastType) >=
      C.getASTContext().getIntWidth(SubType))
    return false;

  unsigned W = C.getASTContext().getIntWidth(CastType);
  if (W == 1 || W >= 64U)
    return false;

  unsigned long long MaxVal = 1ULL << W;
  return isGreaterEqual(C, Cast->getSubExpr(), MaxVal);
}

bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast,
                                   CheckerContext &C) const {
  QualType CastType = Cast->getType();
  QualType SubType = Cast->IgnoreParenImpCasts()->getType();

  if (!CastType->isUnsignedIntegerType() || !SubType->isSignedIntegerType())
    return false;

  return isNegative(C, Cast->getSubExpr());
}

void ento::registerConversionChecker(CheckerManager &mgr) {
  mgr.registerChecker<ConversionChecker>();
}
@


1.1.1.1
log
@Import Clang pre-4.0.0 r291444.
@
text
@@


1.1.1.2
log
@Import clang r309604 from branches/release_50
@
text
@d44 1
a44 2
  bool isLossOfPrecision(const ImplicitCastExpr *Cast, QualType DestType,
                         CheckerContext &C) const;
d76 2
a77 1
    if (Opc == BO_Assign) {
d79 1
a79 16
      LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
    } else if (Opc == BO_AddAssign || Opc == BO_SubAssign) {
      // No loss of sign.
      LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
    } else if (Opc == BO_MulAssign) {
      LossOfSign = isLossOfSign(Cast, C);
      LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
    } else if (Opc == BO_DivAssign || Opc == BO_RemAssign) {
      LossOfSign = isLossOfSign(Cast, C);
      // No loss of precision.
    } else if (Opc == BO_AndAssign) {
      LossOfSign = isLossOfSign(Cast, C);
      // No loss of precision.
    } else if (Opc == BO_OrAssign || Opc == BO_XorAssign) {
      LossOfSign = isLossOfSign(Cast, C);
      LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
d85 1
a85 1
    LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
a115 7
  if (EVal.isUnknownOrUndef())
    return false;
  if (!EVal.getAs<NonLoc>() && EVal.getAs<Loc>()) {
    ProgramStateManager &Mgr = C.getStateManager();
    EVal =
        Mgr.getStoreManager().getBinding(State->getStore(), EVal.castAs<Loc>());
  }
d156 1
a156 2
                                          QualType DestType,
                                          CheckerContext &C) const {
d161 1
d164 1
a164 1
  if (!DestType->isIntegerType() || !SubType->isIntegerType())
d167 1
a167 1
  if (C.getASTContext().getIntWidth(DestType) >=
d171 1
a171 1
  unsigned W = C.getASTContext().getIntWidth(DestType);
@


1.1.1.2.4.1
log
@Sync with HEAD
@
text
@d126 51
d198 1
a198 1
  return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal);
d202 1
a202 1
                                     CheckerContext &C) const {
d209 1
a209 1
  return C.isNegative(Cast->getSubExpr());
@


1.1.1.2.4.2
log
@Mostly merge changes from HEAD upto 20200411
@
text
@@


1.1.1.2.2.1
log
@Sync with HEAD
@
text
@d126 51
d198 1
a198 1
  return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal);
d202 1
a202 1
                                     CheckerContext &C) const {
d209 1
a209 1
  return C.isNegative(Cast->getSubExpr());
@


1.1.1.3
log
@Import clang r337282 from trunk
@
text
@d126 51
d198 1
a198 1
  return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal);
d202 1
a202 1
                                     CheckerContext &C) const {
d209 1
a209 1
  return C.isNegative(Cast->getSubExpr());
@


1.1.1.4
log
@Mark old LLVM instance as dead.
@
text
@@


1.1.1.1.4.1
log
@file ConversionChecker.cpp was added on branch pgoyette-localcount on 2017-03-20 06:52:42 +0000
@
text
@d1 192
@


1.1.1.1.4.2
log
@Sync with HEAD
@
text
@a0 192
//=== ConversionChecker.cpp -------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Check that there is no loss of sign/precision in assignments, comparisons
// and multiplications.
//
// ConversionChecker uses path sensitive analysis to determine possible values
// of expressions. A warning is reported when:
// * a negative value is implicitly converted to an unsigned value in an
//   assignment, comparison or multiplication.
// * assignment / initialization when source value is greater than the max
//   value of target
//
// Many compilers and tools have similar checks that are based on semantic
// analysis. Those checks are sound but have poor precision. ConversionChecker
// is an alternative to those checks.
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
#include "clang/AST/ParentMap.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"

using namespace clang;
using namespace ento;

namespace {
class ConversionChecker : public Checker<check::PreStmt<ImplicitCastExpr>> {
public:
  void checkPreStmt(const ImplicitCastExpr *Cast, CheckerContext &C) const;

private:
  mutable std::unique_ptr<BuiltinBug> BT;

  // Is there loss of precision
  bool isLossOfPrecision(const ImplicitCastExpr *Cast, CheckerContext &C) const;

  // Is there loss of sign
  bool isLossOfSign(const ImplicitCastExpr *Cast, CheckerContext &C) const;

  void reportBug(ExplodedNode *N, CheckerContext &C, const char Msg[]) const;
};
}

void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast,
                                     CheckerContext &C) const {
  // TODO: For now we only warn about DeclRefExpr, to avoid noise. Warn for
  // calculations also.
  if (!isa<DeclRefExpr>(Cast->IgnoreParenImpCasts()))
    return;

  // Don't warn for loss of sign/precision in macros.
  if (Cast->getExprLoc().isMacroID())
    return;

  // Get Parent.
  const ParentMap &PM = C.getLocationContext()->getParentMap();
  const Stmt *Parent = PM.getParent(Cast);
  if (!Parent)
    return;

  bool LossOfSign = false;
  bool LossOfPrecision = false;

  // Loss of sign/precision in binary operation.
  if (const auto *B = dyn_cast<BinaryOperator>(Parent)) {
    BinaryOperator::Opcode Opc = B->getOpcode();
    if (Opc == BO_Assign || Opc == BO_AddAssign || Opc == BO_SubAssign ||
        Opc == BO_MulAssign) {
      LossOfSign = isLossOfSign(Cast, C);
      LossOfPrecision = isLossOfPrecision(Cast, C);
    } else if (B->isRelationalOp() || B->isMultiplicativeOp()) {
      LossOfSign = isLossOfSign(Cast, C);
    }
  } else if (isa<DeclStmt>(Parent)) {
    LossOfSign = isLossOfSign(Cast, C);
    LossOfPrecision = isLossOfPrecision(Cast, C);
  }

  if (LossOfSign || LossOfPrecision) {
    // Generate an error node.
    ExplodedNode *N = C.generateNonFatalErrorNode(C.getState());
    if (!N)
      return;
    if (LossOfSign)
      reportBug(N, C, "Loss of sign in implicit conversion");
    if (LossOfPrecision)
      reportBug(N, C, "Loss of precision in implicit conversion");
  }
}

void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C,
                                  const char Msg[]) const {
  if (!BT)
    BT.reset(
        new BuiltinBug(this, "Conversion", "Possible loss of sign/precision."));

  // Generate a report for this bug.
  auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
  C.emitReport(std::move(R));
}

// Is E value greater or equal than Val?
static bool isGreaterEqual(CheckerContext &C, const Expr *E,
                           unsigned long long Val) {
  ProgramStateRef State = C.getState();
  SVal EVal = C.getSVal(E);
  if (EVal.isUnknownOrUndef() || !EVal.getAs<NonLoc>())
    return false;

  SValBuilder &Bldr = C.getSValBuilder();
  DefinedSVal V = Bldr.makeIntVal(Val, C.getASTContext().LongLongTy);

  // Is DefinedEVal greater or equal with V?
  SVal GE = Bldr.evalBinOp(State, BO_GE, EVal, V, Bldr.getConditionType());
  if (GE.isUnknownOrUndef())
    return false;
  ConstraintManager &CM = C.getConstraintManager();
  ProgramStateRef StGE, StLT;
  std::tie(StGE, StLT) = CM.assumeDual(State, GE.castAs<DefinedSVal>());
  return StGE && !StLT;
}

// Is E value negative?
static bool isNegative(CheckerContext &C, const Expr *E) {
  ProgramStateRef State = C.getState();
  SVal EVal = State->getSVal(E, C.getLocationContext());
  if (EVal.isUnknownOrUndef() || !EVal.getAs<NonLoc>())
    return false;
  DefinedSVal DefinedEVal = EVal.castAs<DefinedSVal>();

  SValBuilder &Bldr = C.getSValBuilder();
  DefinedSVal V = Bldr.makeIntVal(0, false);

  SVal LT =
      Bldr.evalBinOp(State, BO_LT, DefinedEVal, V, Bldr.getConditionType());

  // Is E value greater than MaxVal?
  ConstraintManager &CM = C.getConstraintManager();
  ProgramStateRef StNegative, StPositive;
  std::tie(StNegative, StPositive) =
      CM.assumeDual(State, LT.castAs<DefinedSVal>());

  return StNegative && !StPositive;
}

bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast,
                                        CheckerContext &C) const {
  // Don't warn about explicit loss of precision.
  if (Cast->isEvaluatable(C.getASTContext()))
    return false;

  QualType CastType = Cast->getType();
  QualType SubType = Cast->IgnoreParenImpCasts()->getType();

  if (!CastType->isIntegerType() || !SubType->isIntegerType())
    return false;

  if (C.getASTContext().getIntWidth(CastType) >=
      C.getASTContext().getIntWidth(SubType))
    return false;

  unsigned W = C.getASTContext().getIntWidth(CastType);
  if (W == 1 || W >= 64U)
    return false;

  unsigned long long MaxVal = 1ULL << W;
  return isGreaterEqual(C, Cast->getSubExpr(), MaxVal);
}

bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast,
                                   CheckerContext &C) const {
  QualType CastType = Cast->getType();
  QualType SubType = Cast->IgnoreParenImpCasts()->getType();

  if (!CastType->isUnsignedIntegerType() || !SubType->isSignedIntegerType())
    return false;

  return isNegative(C, Cast->getSubExpr());
}

void ento::registerConversionChecker(CheckerManager &mgr) {
  mgr.registerChecker<ConversionChecker>();
}
@


