30#include "llvm/ADT/DenseMap.h"
31#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/SmallVector.h"
33#include "llvm/ADT/iterator_range.h"
34#include "llvm/Support/Error.h"
35#include "llvm/Support/JSON.h"
43json::Object serializeUnsafeBufferUsageAnalysisResult(
54deserializeUnsafeBufferUsageAnalysisResult(
56 const json::Array *Content =
66 return UnsafeBuffers.takeError();
68 auto Ret = std::make_unique<UnsafeBufferUsageAnalysisResult>();
70 Ret->UnsafeBuffers = std::move(*UnsafeBuffers);
71 return std::move(Ret);
74JSONFormat::AnalysisResultRegistry::Add<UnsafeBufferUsageAnalysisResult>
75 RegisterUnsafeBufferUsageResultForJSON(
76 serializeUnsafeBufferUsageAnalysisResult,
77 deserializeUnsafeBufferUsageAnalysisResult);
79class UnsafeBufferUsageAnalysis final
81 UnsafeBufferUsageEntitySummary> {
83 llvm::Error add(EntityId Id,
84 const UnsafeBufferUsageEntitySummary &Summary)
override {
87 getResult().UnsafeBuffers[Id] = EntityPointerLevelSet(
88 UnsafeBuffersOfEntity.begin(), UnsafeBuffersOfEntity.end());
89 return llvm::Error::success();
93AnalysisRegistry::Add<UnsafeBufferUsageAnalysis>
94 RegisterUnsafeBufferUsageAnalysis(
95 "Whole-program unsafe buffer usage analysis");
101json::Object serializeUnsafeBufferReachableAnalysisResult(
112deserializeUnsafeBufferReachableAnalysisResult(
114 const json::Array *Content =
119 Obj,
"an object with a key %s",
125 return Reachables.takeError();
127 auto Ret = std::make_unique<UnsafeBufferReachableAnalysisResult>();
129 Ret->Reachables = std::move(*Reachables);
130 return std::move(Ret);
133JSONFormat::AnalysisResultRegistry::Add<UnsafeBufferReachableAnalysisResult>
134 RegisterUnsafeBufferReachableResultForJSON(
135 serializeUnsafeBufferReachableAnalysisResult,
136 deserializeUnsafeBufferReachableAnalysisResult);
152class UnsafeBufferReachableAnalysis
154 UnsafeBufferReachableAnalysisResult, PointerFlowAnalysisResult,
155 TypeConstrainedPointersAnalysisResult,
156 UnsafeBufferUsageAnalysisResult, VirtualMethodFamilyAnalysisResult> {
158 struct BoundsPropagationGraph {
163 EntityPointerLevelSet getDestNodes(
const EntityPointerLevel &Src)
const {
164 auto I = PointerFlows.find(Src);
165 if (I == PointerFlows.end())
171 std::map<EntityId, BoundsPropagationGraph> BPG;
174 const llvm::DenseMap<EntityId, EntityId> *FamilyOf =
nullptr;
177 llvm::DenseMap<EntityId, llvm::SmallVector<EntityId, 2>> FamilyMembers;
181 using EPLPtr =
const EntityPointerLevel *;
184 void insertReachable(
const EntityPointerLevel &EPL,
185 std::vector<EPLPtr> &WorkList) {
186 auto [It, Inserted] = getResult().Reachables.insert(EPL);
188 WorkList.push_back(&*It);
194 void updateReachablesWithOutgoings(EPLPtr EPL,
195 std::vector<EPLPtr> &WorkList) {
196 for (
auto &[Id, SubGraph] : BPG) {
197 auto R = SubGraph.getDestNodes(*EPL);
199 for (
const auto &Dst : R)
200 insertReachable(Dst, WorkList);
206 void updateReachablesWithFamily(EPLPtr EPL, std::vector<EPLPtr> &WorkList) {
207 auto FamilyIt = FamilyOf->find(EPL->getEntity());
208 if (FamilyIt == FamilyOf->end())
210 auto MembersIt = FamilyMembers.find(FamilyIt->second);
211 if (MembersIt == FamilyMembers.end())
213 for (EntityId Member : MembersIt->second)
220 void computeReachableUnsafePointers() {
221 auto &Reachables = getResult().Reachables;
223 std::vector<EPLPtr> Worklist;
225 for (
auto &EPL : Reachables)
226 Worklist.push_back(&EPL);
228 while (!Worklist.empty()) {
229 EPLPtr Node = Worklist.back();
232 updateReachablesWithOutgoings(Node, Worklist);
233 updateReachablesWithFamily(Node, Worklist);
239 initialize(
const PointerFlowAnalysisResult &PtrFlowGraph,
240 const TypeConstrainedPointersAnalysisResult &TypeConstraints,
241 const UnsafeBufferUsageAnalysisResult &UnsafePtrs,
242 const VirtualMethodFamilyAnalysisResult &Families)
override {
243 auto HasNoTypeConstraint =
244 [&TypeConstraints](
const EntityPointerLevel &EPL) {
245 return !TypeConstraints.
contains(EPL.getEntity());
249 for (
auto &[Id, SubGraph] : PtrFlowGraph.
Edges) {
252 for (
const auto &[Src, Dsts] : SubGraph) {
253 if (TypeConstraints.
contains(Src.getEntity()))
256 auto FilteredDstRange =
257 llvm::make_filter_range(Dsts, HasNoTypeConstraint);
259 if (!FilteredDstRange.empty())
260 FilteredSubGraph[Src].insert(FilteredDstRange.begin(),
261 FilteredDstRange.end());
263 if (!FilteredSubGraph.empty())
265 BoundsPropagationGraph{std::move(FilteredSubGraph)});
269 for (
auto &[Contributor, EPLs] : UnsafePtrs) {
270 auto FilteredRange = llvm::make_filter_range(EPLs, HasNoTypeConstraint);
272 getResult().Reachables.insert(FilteredRange.begin(), FilteredRange.end());
278 if (!TypeConstraints.
contains(Slot))
279 FamilyMembers[FamilyId].push_back(Slot);
280 return llvm::Error::success();
283 llvm::Expected<bool>
step()
override {
287 computeReachableUnsafePointers();
293AnalysisRegistry::Add<UnsafeBufferReachableAnalysis>
294 RegisterUnsafeBufferReachableAnalysis(
295 "Reachable pointers from unsafe buffer usage in pointer flow graph, "
296 "family-closed across virtual method overrides");
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)
EntityPointerLevel buildEntityPointerLevel(EntityId, unsigned)
An EntityPointerLevel is associated with a level of the declared pointer/array type of an entity.
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.
llvm::json::Array entityPointerLevelSetToJSON(llvm::iterator_range< EntityPointerLevelSet::const_iterator > EPLs, JSONFormat::EntityIdToJSONFn EntityId2JSON)
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
Expected< EntityPointerLevelSet > entityPointerLevelSetFromJSON(const llvm::json::Array &EPLsData, JSONFormat::EntityIdFromJSONFn EntityIdFromJSON)
constexpr llvm::StringLiteral UnsafeBufferReachableAnalysisResultName
llvm::iterator_range< EntityPointerLevelSet::const_iterator > getUnsafeBuffers(const UnsafeBufferUsageEntitySummary &)
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
llvm::DenseMap< EntityId, EntityId > RetAndParamData
Maps each parameter or return slot to the ID of the family it belongs to.