diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 889d9a4..20a3ae8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,26 +21,24 @@ jobs: - name: Install jq run: sudo apt-get update && sudo apt-get install -y jq - - name: Get next version from TestPyPI + - name: Get next version from PyPI id: get_next_version run: | PACKAGE="pysvf" - INDEX_URL="https://test.pypi.org/pypi/$PACKAGE/json" - + INDEX_URL="https://pypi.org/pypi/$PACKAGE/json" + echo "Querying $INDEX_URL ..." - VERSIONS=$(curl -s "$INDEX_URL" | jq -r '.releases | keys[]' | grep -E '^1\.0\.0\.[0-9]+$') - + VERSIONS=$(curl -s "$INDEX_URL" | jq -r '.releases | keys[]' | grep -E '^1\.0\.0\.[0-9]+$' || true) + if [ -z "$VERSIONS" ]; then - LAST_VERSION="1.0.0.0" + NEXT_VERSION="1.0.0.0" else LAST_VERSION=$(echo "$VERSIONS" | sort -V | tail -n 1) + echo "Last version: $LAST_VERSION" + NEXT_VERSION=$(echo "$LAST_VERSION" | awk -F. '{$NF+=1; print $1 "." $2 "." $3 "." $4}') fi - - echo "Last version: $LAST_VERSION" - - NEXT_VERSION=$(echo "$LAST_VERSION" | awk -F. '{$NF+=1; print $1 "." $2 "." $3 "." $4}') + echo "Next version: $NEXT_VERSION" - echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT stubtest: @@ -200,14 +198,13 @@ jobs: echo "Built wheel files:" ls -lh dist/ - - name: Publish to TestPyPI + - name: Publish to PyPI env: TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }} + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} run: | cd SVF-Python - pip install twine - twine upload --repository testpypi dist/* --verbose + twine upload dist/* --verbose - name: Upload Python wheels uses: actions/upload-artifact@v4 diff --git a/README.md b/README.md index 3650cb4..1b147cd 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ ## News +* Pysvf is now available on [PyPI](https://pypi.org/project/pysvf/). The previous Test PyPI distribution is no longer maintained. +* Thanks to [mgree](https://github.com/mgree) for contributing the `FunObjVar::getSourceLoc` binding ([#46](https://github.com/SVF-tools/SVF-Python/pull/46)). * SVF-Python now supports MTA bindings and more pointer analysis strategies(AndersenWaveDiff, AndersenBase, and Steensgaard bindings). (Thank [JoelYYoung](https://github.com/JoelYYoung) for his help!). ## 1. Introduction @@ -12,17 +14,17 @@ Pysvf can be installed in two ways: -### Method 1: Install via pip (Test PyPI) +### Method 1: Install via pip #### Requirements -- Python 3.8 - 3.11 +- Python 3.8 - 3.12 - OS: Linux X86-64, Linux Arm64, MacOS #### Install Command ```bash -python3 -m pip install -i https://test.pypi.org/simple/ pysvf +pip install pysvf ```` ### Method 2: Build from Source diff --git a/demo/icfg.ipynb b/demo/icfg.ipynb index 08da047..191642f 100644 --- a/demo/icfg.ipynb +++ b/demo/icfg.ipynb @@ -693,12 +693,12 @@ "| | `getLHSVarID` | Get the ID of the LHS variable of the load statement |\n", "| | `getRHSVar` | Get the RHS variable of the load statement |\n", "| | `getRHSVarID` | Get the ID of the RHS variable of the load statement |\n", - "| `CallPE` | `getCallSite` | Get the call site |\n", - "| | `getLHSVar` | Get the LHS variable of the call PE |\n", - "| | `getLHSVarID` | Get the ID of the LHS variable of the call PE |\n", - "| | `getRHSVar` | Get the RHS variable of the call PE |\n", - "| | `getRHSVarID` | Get the ID of the RHS variable of the call PE |\n", - "| | `getFunEntryICFGNode` | Get the function entry ICFG node |\n", + "| `CallPE` | `getFunEntryICFGNode` | Get the function entry ICFG node |\n", + "| (MultiOpndStmt) | `getOpCallICFGNode(idx)` | Get the CallICFGNode of the i-th operand |\n", + "| | `getOpCallICFGNodes` | Get all call site ICFGNodes |\n", + "| | `getRes` | Get the result variable (formal parameter) |\n", + "| | `getOpVar(idx)` | Get the i-th operand variable (actual parameter) |\n", + "| | `getOpVarNum` | Get the number of operands |\n", "| `RetPE` | `getCallSite` | Get the call site |\n", "| | `getLHSVar` | Get the LHS variable of the return PE |\n", "| | `getLHSVarID` | Get the ID of the LHS variable of the return PE |\n", @@ -809,12 +809,12 @@ "| | `getLHSVarID` | Get the ID of the LHS variable of the load statement |\n", "| | `getRHSVar` | Get the RHS variable of the load statement |\n", "| | `getRHSVarID` | Get the ID of the RHS variable of the load statement |\n", - "| `CallPE` | `getCallSite` | Get the call site |\n", - "| | `getLHSVar` | Get the LHS variable of the call PE |\n", - "| | `getLHSVarID` | Get the ID of the LHS variable of the call PE |\n", - "| | `getRHSVar` | Get the RHS variable of the call PE |\n", - "| | `getRHSVarID` | Get the ID of the RHS variable of the call PE |\n", - "| | `getFunEntryICFGNode` | Get the function entry ICFG node |\n", + "| `CallPE` | `getFunEntryICFGNode` | Get the function entry ICFG node |\n", + "| (MultiOpndStmt) | `getOpCallICFGNode(idx)` | Get the CallICFGNode of the i-th operand |\n", + "| | `getOpCallICFGNodes` | Get all call site ICFGNodes |\n", + "| | `getRes` | Get the result variable (formal parameter) |\n", + "| | `getOpVar(idx)` | Get the i-th operand variable (actual parameter) |\n", + "| | `getOpVarNum` | Get the number of operands |\n", "| `RetPE` | `getCallSite` | Get the call site |\n", "| | `getLHSVar` | Get the LHS variable of the return PE |\n", "| | `getLHSVarID` | Get the ID of the LHS variable of the return PE |\n", @@ -980,12 +980,12 @@ "| | `getLHSVarID` | Get the ID of the LHS variable of the load statement |\n", "| | `getRHSVar` | Get the RHS variable of the load statement |\n", "| | `getRHSVarID` | Get the ID of the RHS variable of the load statement |\n", - "| `CallPE` | `getCallSite` | Get the call site |\n", - "| | `getLHSVar` | Get the LHS variable of the call PE |\n", - "| | `getLHSVarID` | Get the ID of the LHS variable of the call PE |\n", - "| | `getRHSVar` | Get the RHS variable of the call PE |\n", - "| | `getRHSVarID` | Get the ID of the RHS variable of the call PE |\n", - "| | `getFunEntryICFGNode` | Get the function entry ICFG node |\n", + "| `CallPE` | `getFunEntryICFGNode` | Get the function entry ICFG node |\n", + "| (MultiOpndStmt) | `getOpCallICFGNode(idx)` | Get the CallICFGNode of the i-th operand |\n", + "| | `getOpCallICFGNodes` | Get all call site ICFGNodes |\n", + "| | `getRes` | Get the result variable (formal parameter) |\n", + "| | `getOpVar(idx)` | Get the i-th operand variable (actual parameter) |\n", + "| | `getOpVarNum` | Get the number of operands |\n", "| `RetPE` | `getCallSite` | Get the call site |\n", "| | `getLHSVar` | Get the LHS variable of the return PE |\n", "| | `getLHSVarID` | Get the ID of the LHS variable of the return PE |\n", @@ -1044,213 +1044,7 @@ }, "collapsed": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CopyStmt: lhs_var=DummyValVar ID: 1, rhs_var=ConstNullPtrValVar ID: 0\n", - " ptr null { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 5\n", - " i8 37 { constant data }, rhs_var=ConstIntObjVar ID: 6\n", - " i8 37 { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 7\n", - " i8 100 { constant data }, rhs_var=ConstIntObjVar ID: 8\n", - " i8 100 { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 9\n", - " i8 10 { constant data }, rhs_var=ConstIntObjVar ID: 10\n", - " i8 10 { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 11\n", - " i8 0 { constant data }, rhs_var=ConstIntObjVar ID: 12\n", - " i8 0 { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 48\n", - " i32 3 { constant data }, rhs_var=ConstIntObjVar ID: 49\n", - " i32 3 { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 45\n", - " i64 1 { constant data }, rhs_var=ConstIntObjVar ID: 46\n", - " i64 1 { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 42\n", - " i32 5 { constant data }, rhs_var=ConstIntObjVar ID: 43\n", - " i32 5 { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 39\n", - " i64 0 { constant data }, rhs_var=ConstIntObjVar ID: 40\n", - " i64 0 { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 55\n", - " i32 1 { constant data }, rhs_var=ConstIntObjVar ID: 56\n", - " i32 1 { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 21\n", - " i32 0 { constant data }, rhs_var=ConstIntObjVar ID: 22\n", - " i32 0 { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 60\n", - " i1 false { constant data }, rhs_var=ConstIntObjVar ID: 61\n", - " i1 false { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 36\n", - " i64 8 { constant data }, rhs_var=ConstIntObjVar ID: 37\n", - " i64 8 { constant data }\n", - "AddrStmt: lhs_var=ConstIntValVar ID: 62\n", - " i1 true { constant data }, rhs_var=ConstIntObjVar ID: 63\n", - " i1 true { constant data }\n", - "AddrStmt: lhs_var=GlobalValVar ID: 4\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=GlobalObjVar ID: 13\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }\n", - "GepStmt: lhs_var=GepValVar ID: 86 with offset_0\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=GlobalValVar ID: 4\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }\n", - "StoreStmt: lhs_var=GepValVar ID: 86 with offset_0\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=ConstIntValVar ID: 5\n", - " i8 37 { constant data }\n", - "GepStmt: lhs_var=GepValVar ID: 87 with offset_1\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=GlobalValVar ID: 4\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }\n", - "StoreStmt: lhs_var=GepValVar ID: 87 with offset_1\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=ConstIntValVar ID: 7\n", - " i8 100 { constant data }\n", - "GepStmt: lhs_var=GepValVar ID: 88 with offset_2\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=GlobalValVar ID: 4\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }\n", - "StoreStmt: lhs_var=GepValVar ID: 88 with offset_2\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=ConstIntValVar ID: 9\n", - " i8 10 { constant data }\n", - "GepStmt: lhs_var=GepValVar ID: 89 with offset_3\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=GlobalValVar ID: 4\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }\n", - "StoreStmt: lhs_var=GepValVar ID: 89 with offset_3\n", - " @.str = private unnamed_addr constant [4 x i8] c\"%d\\0A\\00\", align 1 { Glob }, rhs_var=ConstIntValVar ID: 11\n", - " i8 0 { constant data }\n", - "AddrStmt: lhs_var=FunValVar ID: 14\n", - "add_or_sub, rhs_var=FunObjVar ID: 15 (base object)\n", - "add_or_sub\n", - "AddrStmt: lhs_var=FunValVar ID: 31\n", - "main, rhs_var=FunObjVar ID: 32 (base object)\n", - "main\n", - "AddrStmt: lhs_var=FunValVar ID: 67\n", - "__memcpy_chk, rhs_var=FunObjVar ID: 68 (base object)\n", - "__memcpy_chk\n", - "AddrStmt: lhs_var=FunValVar ID: 64\n", - "llvm.objectsize.i64.p0, rhs_var=FunObjVar ID: 65 (base object)\n", - "llvm.objectsize.i64.p0\n", - "AddrStmt: lhs_var=FunValVar ID: 70\n", - "printf, rhs_var=FunObjVar ID: 71 (base object)\n", - "printf\n", - "PhiStmt: res_var=RetValPN ID: 16 unique return node for function add_or_sub, op_var_num=1\n", - "PhiStmt: res_var=RetValPN ID: 33 unique return node for function main, op_var_num=1\n", - "CmpStmt: predicate=33, res=ValVar ID: 20\n", - " %tobool = icmp ne i32 %flag, 0 , op_var0=ArgValVar ID: 19\n", - " i32 %flag { 2nd arg add_or_sub }, op_var1=ConstIntValVar ID: 21\n", - " i32 0 { constant data }\n", - "BranchStmt: successors=[(, 1), (, 0)], condition=ValVar ID: 20\n", - " %tobool = icmp ne i32 %flag, 0 \n", - "BinaryOPStmt: opcode=13, res=ValVar ID: 24\n", - " %add = add nsw i32 %a, %b , op_var_0=ArgValVar ID: 17\n", - " i32 %a { 0th arg add_or_sub }, op_var_1=ArgValVar ID: 18\n", - " i32 %b { 1st arg add_or_sub }\n", - "BinaryOPStmt: opcode=15, res=ValVar ID: 27\n", - " %sub = sub nsw i32 %a, %b , op_var_0=ArgValVar ID: 17\n", - " i32 %a { 0th arg add_or_sub }, op_var_1=ArgValVar ID: 18\n", - " i32 %b { 1st arg add_or_sub }\n", - "BranchStmt: successors=[(, 1)], condition=ConstNullPtrValVar ID: 0\n", - " ptr null { constant data }\n", - "BranchStmt: successors=[(, 1)], condition=ConstNullPtrValVar ID: 0\n", - " ptr null { constant data }\n", - "PhiStmt: res_var=ValVar ID: 29\n", - " %result.0 = phi i32 [ %add, %if.then ], [ %sub, %if.else ] , op_var_num=2\n", - "AddrStmt: lhs_var=ValVar ID: 34\n", - " %0 = alloca i8, i64 8, align 8 , rhs_var=StackObjVar ID: 35\n", - " %0 = alloca i8, i64 8, align 8 \n", - "GepStmt: lhs_var=ValVar ID: 38\n", - " %arrayidx = getelementptr inbounds i32, ptr %0, i64 0 , rhs_var=ValVar ID: 34\n", - " %0 = alloca i8, i64 8, align 8 \n", - "StoreStmt: lhs_var=ValVar ID: 38\n", - " %arrayidx = getelementptr inbounds i32, ptr %0, i64 0 , rhs_var=ConstIntValVar ID: 42\n", - " i32 5 { constant data }\n", - "GepStmt: lhs_var=ValVar ID: 44\n", - " %arrayidx1 = getelementptr inbounds i32, ptr %0, i64 1 , rhs_var=ValVar ID: 34\n", - " %0 = alloca i8, i64 8, align 8 \n", - "StoreStmt: lhs_var=ValVar ID: 44\n", - " %arrayidx1 = getelementptr inbounds i32, ptr %0, i64 1 , rhs_var=ConstIntValVar ID: 48\n", - " i32 3 { constant data }\n", - "GepStmt: lhs_var=ValVar ID: 50\n", - " %arrayidx2 = getelementptr inbounds i32, ptr %0, i64 0 , rhs_var=ValVar ID: 34\n", - " %0 = alloca i8, i64 8, align 8 \n", - "LoadStmt: lhs_var=ValVar ID: 51\n", - " %1 = load i32, ptr %arrayidx2, align 4 , rhs_var=ValVar ID: 50\n", - " %arrayidx2 = getelementptr inbounds i32, ptr %0, i64 0 \n", - "GepStmt: lhs_var=ValVar ID: 52\n", - " %arrayidx3 = getelementptr inbounds i32, ptr %0, i64 1 , rhs_var=ValVar ID: 34\n", - " %0 = alloca i8, i64 8, align 8 \n", - "LoadStmt: lhs_var=ValVar ID: 53\n", - " %2 = load i32, ptr %arrayidx3, align 4 , rhs_var=ValVar ID: 52\n", - " %arrayidx3 = getelementptr inbounds i32, ptr %0, i64 1 \n", - "CallPE: callsite=CallICFGNode22 {fun: main}\n", - "CallPE: [Var17 <-- Var51]\t\n", - "ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n", - "CallPE: [Var18 <-- Var53]\t\n", - "ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n", - "CallPE: [Var19 <-- Var55]\t\n", - "ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n", - ", lhs_var=ArgValVar ID: 17\n", - " i32 %a { 0th arg add_or_sub }, rhs_var=ValVar ID: 51\n", - " %1 = load i32, ptr %arrayidx2, align 4 \n", - "CallPE: callsite=CallICFGNode22 {fun: main}\n", - "CallPE: [Var17 <-- Var51]\t\n", - "ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n", - "CallPE: [Var18 <-- Var53]\t\n", - "ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n", - "CallPE: [Var19 <-- Var55]\t\n", - "ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n", - ", lhs_var=ArgValVar ID: 18\n", - " i32 %b { 1st arg add_or_sub }, rhs_var=ValVar ID: 53\n", - " %2 = load i32, ptr %arrayidx3, align 4 \n", - "CallPE: callsite=CallICFGNode22 {fun: main}\n", - "CallPE: [Var17 <-- Var51]\t\n", - "ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n", - "CallPE: [Var18 <-- Var53]\t\n", - "ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n", - "CallPE: [Var19 <-- Var55]\t\n", - "ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n", - ", lhs_var=ArgValVar ID: 19\n", - " i32 %flag { 2nd arg add_or_sub }, rhs_var=ConstIntValVar ID: 55\n", - " i32 1 { constant data }\n", - "RetPE: callsite=CallICFGNode22 {fun: main}\n", - "CallPE: [Var17 <-- Var51]\t\n", - "ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n", - "CallPE: [Var18 <-- Var53]\t\n", - "ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n", - "CallPE: [Var19 <-- Var55]\t\n", - "ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) \n", - ", lhs_var=ValVar ID: 54\n", - " %call = call i32 @add_or_sub(i32 noundef %1, i32 noundef %2, i32 noundef 1) , rhs_var=RetValPN ID: 16 unique return node for function add_or_sub\n", - "AddrStmt: lhs_var=ValVar ID: 57\n", - " %3 = alloca i8, i64 8, align 8 , rhs_var=StackObjVar ID: 58\n", - " %3 = alloca i8, i64 8, align 8 \n", - "GepStmt: lhs_var=GepValVar ID: 90 with offset_0\n", - " %3 = alloca i8, i64 8, align 8 , rhs_var=ValVar ID: 57\n", - " %3 = alloca i8, i64 8, align 8 \n", - "GepStmt: lhs_var=GepValVar ID: 91 with offset_0\n", - " %0 = alloca i8, i64 8, align 8 , rhs_var=ValVar ID: 34\n", - " %0 = alloca i8, i64 8, align 8 \n", - "LoadStmt: lhs_var=DummyValVar ID: 92, rhs_var=GepValVar ID: 91 with offset_0\n", - " %0 = alloca i8, i64 8, align 8 \n", - "StoreStmt: lhs_var=GepValVar ID: 90 with offset_0\n", - " %3 = alloca i8, i64 8, align 8 , rhs_var=DummyValVar ID: 92\n", - "CopyStmt: lhs_var=ValVar ID: 66\n", - " %call4 = call ptr @__memcpy_chk(ptr noundef %3, ptr noundef %0, i64 noundef 8, i64 noundef %4) #4 , rhs_var=ValVar ID: 57\n", - " %3 = alloca i8, i64 8, align 8 \n" - ] - } - ], + "outputs": [], "source": [ "for node in cfg.getNodes():\n", " for stmt in node.getSVFStmts():\n", @@ -1274,7 +1068,7 @@ " print(\"StoreStmt: lhs_var={}, rhs_var={}\".format(store_stmt.getLHSVar(), store_stmt.getRHSVar()))\n", " elif isinstance(stmt, pysvf.CallPE):\n", " call_pe = stmt.asCallPE()\n", - " print(\"CallPE: callsite={}, lhs_var={}, rhs_var={}\".format(call_pe.getCallSite(), call_pe.getLHSVar(), call_pe.getRHSVar()))\n", + " print(\"CallPE: entry={}, res={}, num_opnds={}\".format(call_pe.getFunEntryICFGNode(), call_pe.getRes(), call_pe.getOpVarNum()))\n", " elif isinstance(stmt, pysvf.RetPE):\n", " ret_pe = stmt.asRetPE()\n", " print(\"RetPE: callsite={}, lhs_var={}, rhs_var={}\".format(ret_pe.getCallSite(), ret_pe.getLHSVar(), ret_pe.getRHSVar()))\n", diff --git a/demo/pag.ipynb b/demo/pag.ipynb index 8077696..fddf2a8 100644 --- a/demo/pag.ipynb +++ b/demo/pag.ipynb @@ -36,7 +36,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-03-28T11:45:40.163290Z", @@ -44,21 +44,8 @@ }, "collapsed": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Looking in indexes: https://test.pypi.org/simple/\r\n", - "Requirement already satisfied: pysvf in /Users/z5489735/PycharmProjects/Amei/.venv/lib/python3.9/site-packages (0.0.0)\r\n" - ] - } - ], - "source": [ - "# bash install pip install pysvf from testpypi\n", - "\n", - "!pip install pysvf --index-url https://test.pypi.org/simple/" - ] + "outputs": [], + "source": "# Install pysvf from PyPI\n\n!pip install pysvf" }, { "cell_type": "code", @@ -656,4 +643,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/pybind/SVFIR.cpp b/pybind/SVFIR.cpp index 6ef2b46..84bf9af 100644 --- a/pybind/SVFIR.cpp +++ b/pybind/SVFIR.cpp @@ -120,11 +120,6 @@ void bind_svf_stmt(py::module& m) { py::class_(m, "LoadStmt"); - py::class_(m, "CallPE") - .def("getCallSite", &CallPE::getCallSite, "Get the call site") - .def("getFunEntryICFGNode", &CallPE::getFunEntryICFGNode, py::return_value_policy::reference, - "Get the function entry ICFG node"); - py::class_(m, "RetPE") .def("getCallSite", &RetPE::getCallSite, "Get the call site") .def("getFunExitICFGNode", &RetPE::getFunExitICFGNode, py::return_value_policy::reference, @@ -155,6 +150,14 @@ void bind_svf_stmt(py::module& m) { return py::make_iterator(stmt.opVarBegin(), stmt.opVerEnd()); }, py::keep_alive<0, 1>()); // Keep the iterator alive while iterating + py::class_(m, "CallPE") + .def("getOpCallICFGNode", &CallPE::getOpCallICFGNode, py::return_value_policy::reference, + "Get the CallICFGNode of the i-th operand") + .def("getOpCallICFGNodes", &CallPE::getOpCallICFGNodes, py::return_value_policy::reference, + "Get all call site ICFGNodes") + .def("getFunEntryICFGNode", &CallPE::getFunEntryICFGNode, py::return_value_policy::reference, + "Get the function entry ICFG node"); + py::class_(m, "PhiStmt") // TODO: may implement get_op_var and get_op_var_id .def("getOpICFGNode", [](PhiStmt& stmt, int idx) { return stmt.getOpICFGNode(idx); }, diff --git a/pysvf/pysvf.pyi b/pysvf/pysvf.pyi index a1447ad..bd0191a 100644 --- a/pysvf/pysvf.pyi +++ b/pysvf/pysvf.pyi @@ -486,12 +486,15 @@ class StoreStmt(AssignStmt): class LoadStmt(AssignStmt): ... -class CallPE(AssignStmt): +class CallPE(MultiOpndStmt): def __init__(self, *args, **kwargs) -> None: ... """Not intended for direct instantiation.""" - - def getCallSite(self) -> "CallICFGNode": ... - """Get the call site""" + + def getOpCallICFGNode(self, op_idx: int) -> "CallICFGNode": ... + """Get the CallICFGNode of the i-th operand""" + + def getOpCallICFGNodes(self) -> List["CallICFGNode"]: ... + """Get all call site ICFGNodes""" def getFunEntryICFGNode(self) -> "FunEntryICFGNode": ... """Get the function entry ICFG node"""