Skip to content

Writing an IFDS Analysis

Fabian Schiebel edited this page Jun 17, 2023 · 6 revisions

In order to solve a data-flow analysis using IFDS one basically only has to implement a single class. It is a good idea to create name the analysis using the naming conventions that can be found in the corresponding problem directories.

To make the class an analysis problem our solver is able to solve, you let your class inherit from 'IFDSTabulationProblem' interface. The concrete analysis is formulated by overwriting all abstract functions of the interface. The member functions you have to override are:

  • getNormalFlowFunction()

    • Returns flow functions that describe the intra-procedural flows.
  • getCallFlowFunction()

    • Express what the solver should do when it hits a call-site. This flow function factory usually returns a flow function that maps the actual parameters to the formal parameters of the called function.
  • getRetFlowFunction()

    • Usually propagates the information at the end of the callee back to the caller.
  • getCallToRetFlowFunction()

    • Every information that is not involved in the function call is handled here. Usually just passes every information as identity, except for pointer parameters that may be changed in the callee.
  • Optional: getSummaryFlowFunction()

    • Default: Implemented to return nullptr. But can be used to model llvm.intrinsic functions or libc function that one does not wish to follow (e.g if no implementation is available).
  • initialSeeds()

    • The initial seeds are the starting points of an analysis. An analysis can start at one or more points in the target program. The function must return start points as well as a set of data-flow facts that hold at these program points. Unless the concrete analysis requires something special, one would usually treat the first instruction of the main function as a starting point and use the special zero fact to hold at the analysis start.
  • createZeroValue()

    • This function must define what value the analysis should use as the special zero value.
  • Constructor

    • The constructor of an analysis receives the ICFG that shall be used to solve the analysis. Here is an example of how your constructor can looks like:
  IFDSSolverTest::IFDSSolverTest(const LLVMProjectIRDB *IRDB,
                               std::vector<std::string> EntryPoints)
    : IFDSTabulationProblem(IRDB, std::move(EntryPoints), createZeroValue()) {}

Memory Management

Our IFDS interface functions use the custom type FlowFunctionPtrType as a return type. This type hides the memory management mechanism used from the actual analysis interface. Currently, FlowFunctionPtrType maps to std::shared_ptr<FlowFunction<D>>, but this may change in the future.

Clone this wiki locally