Skip to content

Commit 1ce7520

Browse files
authored
Merge pull request #258 from plum-umd/RootCauseDiag
Add flag for root cause diagnostic output
2 parents 7a47739 + 33bf75c commit 1ce7520

File tree

10 files changed

+98
-25
lines changed

10 files changed

+98
-25
lines changed

clang/include/clang/CConv/CCGlobalOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,7 @@ extern bool NewSolver;
2626
extern std::string BaseDir;
2727
extern std::vector<std::string> AllocatorFunctions;
2828
extern bool AddCheckedRegions;
29+
extern bool WarnRootCause;
30+
extern bool WarnAllRootCause;
2931

3032
#endif //_CCGLOBALOPTIONS_H

clang/include/clang/CConv/CConv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ struct CConvertOptions {
5151
bool AddCheckedRegions;
5252

5353
bool DisableCCTypeChecker;
54+
55+
bool WarnRootCause;
56+
57+
bool WarnAllRootCause;
5458
};
5559

5660
// The main interface exposed by the CConv to interact with the tool.

clang/include/clang/CConv/ConstraintVariables.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,14 +304,27 @@ class PointerVariableConstraint : public ConstraintVariable {
304304
bool solutionEqualTo(Constraints &CS,
305305
const ConstraintVariable *CV) const override;
306306

307-
// Constructor for when we have a Decl. K is the current free
308-
// constraint variable index. We don't need to explicitly pass
309-
// the name because it's available in 'D'.
307+
// Construct a PVConstraint when the variable is generated by a specific
308+
// declaration (D). This constructor calls the next constructor below with
309+
// QT and N instantiated with information in D.
310310
PointerVariableConstraint(clang::DeclaratorDecl *D,
311311
ProgramInfo &I, const clang::ASTContext &C);
312312

313-
// Constructor for when we only have a Type. Needs a string name
314-
// N for the name of the variable that this represents.
313+
// QT: Defines the type for the constraint variable. One atom is added for
314+
// each level of pointer (or array) indirection in the type.
315+
// D: If this constraint is generated because of a variable declaration, this
316+
// should be a pointer to the the declaration AST node. May be null if the
317+
// constraint is not generated by a declaration.
318+
// N: Name for the constraint variable. This may be chosen arbitrarily, as it
319+
// it is only used for labeling graph nodes. Equality is based on generated
320+
// unique ids.
321+
// I and C: Context objects required for this construction. It is expected
322+
// that all constructor calls will take the same global objects here.
323+
// inFunc: If this variable is part of a function prototype, this string is
324+
// the name of the function. nullptr otherwise.
325+
// IsGeneric: CheckedC supports generic types (_Itype_for_any) which need less
326+
// restrictive constraints. Set to true to indicate that this
327+
// variable is generic.
315328
PointerVariableConstraint(const clang::QualType &QT,
316329
clang::DeclaratorDecl *D, std::string N,
317330
ProgramInfo &I,

clang/include/clang/CConv/RewriteUtils.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,13 @@ class RewriteConsumer : public ASTConsumer {
219219
ProgramInfo &Info;
220220
static std::map<std::string, std::string> ModifiedFuncSignatures;
221221
std::string &OutputPostfix;
222+
223+
// A single header file can be included in multiple translations units. This
224+
// set ensures that the diagnostics for a header file are not emitted each
225+
// time a translation unit containing the header is vistied.
226+
static std::set<PersistentSourceLoc *> EmittedDiagnostics;
227+
228+
void emitRootCauseDiagnostics(ASTContext &Context);
222229
};
223230

224231
bool canRewrite(Rewriter &R, SourceRange &SR);

clang/lib/CConv/CConv.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,11 @@ bool AllTypes;
5151
std::string BaseDir;
5252
bool AddCheckedRegions;
5353
bool DisableCCTypeChecker;
54+
bool WarnRootCause;
55+
bool WarnAllRootCause;
5456
std::set<std::string> FilePaths;
5557

58+
5659
static ClangTool *GlobalCTool = nullptr;
5760

5861
static CompilationDatabase *CurrCompDB = nullptr;
@@ -185,6 +188,8 @@ CConvInterface::CConvInterface(const struct CConvertOptions &CCopt,
185188
AddCheckedRegions = CCopt.AddCheckedRegions;
186189
DisableCCTypeChecker = CCopt.DisableCCTypeChecker;
187190
AllocatorFunctions = CCopt.AllocatorFunctions;
191+
WarnRootCause = CCopt.WarnRootCause || CCopt.WarnAllRootCause;
192+
WarnAllRootCause = CCopt.WarnAllRootCause;
188193

189194
llvm::InitializeAllTargets();
190195
llvm::InitializeAllTargetMCs();

clang/lib/CConv/ConstraintBuilder.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,7 @@ class FunctionVisitor : public RecursiveASTVisitor<FunctionVisitor> {
122122
QualType DstT = C->getType();
123123
if (!isCastSafe(DstT, SrcT)) {
124124
auto CVs = CB.getExprConstraintVars(C->getSubExpr());
125-
std::string Rsn = "Casted from " +
126-
SrcT.getAsString() + " to " +
125+
std::string Rsn = "Cast from " + SrcT.getAsString() + " to " +
127126
DstT.getAsString();
128127
CB.constraintAllCVarsToWild(CVs, Rsn, C);
129128
}

clang/lib/CConv/ConstraintResolver.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -187,17 +187,12 @@ CVarSet ConstraintResolver::getInvalidCastPVCons(Expr *E) {
187187
if (ExplicitCastExpr *ECE = dyn_cast<ExplicitCastExpr>(E))
188188
SrcType = ECE->getSubExpr()->getType();
189189

190-
auto &CS = Info.getConstraints();
191-
CAtoms NewVA;
192-
Atom *NewA = CS.getFreshVar("Invalid cast to:" + E->getType().getAsString(),
193-
VarAtom::V_Other);
194-
NewVA.push_back(NewA);
190+
auto *P = new PVConstraint(DstType, nullptr, "Invalid cast", Info, *Context);
195191

196-
PVConstraint *P = new PVConstraint(NewVA, "unsigned", "wildvar",
197-
nullptr, false, false, "");
198192
PersistentSourceLoc PL = PersistentSourceLoc::mkPSL(E, *Context);
199-
P->constrainToWild(CS, "Casted from " + SrcType.getAsString() + " to " +
200-
DstType.getAsString() , &PL);
193+
std::string Rsn =
194+
"Cast from " + SrcType.getAsString() + " to " + DstType.getAsString();
195+
P->constrainToWild(Info.getConstraints(), Rsn, &PL);
201196
Ret = {P};
202197
storePersistentConstraints(E, Ret);
203198
return Ret;
@@ -240,8 +235,7 @@ CVarSet
240235
!(SubTypE->isFunctionType() || SubTypE->isArrayType() ||
241236
SubTypE->isVoidPointerType()) &&
242237
!isCastSafe(TypE, SubTypE)) {
243-
std::string Rsn = "Casted from " +
244-
SubTypE.getAsString() + " to " +
238+
std::string Rsn = "Cast from " + SubTypE.getAsString() + " to " +
245239
TypE.getAsString();
246240
constraintAllCVarsToWild(CVs, Rsn, IE);
247241
return getInvalidCastPVCons(E);

clang/lib/CConv/ConstraintVariables.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -373,11 +373,9 @@ PointerVariableConstraint::PointerVariableConstraint(const QualType &QT,
373373

374374
bool IsWild = !IsGeneric && (isVarArgType(BaseType) || isTypeHasVoid(QT));
375375
if (IsWild) {
376-
std::string Rsn = "Default Var arg list type.";
377-
if (D && hasVoidType(D))
378-
Rsn = "Default void* type";
379-
// TODO: Github issue #61: improve handling of types for
380-
// Variable arguments.
376+
std::string Rsn =
377+
isTypeHasVoid(QT) ? "Default void* type" : "Default Var arg list type";
378+
// TODO: Github issue #61: improve handling of types for variable arguments.
381379
for (const auto &V : vars)
382380
if (VarAtom *VA = dyn_cast<VarAtom>(V))
383381
CS.addConstraint(CS.createGeq(VA, CS.getWild(), Rsn));

clang/lib/CConv/RewriteUtils.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "clang/CConv/DeclRewriter.h"
1616
#include "clang/Tooling/Refactoring/SourceCode.h"
1717
#include "clang/CConv/CCGlobalOptions.h"
18+
#include "clang/Basic/DiagnosticCConvKinds.inc"
1819

1920
using namespace llvm;
2021
using namespace clang;
@@ -360,9 +361,46 @@ std::string ArrayBoundsRewriter::getBoundsString(PVConstraint *PV,
360361
return BString;
361362
}
362363

364+
std::set<PersistentSourceLoc *> RewriteConsumer::EmittedDiagnostics;
365+
void RewriteConsumer::emitRootCauseDiagnostics(ASTContext &Context) {
366+
clang::DiagnosticsEngine &DE = Context.getDiagnostics();
367+
unsigned ID = DE.getCustomDiagID(DiagnosticsEngine::Warning,
368+
"Root cause of unchecked pointers: %0");
369+
auto I = Info.getInterimConstraintState();
370+
SourceManager &SM = Context.getSourceManager();
371+
for (auto &WReason : I.RealWildPtrsWithReasons) {
372+
if (I.PtrSourceMap.find(WReason.first) != I.PtrSourceMap.end()) {
373+
PersistentSourceLoc *PsInfo = I.PtrSourceMap[WReason.first];
374+
// Avoid emitting the same diagnostic message twice.
375+
if (EmittedDiagnostics.find(PsInfo) == EmittedDiagnostics.end()) {
376+
// Convert the PSL into a clang::SourceLocation that can be used with
377+
// the DiagnosticsEngine.
378+
auto File = SM.getFileManager().getFile(PsInfo->getFileName());
379+
SourceLocation SL = SM.translateFileLineCol(File, PsInfo->getLineNo(),
380+
PsInfo->getColSNo());
381+
// Limit emitted root causes to those that effect more than one pointer
382+
// or are in the main file of the TU. Alternatively, don't filter causes
383+
// if -warn-all-root-cause is passed.
384+
if (WarnAllRootCause || SM.isInMainFile(SL)
385+
|| I.GetSrcCVars(WReason.first).size() > 1) {
386+
// SL is invalid when the File is not in the current translation unit.
387+
if (SL.isValid()) {
388+
EmittedDiagnostics.insert(PsInfo);
389+
auto DiagBuilder = DE.Report(SL, ID);
390+
DiagBuilder.AddString(WReason.second.WildPtrReason);
391+
}
392+
}
393+
}
394+
}
395+
}
396+
}
397+
363398
void RewriteConsumer::HandleTranslationUnit(ASTContext &Context) {
364399
Info.enterCompilationUnit(Context);
365400

401+
if (WarnRootCause)
402+
emitRootCauseDiagnostics(Context);
403+
366404
// Rewrite Variable declarations
367405
Rewriter R(Context.getSourceManager(), Context.getLangOpts());
368406
DeclRewriter::rewriteDecls(Context, Info, R);
@@ -397,4 +435,4 @@ void RewriteConsumer::HandleTranslationUnit(ASTContext &Context) {
397435

398436
Info.exitCompilationUnit();
399437
return;
400-
}
438+
}

clang/tools/cconv-standalone/CConvStandalone.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,17 @@ static cl::opt<std::string>
104104
cl::desc("Base directory for the code we're translating"),
105105
cl::init(""), cl::cat(ConvertCategory));
106106

107+
static cl::opt<bool> OptWarnRootCause
108+
("warn-root-cause",
109+
cl::desc("Emit warnings indicating root causes of unchecked pointers."),
110+
cl::init(false), cl::cat(ConvertCategory));
111+
112+
static cl::opt<bool> OptWarnAllRootCause
113+
("warn-all-root-cause",
114+
cl::desc("Emit warnings for all root causes, "
115+
"even those unlikely to be interesting."),
116+
cl::init(false), cl::cat(ConvertCategory));
117+
107118
int main(int argc, const char **argv) {
108119
sys::PrintStackTraceOnErrorSignal(argv[0]);
109120

@@ -131,6 +142,8 @@ int main(int argc, const char **argv) {
131142
CcOptions.AddCheckedRegions = OptAddCheckedRegions;
132143
CcOptions.EnableAllTypes = OptAllTypes;
133144
CcOptions.DisableCCTypeChecker = OptDiableCCTypeChecker;
145+
CcOptions.WarnRootCause = OptWarnRootCause;
146+
CcOptions.WarnAllRootCause = OptWarnAllRootCause;
134147
//Add user specified function allocators
135148
std::string Malloc = OptMalloc.getValue();
136149
if (!Malloc.empty()) {
@@ -167,7 +180,7 @@ int main(int argc, const char **argv) {
167180
}
168181

169182
// Next solve the constraints.
170-
if (!CCInterface.SolveConstraints()) {
183+
if (!CCInterface.SolveConstraints(OptWarnRootCause)) {
171184
errs() << "Failure occurred while trying to solve constraints. Exiting.\n";
172185
return 1;
173186
}

0 commit comments

Comments
 (0)