SVF icon indicating copy to clipboard operation
SVF copied to clipboard

SVFG does not use indirect call edges to join formal and actual parameters

Open acidghost opened this issue 1 year ago • 15 comments

I'm trying to use SVFG to compute a def-use graph in order to compute a thin backward interprocedural slice from a Value.

The following case produces an SVFG as I would expect:

#include <stddef.h>
#include <stdint.h>

int myFunc(int A) {
  // target
  return A + 42;
}

int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
  if (Size < 1)
    return 1;
  int Type = Data[0];

  myFunc(Type);

  return 0;
}

The SVFG for the above example clearly shows a path from, e.g., LoadSVFGNode ID 18 (bottom left in figure) to the 0th argument of LLVMFuzzerTestOneInput: svfg-direct

If I instead call the function indirectly:

  // myFunc(Type);
  int (*Fn)(int) = myFunc;
  Fn(Type);

Then the SVFG for this version does not link the actual and formal parameter of the indirectly called function: svfg-indir

I verified that the indirect call gets resolved correctly by PTA. What am I missing?

Bitcode: https://godbolt.org/z/rjM9ban1r.

The code I'm using to build the SVFG is the same as the example pass.

acidghost avatar Dec 11 '23 23:12 acidghost

Did you try ‘wpa -ander -svfg ‘?

yuleisui avatar Dec 11 '23 23:12 yuleisui

I think you might have to update the svfg by calling its ‘updatecallgraph’ method to connect indirect edges

yuleisui avatar Dec 11 '23 23:12 yuleisui

Did you try ‘wpa -ander -svfg ‘?

I'm running equivalent code:

  auto *LLVMModuleSet = SVF::LLVMModuleSet::getLLVMModuleSet();
  auto *SVFModule = LLVMModuleSet->buildSVFModule(M);

  SVF::SVFIRBuilder Builder(SVFModule);
  auto *PAG = Builder.build();

  auto *Andersen = SVF::AndersenWaveDiff::createAndersenWaveDiff(PAG);

  SVF::SVFGBuilder SvfBuilder(true);
  SVF::SVFG *SVFG = SvfBuilder.buildFullSVFG(Andersen);
  SVFG->updateCallGraph(Andersen);

  // [...]

  SVFG->dump("svfg");

  // clean up memory
  // delete SVFG;
  SVF::AndersenWaveDiff::releaseAndersenWaveDiff();
  SVF::SVFIR::releaseSVFIR();

  SVF::LLVMModuleSet::getLLVMModuleSet()->dumpModulesToFile(".svf.bc");
  SVF::LLVMModuleSet::releaseLLVMModuleSet();

I think you might have to update the svfg by calling its ‘updatecallgraph’ method to connect indirect edges

I tried that but the result is the same.

acidghost avatar Dec 11 '23 23:12 acidghost

Could you change ‘ LLVMFuzzerTestOneInput’ to be ‘main’?

yuleisui avatar Dec 11 '23 23:12 yuleisui

I tried with the following but the result is the same.

#include <stddef.h>
#include <stdint.h>

int myFunc(int A) {
  // target
  return A + 42;
}

// int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
int main(int argc, char **argv) {
  // if (Size < 1)
  //   return 1;
  // int Type = Data[0];
  if (argc < 2)
    return 1;
  int Type = argv[1][0];

  // myFunc(Type);

  int (*Fn)(int) = myFunc;
  Fn(Type);

  return 0;
}

acidghost avatar Dec 12 '23 07:12 acidghost

I am not available to debug now. The easiest way is to debug into ‘ updateCallGraph’ to see what is happening there.

yuleisui avatar Dec 12 '23 07:12 yuleisui

@jumormt could you have a quick Look at this issue?

yuleisui avatar Dec 12 '23 07:12 yuleisui

The issue seems to be related to these lines https://github.com/SVF-tools/SVF/blob/a83aec286b249675a56f1b48b987ceb4d8672b69/svf/lib/Graphs/VFG.cpp#L990-L991

Because the argument is not a pointer it does not connect it with the callsite parameter:

Matching ValVar ID: 67
   %19 = load i32, i32* %6, align 4, !dbg !36 { "ln": 21, "cl": 6, "fl": "test-indir.c" } and ValVar ID: 7
 i32 %0 { 0th arg myFunc "ln": 4, "file": "test-indir.c" }
    pointers? 0 0

I'm wondering, why does it need function arguments to be pointers in this case (i.e. calling the function indirectly) and does not have this requirement if the function is called directly?

acidghost avatar Dec 12 '23 09:12 acidghost

Yes, this is the problem and indirectly called function should be done the same way as the original SVFG

yuleisui avatar Dec 12 '23 09:12 yuleisui

Yes, this is the problem and indirectly called function should be done the same way as the original SVFG

Does it mean that updateCallGraph needs to be properly implemented for SVFG and should not rely on VFG::updateCallGraph?

acidghost avatar Dec 12 '23 09:12 acidghost

I just tried to commend out the if branch that checks if the argument is a pointer and it seems to be working.

acidghost avatar Dec 12 '23 09:12 acidghost

Hi @acidghost , can you try this patch #1282 to check if it fixes your issue?

jumormt avatar Dec 12 '23 10:12 jumormt

@acidghost could you try the patch before I merge?

yuleisui avatar Dec 12 '23 10:12 yuleisui

Seems to be working also for larger examples. Thank you very much!

I'll do more complex testing and reopen if I find something awry.

acidghost avatar Dec 12 '23 10:12 acidghost

Good!

yuleisui avatar Dec 12 '23 10:12 yuleisui