1414//
1515// ===----------------------------------------------------------------------===//
1616
17+ #include " CHERIUtils.h"
1718#include " clang/AST/StmtVisitor.h"
1819#include " clang/ASTMatchers/ASTMatchFinder.h"
1920#include " clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
@@ -31,6 +32,9 @@ using namespace ento;
3132namespace {
3233class SubObjectRepresentabilityChecker
3334 : public Checker<check::ASTDecl<RecordDecl>> {
35+ BugType BT_1{this , " Field with imprecise subobject bounds" ,
36+ " CHERI portability" };
37+
3438public:
3539 void checkASTDecl (const RecordDecl *R, AnalysisManager &mgr,
3640 BugReporter &BR) const ;
@@ -65,7 +69,8 @@ void SubObjectRepresentabilityChecker::checkASTDecl(const RecordDecl *R,
6569 uint64_t ReqAlign = llvm::CompressedCapability::GetRequiredAlignment (
6670 Size, llvm::CompressedCapability::Cheri128)
6771 .value ();
68- if (1 << llvm::countr_zero (Offset) < ReqAlign) {
72+ uint64_t CurAlign = 1 << llvm::countr_zero (Offset);
73+ if (CurAlign < ReqAlign) {
6974 /* Emit warning */
7075 SmallString<1024 > Err;
7176 llvm::raw_svector_ostream OS (Err);
@@ -76,14 +81,64 @@ void SubObjectRepresentabilityChecker::checkASTDecl(const RecordDecl *R,
7681 OS << " (size " << Size << " )" ;
7782 OS << " requires " << ReqAlign << " byte alignment for precise bounds;" ;
7883 OS << " field offset is " << Offset;
84+ OS << " (aligned to " << CurAlign << " );" ;
85+
86+ #if 0
87+ // CHERIOT FIXME: Get rid of dependency on compressed-cap-lib
88+ using Handler = CompressedCap128;
89+ uint64_t ParentSize = ASTCtx.getTypeSize(R->getTypeForDecl())/8;
90+ Handler::addr_t InitLength = Handler ::representable_length(ParentSize);
91+ Handler::cap_t MockCap = Handler::make_max_perms_cap(0, 0, InitLength);
92+ bool exact = Handler::setbounds(&MockCap, Offset, Offset + Size);
93+ assert(!exact);
94+ auto Base = MockCap.base();
95+ Handler::addr_t Top = MockCap.top();
96+ OS << " Current bounds: " << Base << "-" << Top;
97+ #endif
98+
99+ PathDiagnosticLocation L =
100+ PathDiagnosticLocation::createBegin (D, BR.getSourceManager ());
101+ auto Report = std::make_unique<BasicBugReport>(BT_1, OS.str (), L);
102+ Report->setDeclWithIssue (D);
103+ Report->addRange (D->getSourceRange ());
104+
105+ #if 0
106+ // CHERIOT FIXME: Get rid of dependency on compressed-cap-lib
107+ auto FI = R->field_begin();
108+ while (FI != R->field_end() &&
109+ ASTCtx.getFieldOffset(*FI)/8
110+ + ASTCtx.getTypeSize(FI->getType())/8 <= Base)
111+ FI++;
112+
113+ bool Before = true;
114+ while (FI != R->field_end() && ASTCtx.getFieldOffset(*FI)/8 < Top) {
115+ if (*FI != D) {
116+ SmallString<1024> Note;
117+ llvm::raw_svector_ostream OS2(Note);
118+
119+ uint64_t CurFieldOffset = ASTCtx.getFieldOffset(*FI)/8;
120+ uint64_t CurFieldSize = ASTCtx.getTypeSize(FI->getType())/8;
121+ uint64_t BytesExposed =
122+ Before ? std::min(CurFieldSize,
123+ CurFieldOffset + CurFieldSize - Base)
124+ : std::min(CurFieldSize, Top - CurFieldOffset);
125+ OS2 << BytesExposed << "/" << CurFieldSize << " bytes exposed";
126+ if (cheri::hasCapability(FI->getType(), ASTCtx))
127+ OS2 << " (may expose capability!)";
128+
129+ PathDiagnosticLocation LN =
130+ PathDiagnosticLocation::createBegin(*FI, BR.getSourceManager());
131+ Report->addNote(OS2.str(), LN);
132+ } else
133+ Before = false;
134+ FI++;
135+ }
136+ #endif
79137
80138 // Note that this will fire for every translation unit that uses this
81139 // class. This is suboptimal, but at least scan-build will merge
82140 // duplicate HTML reports.
83- PathDiagnosticLocation L =
84- PathDiagnosticLocation::createBegin (D, BR.getSourceManager ());
85- BR.EmitBasicReport (R, this , " Field with imprecise subobject bounds" ,
86- " CHERI portability" , OS.str (), L);
141+ BR.emitReport (std::move (Report));
87142 }
88143 }
89144 }
0 commit comments