26#include "llvm/ADT/STLExtras.h"
27#include "llvm/ADT/iterator_range.h"
28#include "llvm/Support/Error.h"
29#include "llvm/Support/JSON.h"
37json::Object serializeUnsafeBufferUsageAnalysisResult(
48deserializeUnsafeBufferUsageAnalysisResult(
50 const json::Array *Content =
60 return UnsafeBuffers.takeError();
62 auto Ret = std::make_unique<UnsafeBufferUsageAnalysisResult>();
64 Ret->UnsafeBuffers = std::move(*UnsafeBuffers);
65 return std::move(Ret);
68JSONFormat::AnalysisResultRegistry::Add<UnsafeBufferUsageAnalysisResult>
69 RegisterUnsafeBufferUsageResultForJSON(
70 serializeUnsafeBufferUsageAnalysisResult,
71 deserializeUnsafeBufferUsageAnalysisResult);
73class UnsafeBufferUsageAnalysis final
75 UnsafeBufferUsageEntitySummary> {
77 llvm::Error add(EntityId Id,
78 const UnsafeBufferUsageEntitySummary &Summary)
override {
79 auto UnsafeBuffersOfEntity = getUnsafeBuffers(Summary);
81 getResult().UnsafeBuffers[Id] = EntityPointerLevelSet(
82 UnsafeBuffersOfEntity.begin(), UnsafeBuffersOfEntity.end());
83 return llvm::Error::success();
87AnalysisRegistry::Add<UnsafeBufferUsageAnalysis>
88 RegisterUnsafeBufferUsageAnalysis(
89 "Whole-program unsafe buffer usage analysis");
95json::Object serializeUnsafeBufferReachableAnalysisResult(
106deserializeUnsafeBufferReachableAnalysisResult(
108 const json::Array *Content =
113 Obj,
"an object with a key %s",
119 return Reachables.takeError();
121 auto Ret = std::make_unique<UnsafeBufferReachableAnalysisResult>();
123 Ret->Reachables = std::move(*Reachables);
124 return std::move(Ret);
127JSONFormat::AnalysisResultRegistry::Add<UnsafeBufferReachableAnalysisResult>
128 RegisterUnsafeBufferReachableResultForJSON(
129 serializeUnsafeBufferReachableAnalysisResult,
130 deserializeUnsafeBufferReachableAnalysisResult);
142class UnsafeBufferReachableAnalysis
144 PointerFlowAnalysisResult,
145 TypeConstrainedPointersAnalysisResult,
146 UnsafeBufferUsageAnalysisResult> {
173 struct BoundsPropagationGraph {
178 BoundsPropagationGraph(
EdgeSet PointerFlows)
179 : PointerFlows(std::move(PointerFlows)) {}
183 EntityPointerLevelSet getDestNodes(
const EntityPointerLevel &Src)
const {
184 unsigned SrcPtrLv = Src.getPointerLevel();
185 EntityPointerLevelSet
Result;
187 for (
unsigned P = 1; P <= SrcPtrLv; ++P) {
188 auto I = PointerFlows.find(buildEntityPointerLevel(Src.getEntity(), P));
190 if (I != PointerFlows.end()) {
191 unsigned Delta = SrcPtrLv - P;
192 for (
const auto &EPL : I->second)
193 Result.insert(buildEntityPointerLevel(
194 EPL.getEntity(), EPL.getPointerLevel() + Delta));
201 std::map<EntityId, BoundsPropagationGraph> BPG;
205 using EPLPtr =
const EntityPointerLevel *;
210 void updateReachablesWithOutgoings(EPLPtr EPL,
211 std::vector<EPLPtr> &WorkList) {
212 for (
auto &[Id, SubGraph] : BPG) {
213 auto R = SubGraph.getDestNodes(*EPL);
215 for (
const auto &Dst : R) {
216 auto [It, Inserted] = getResult().Reachables[Id].insert(Dst);
218 WorkList.push_back(&*It);
225 void computeReachableUnsafePointers() {
226 auto &Reachables = getResult().Reachables;
228 std::vector<EPLPtr> Worklist;
230 for (
auto &[Id, EPLs] : Reachables)
231 for (
auto &EPL : EPLs)
232 Worklist.push_back(&EPL);
234 while (!Worklist.empty()) {
235 EPLPtr Node = Worklist.back();
238 updateReachablesWithOutgoings(Node, Worklist);
244 initialize(
const PointerFlowAnalysisResult &PtrFlowGraph,
245 const TypeConstrainedPointersAnalysisResult &TypeConstraints,
246 const UnsafeBufferUsageAnalysisResult &UnsafePtrs)
override {
247 auto HasNoTypeConstraint =
248 [&TypeConstraints](
const EntityPointerLevel &EPL) {
249 return !TypeConstraints.
contains(EPL.getEntity());
253 for (
auto &[Id, SubGraph] : PtrFlowGraph.
Edges) {
256 for (
const auto &[Src, Dsts] : SubGraph) {
257 if (TypeConstraints.
contains(Src.getEntity()))
260 auto FilteredDstRange =
261 llvm::make_filter_range(Dsts, HasNoTypeConstraint);
263 if (!FilteredDstRange.empty())
264 FilteredSubGraph[Src].insert(FilteredDstRange.begin(),
265 FilteredDstRange.end());
267 if (!FilteredSubGraph.empty())
268 BPG.try_emplace(Id, std::move(FilteredSubGraph));
272 for (
auto &[Contributor, EPLs] : UnsafePtrs) {
273 auto FilteredRange = llvm::make_filter_range(EPLs, HasNoTypeConstraint);
275 if (!FilteredRange.empty())
276 getResult().Reachables[Contributor].insert(FilteredRange.begin(),
277 FilteredRange.end());
279 return llvm::Error::success();
282 llvm::Expected<bool>
step()
override {
286 computeReachableUnsafePointers();
292AnalysisRegistry::Add<UnsafeBufferReachableAnalysis>
293 RegisterUnsafeBufferReachableAnalysis(
294 "Reachable pointers from unsafe buffer usage in pointer flow graph");
Result
Implement __builtin_bit_cast and related operations.
Typed intermediate that concrete derived analyses inherit from.
Typed intermediate that concrete summary analyses inherit from.
PRESERVE_NONE bool Ret(InterpState &S)
Expected< std::map< EntityId, EntityPointerLevelSet > > entityPointerLevelMapFromJSON(const llvm::json::Array &Content, JSONFormat::EntityIdFromJSONFn IdFromJSON)
Deserialize a flat array of alternating [EntityId, EntityPointerLevelSet, ...] pairs into a map.
std::map< EntityPointerLevel, EntityPointerLevelSet > EdgeSet
Maps each LHS pointer (source / assignee) to the set of RHS pointers (destinations / assigned values)...
volatile int UnsafeBufferUsageAnalysisAnchorSource
llvm::Error makeSawButExpectedError(const JSONTy &Saw, llvm::StringRef Expected, const Ts &...ExpectedArgs)
constexpr llvm::StringLiteral UnsafeBufferUsageAnalysisResultName
constexpr llvm::StringLiteral UnsafeBufferReachableAnalysisResultName
llvm::json::Array entityPointerLevelMapToJSON(const std::map< EntityId, EntityPointerLevelSet > &Map, JSONFormat::EntityIdToJSONFn IdToJSON)
Serialize a map<EntityId, EntityPointerLevelSet> as a flat array of alternating [EntityId,...
Diagnostic wrappers for TextAPI types for error reporting.
float __ovld __cnfn step(float, float)
Returns 0.0 if x < edge, otherwise it returns 1.0.
std::map< EntityId, EdgeSet > Edges
bool contains(const EntityId &Id) const