├── A1 ├── IterativeSolver.java ├── LiveVariableAnalysis.java ├── Solver.java └── submission.zip ├── A2 ├── ConstantPropagation.java ├── Solver.java └── WorkListSolver.java ├── A3 └── DeadCodeDetection.java ├── A4 ├── CHABuilder.java ├── InterConstantPropagation.java └── InterSolver.java ├── A5 └── Solver.java ├── A6 ├── Solver.java ├── _1CallSelector.java ├── _1ObjSelector.java ├── _1TypeSelector.java ├── _2CallSelector.java ├── _2ObjSelector.java └── _2TypeSelector.java ├── A7 ├── ConstantPropagation.java ├── InterConstantPropagation.java └── InterSolver.java ├── A8 ├── Solver.java └── TaintAnalysiss.java └── README.md /A1/IterativeSolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.dataflow.solver; 24 | 25 | import pascal.taie.analysis.dataflow.analysis.DataflowAnalysis; 26 | import pascal.taie.analysis.dataflow.fact.DataflowResult; 27 | import pascal.taie.analysis.dataflow.fact.SetFact; 28 | import pascal.taie.analysis.graph.cfg.CFG; 29 | import pascal.taie.ir.exp.Var; 30 | 31 | class IterativeSolver extends Solver { 32 | 33 | public IterativeSolver(DataflowAnalysis analysis) { 34 | super(analysis); 35 | } 36 | 37 | @Override 38 | protected void doSolveForward(CFG cfg, DataflowResult result) { 39 | throw new UnsupportedOperationException(); 40 | } 41 | 42 | @Override 43 | @SuppressWarnings("unchecked") 44 | protected void doSolveBackward(CFG cfg, DataflowResult result) { 45 | boolean go = true; 46 | while(go) { 47 | go = false; 48 | for (Node node : cfg) { 49 | SetFact out = new SetFact<>(); 50 | SetFact in = (SetFact) result.getInFact(node); 51 | for (Node succ : cfg.getSuccsOf(node)) { 52 | out.union((SetFact) result.getInFact(succ)); 53 | } 54 | if (analysis.transferNode(node, (Fact) out, (Fact) in)){ 55 | go = true; 56 | } 57 | result.setInFact(node, (Fact) in); 58 | result.setOutFact(node, (Fact) out); 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /A1/LiveVariableAnalysis.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.dataflow.analysis; 24 | 25 | import pascal.taie.analysis.dataflow.fact.SetFact; 26 | import pascal.taie.analysis.graph.cfg.CFG; 27 | import pascal.taie.config.AnalysisConfig; 28 | import pascal.taie.ir.exp.Exp; 29 | import pascal.taie.ir.exp.Var; 30 | import pascal.taie.ir.stmt.Stmt; 31 | 32 | /** 33 | * Implementation of classic live variable analysis. 34 | */ 35 | public class LiveVariableAnalysis extends 36 | AbstractDataflowAnalysis> { 37 | 38 | public static final String ID = "livevar"; 39 | 40 | public LiveVariableAnalysis(AnalysisConfig config) { 41 | super(config); 42 | } 43 | 44 | @Override 45 | public boolean isForward() { 46 | return false; 47 | } 48 | 49 | @Override 50 | public SetFact newBoundaryFact(CFG cfg) { 51 | return new SetFact<>(); 52 | } 53 | 54 | @Override 55 | public SetFact newInitialFact() { 56 | return new SetFact<>(); 57 | } 58 | 59 | @Override 60 | public void meetInto(SetFact fact, SetFact target) { 61 | target.union(fact); 62 | } 63 | 64 | @Override 65 | public boolean transferNode(Stmt stmt, SetFact out, SetFact in) { 66 | SetFact oldIn = in.copy(); 67 | in.union(out); 68 | stmt.getDef().ifPresent(lValue -> { 69 | if(lValue instanceof Var){ 70 | in.remove((Var)lValue); 71 | } 72 | }); 73 | for(Exp exp : stmt.getUses()){ 74 | if(exp instanceof Var){ 75 | in.add((Var)exp); 76 | } 77 | } 78 | return !in.equals(oldIn); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /A1/Solver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.dataflow.solver; 24 | 25 | import pascal.taie.analysis.dataflow.analysis.DataflowAnalysis; 26 | import pascal.taie.analysis.dataflow.fact.DataflowResult; 27 | import pascal.taie.analysis.graph.cfg.CFG; 28 | 29 | /** 30 | * Base class for data-flow analysis solver, which provides common 31 | * functionalities for different solver implementations. 32 | * 33 | * @param type of CFG nodes 34 | * @param type of data-flow facts 35 | */ 36 | public abstract class Solver { 37 | 38 | protected final DataflowAnalysis analysis; 39 | 40 | protected Solver(DataflowAnalysis analysis) { 41 | this.analysis = analysis; 42 | } 43 | 44 | /** 45 | * Static factory method to create a new solver for given analysis. 46 | */ 47 | public static Solver makeSolver( 48 | DataflowAnalysis analysis) { 49 | return new IterativeSolver<>(analysis); 50 | } 51 | 52 | /** 53 | * Starts this solver on the given CFG. 54 | * 55 | * @param cfg control-flow graph where the analysis is performed on 56 | * @return the analysis result 57 | */ 58 | public DataflowResult solve(CFG cfg) { 59 | DataflowResult result = initialize(cfg); 60 | doSolve(cfg, result); 61 | return result; 62 | } 63 | 64 | /** 65 | * Creates and initializes a new data-flow result for given CFG. 66 | * 67 | * @return the initialized data-flow result 68 | */ 69 | private DataflowResult initialize(CFG cfg) { 70 | DataflowResult result = new DataflowResult<>(); 71 | if (analysis.isForward()) { 72 | initializeForward(cfg, result); 73 | } else { 74 | initializeBackward(cfg, result); 75 | } 76 | return result; 77 | } 78 | 79 | protected void initializeForward(CFG cfg, DataflowResult result) { 80 | throw new UnsupportedOperationException(); 81 | } 82 | 83 | protected void initializeBackward(CFG cfg, DataflowResult result) { 84 | result.setInFact(cfg.getExit(), analysis.newBoundaryFact(cfg)); 85 | for(Node node : cfg){ 86 | if(node != cfg.getExit()){ 87 | result.setInFact(node, analysis.newInitialFact()); 88 | } 89 | } 90 | } 91 | 92 | /** 93 | * Solves the data-flow problem for given CFG. 94 | */ 95 | private void doSolve(CFG cfg, DataflowResult result) { 96 | if (analysis.isForward()) { 97 | doSolveForward(cfg, result); 98 | } else { 99 | doSolveBackward(cfg, result); 100 | } 101 | } 102 | 103 | protected abstract void doSolveForward(CFG cfg, DataflowResult result); 104 | 105 | protected abstract void doSolveBackward(CFG cfg, DataflowResult result); 106 | } 107 | -------------------------------------------------------------------------------- /A1/submission.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluesadi/Tai-e-solutions/3131d51050e1911313fc52b35baab8c8160989ac/A1/submission.zip -------------------------------------------------------------------------------- /A2/ConstantPropagation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.dataflow.analysis.constprop; 24 | 25 | import pascal.taie.analysis.dataflow.analysis.AbstractDataflowAnalysis; 26 | import pascal.taie.analysis.graph.cfg.CFG; 27 | import pascal.taie.config.AnalysisConfig; 28 | import pascal.taie.ir.exp.*; 29 | import pascal.taie.ir.stmt.DefinitionStmt; 30 | import pascal.taie.ir.stmt.Stmt; 31 | import pascal.taie.language.type.PrimitiveType; 32 | import pascal.taie.language.type.Type; 33 | 34 | import java.util.concurrent.atomic.AtomicBoolean; 35 | 36 | public class ConstantPropagation extends 37 | AbstractDataflowAnalysis { 38 | 39 | public static final String ID = "constprop"; 40 | 41 | public ConstantPropagation(AnalysisConfig config) { 42 | super(config); 43 | } 44 | 45 | @Override 46 | public boolean isForward() { 47 | return true; 48 | } 49 | 50 | @Override 51 | public CPFact newBoundaryFact(CFG cfg) { 52 | CPFact fact = new CPFact(); 53 | cfg.getIR().getParams().forEach(var -> { 54 | if(canHoldInt(var)) { 55 | fact.update(var, Value.getNAC()); 56 | } 57 | }); 58 | return fact; 59 | } 60 | 61 | @Override 62 | public CPFact newInitialFact() { 63 | return new CPFact(); 64 | } 65 | 66 | @Override 67 | public void meetInto(CPFact fact, CPFact target) { 68 | fact.forEach(((var, value) -> { 69 | target.update(var, meetValue(value, target.get(var))); 70 | })); 71 | } 72 | 73 | /** 74 | * Meets two Values. 75 | */ 76 | public Value meetValue(Value v1, Value v2) { 77 | if(v1.isConstant() && v2.isConstant()){ 78 | if(v1.equals(v2)){ 79 | return Value.makeConstant(v1.getConstant()); 80 | }else{ 81 | return Value.getNAC(); 82 | } 83 | }else if(v1.isNAC() || v2.isNAC()){ 84 | return Value.getNAC(); 85 | }else if(v1.isConstant() && v2.isUndef()){ 86 | return Value.makeConstant(v1.getConstant()); 87 | }else if(v2.isConstant() && v1.isUndef()){ 88 | return Value.makeConstant(v2.getConstant()); 89 | } 90 | return Value.getUndef(); 91 | } 92 | 93 | @Override 94 | public boolean transferNode(Stmt stmt, CPFact in, CPFact out) { 95 | AtomicBoolean changed = new AtomicBoolean(false); 96 | in.forEach(((var, value) -> { 97 | if(out.update(var, value)){ 98 | changed.set(true); 99 | } 100 | })); 101 | if(stmt instanceof DefinitionStmt s){ 102 | if(s.getLValue() instanceof Var var && canHoldInt(var)) { 103 | CPFact inCopy = in.copy(); 104 | Value removedVal = inCopy.get(var); 105 | inCopy.remove(var); 106 | Value newVal = evaluate(s.getRValue(), in); 107 | out.update(var, newVal); 108 | return !removedVal.equals(newVal) || changed.get(); 109 | } 110 | } 111 | return changed.get(); 112 | } 113 | 114 | /** 115 | * @return true if the given variable can hold integer value, otherwise false. 116 | */ 117 | public static boolean canHoldInt(Var var) { 118 | Type type = var.getType(); 119 | if (type instanceof PrimitiveType) { 120 | switch ((PrimitiveType) type) { 121 | case BYTE: 122 | case SHORT: 123 | case INT: 124 | case CHAR: 125 | case BOOLEAN: 126 | return true; 127 | } 128 | } 129 | return false; 130 | } 131 | 132 | /** 133 | * Evaluates the {@link Value} of given expression. 134 | * 135 | * @param exp the expression to be evaluated 136 | * @param in IN fact of the statement 137 | * @return the resulting {@link Value} 138 | */ 139 | public static Value evaluate(Exp exp, CPFact in) { 140 | if(exp instanceof IntLiteral e){ 141 | return Value.makeConstant(e.getValue()); 142 | }else if(exp instanceof Var var){ 143 | if(in.get(var).isConstant()){ 144 | return Value.makeConstant(in.get(var).getConstant()); 145 | } 146 | return in.get(var); 147 | }else if(exp instanceof BinaryExp b){ 148 | Value v1 = evaluate(b.getOperand1(), in); 149 | Value v2 = evaluate(b.getOperand2(), in); 150 | if(v2.isConstant() && v2.getConstant() == 0 151 | && b.getOperator() instanceof ArithmeticExp.Op op){ 152 | if(op == ArithmeticExp.Op.DIV || op == ArithmeticExp.Op.REM){ 153 | return Value.getUndef(); 154 | } 155 | } 156 | if(v1.isConstant() && v2.isConstant()){ 157 | int c1 = v1.getConstant(), c2 = v2.getConstant(); 158 | if(b.getOperator() instanceof ArithmeticExp.Op op){ 159 | switch (op){ 160 | case ADD -> { 161 | return Value.makeConstant(c1 + c2); 162 | } 163 | case SUB -> { 164 | return Value.makeConstant(c1 - c2); 165 | } 166 | case MUL -> { 167 | return Value.makeConstant(c1 * c2); 168 | } 169 | case DIV -> { 170 | return Value.makeConstant(c1 / c2); 171 | } 172 | case REM -> { 173 | return Value.makeConstant(c1 % c2); 174 | } 175 | } 176 | }else if(b.getOperator() instanceof ShiftExp.Op op){ 177 | switch (op){ 178 | case SHL -> { 179 | return Value.makeConstant(c1 << c2); 180 | } 181 | case SHR -> { 182 | return Value.makeConstant(c1 >> c2); 183 | } 184 | case USHR -> { 185 | return Value.makeConstant(c1 >>> c2); 186 | } 187 | } 188 | }else if(b.getOperator() instanceof BitwiseExp.Op op){ 189 | switch (op){ 190 | case OR -> { 191 | return Value.makeConstant(c1 | c2); 192 | } 193 | case AND -> { 194 | return Value.makeConstant(c1 & c2); 195 | } 196 | case XOR -> { 197 | return Value.makeConstant(c1 ^ c2); 198 | } 199 | } 200 | }else if(b.getOperator() instanceof ConditionExp.Op op){ 201 | switch (op){ 202 | case EQ -> { 203 | return Value.makeConstant(c1 == c2 ? 1 : 0); 204 | } 205 | case NE -> { 206 | return Value.makeConstant(c1 != c2 ? 1 : 0); 207 | } 208 | case LT -> { 209 | return Value.makeConstant(c1 < c2 ? 1 : 0); 210 | } 211 | case GT -> { 212 | return Value.makeConstant(c1 > c2 ? 1 : 0); 213 | } 214 | case LE -> { 215 | return Value.makeConstant(c1 <= c2 ? 1 : 0); 216 | } 217 | case GE -> { 218 | return Value.makeConstant(c1 >= c2 ? 1 : 0); 219 | } 220 | } 221 | } 222 | }else if(v1.isNAC() || v2.isNAC()){ 223 | return Value.getNAC(); 224 | } 225 | return Value.getUndef(); 226 | } 227 | return Value.getNAC(); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /A2/Solver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.dataflow.solver; 24 | 25 | import pascal.taie.analysis.dataflow.analysis.DataflowAnalysis; 26 | import pascal.taie.analysis.dataflow.fact.DataflowResult; 27 | import pascal.taie.analysis.graph.cfg.CFG; 28 | 29 | /** 30 | * Base class for data-flow analysis solver, which provides common 31 | * functionalities for different solver implementations. 32 | * 33 | * @param type of CFG nodes 34 | * @param type of data-flow facts 35 | */ 36 | public abstract class Solver { 37 | 38 | protected final DataflowAnalysis analysis; 39 | 40 | protected Solver(DataflowAnalysis analysis) { 41 | this.analysis = analysis; 42 | } 43 | 44 | /** 45 | * Static factory method to create a new solver for given analysis. 46 | */ 47 | public static Solver makeSolver( 48 | DataflowAnalysis analysis) { 49 | return new WorkListSolver<>(analysis); 50 | } 51 | 52 | /** 53 | * Starts this solver on the given CFG. 54 | * 55 | * @param cfg control-flow graph where the analysis is performed on 56 | * @return the analysis result 57 | */ 58 | public DataflowResult solve(CFG cfg) { 59 | DataflowResult result = initialize(cfg); 60 | doSolve(cfg, result); 61 | return result; 62 | } 63 | 64 | /** 65 | * Creates and initializes a new data-flow result for given CFG. 66 | * 67 | * @return the initialized data-flow result 68 | */ 69 | private DataflowResult initialize(CFG cfg) { 70 | DataflowResult result = new DataflowResult<>(); 71 | if (analysis.isForward()) { 72 | initializeForward(cfg, result); 73 | } else { 74 | initializeBackward(cfg, result); 75 | } 76 | return result; 77 | } 78 | 79 | protected void initializeForward(CFG cfg, DataflowResult result) { 80 | result.setOutFact(cfg.getEntry(), analysis.newBoundaryFact(cfg)); 81 | for(Node node : cfg){ 82 | if(node != cfg.getEntry()){ 83 | result.setOutFact(node, analysis.newInitialFact()); 84 | } 85 | } 86 | } 87 | 88 | protected void initializeBackward(CFG cfg, DataflowResult result) { 89 | throw new UnsupportedOperationException(); 90 | } 91 | 92 | /** 93 | * Solves the data-flow problem for given CFG. 94 | */ 95 | private void doSolve(CFG cfg, DataflowResult result) { 96 | if (analysis.isForward()) { 97 | doSolveForward(cfg, result); 98 | } else { 99 | doSolveBackward(cfg, result); 100 | } 101 | } 102 | 103 | protected abstract void doSolveForward(CFG cfg, DataflowResult result); 104 | 105 | protected abstract void doSolveBackward(CFG cfg, DataflowResult result); 106 | } 107 | -------------------------------------------------------------------------------- /A2/WorkListSolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.dataflow.solver; 24 | 25 | import pascal.taie.analysis.dataflow.analysis.DataflowAnalysis; 26 | import pascal.taie.analysis.dataflow.analysis.constprop.CPFact; 27 | import pascal.taie.analysis.dataflow.fact.DataflowResult; 28 | import pascal.taie.analysis.graph.cfg.CFG; 29 | import pascal.taie.ir.stmt.Stmt; 30 | 31 | import java.util.ArrayList; 32 | import java.util.LinkedList; 33 | import java.util.List; 34 | import java.util.Queue; 35 | import java.util.concurrent.LinkedBlockingQueue; 36 | 37 | class WorkListSolver extends Solver { 38 | 39 | WorkListSolver(DataflowAnalysis analysis) { 40 | super(analysis); 41 | } 42 | 43 | @Override 44 | @SuppressWarnings("unchecked") 45 | protected void doSolveForward(CFG cfg, DataflowResult result) { 46 | Queue workList = new LinkedList<>(cfg.getNodes()); 47 | while(!workList.isEmpty()){ 48 | Node node = workList.poll(); 49 | CPFact in = new CPFact(); 50 | CPFact out = (CPFact) result.getOutFact(node); 51 | for(Node pred : cfg.getPredsOf(node)){ 52 | analysis.meetInto(result.getOutFact(pred), (Fact) in); 53 | } 54 | if(analysis.transferNode(node, (Fact) in, (Fact) out)){ 55 | cfg.getSuccsOf(node).forEach(workList::offer); 56 | } 57 | result.setInFact(node, (Fact) in); 58 | result.setOutFact(node, (Fact) out); 59 | } 60 | } 61 | 62 | @Override 63 | protected void doSolveBackward(CFG cfg, DataflowResult result) { 64 | throw new UnsupportedOperationException(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /A3/DeadCodeDetection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.dataflow.analysis; 24 | 25 | import pascal.taie.analysis.MethodAnalysis; 26 | import pascal.taie.analysis.dataflow.analysis.constprop.CPFact; 27 | import pascal.taie.analysis.dataflow.analysis.constprop.ConstantPropagation; 28 | import pascal.taie.analysis.dataflow.analysis.constprop.Value; 29 | import pascal.taie.analysis.dataflow.fact.DataflowResult; 30 | import pascal.taie.analysis.dataflow.fact.SetFact; 31 | import pascal.taie.analysis.graph.cfg.CFG; 32 | import pascal.taie.analysis.graph.cfg.CFGBuilder; 33 | import pascal.taie.analysis.graph.cfg.Edge; 34 | import pascal.taie.config.AnalysisConfig; 35 | import pascal.taie.ir.IR; 36 | import pascal.taie.ir.exp.*; 37 | import pascal.taie.ir.stmt.*; 38 | import pascal.taie.util.collection.Pair; 39 | 40 | import java.util.*; 41 | 42 | public class DeadCodeDetection extends MethodAnalysis { 43 | 44 | public static final String ID = "deadcode"; 45 | 46 | public DeadCodeDetection(AnalysisConfig config) { 47 | super(config); 48 | } 49 | 50 | @Override 51 | public Set analyze(IR ir) { 52 | // obtain CFG 53 | CFG cfg = ir.getResult(CFGBuilder.ID); 54 | // obtain result of constant propagation 55 | DataflowResult constants = 56 | ir.getResult(ConstantPropagation.ID); 57 | // obtain result of live variable analysis 58 | DataflowResult> liveVars = 59 | ir.getResult(LiveVariableAnalysis.ID); 60 | // keep statements (dead code) sorted in the resulting set 61 | Set deadCode = new TreeSet<>(Comparator.comparing(Stmt::getIndex)); 62 | // Your task is to recognize dead code in ir and add it to deadCode 63 | Set liveCode = new TreeSet<>(Comparator.comparing(Stmt::getIndex)); 64 | Queue queue = new LinkedList<>(); 65 | queue.add(cfg.getEntry()); 66 | while(!queue.isEmpty()){ 67 | Stmt stmt = queue.poll(); 68 | if(stmt instanceof AssignStmt s && s.getLValue() instanceof Var var) { 69 | if(!liveVars.getResult(stmt).contains(var) && hasNoSideEffect(s.getRValue())) { 70 | queue.addAll(cfg.getSuccsOf(stmt)); 71 | continue; 72 | } 73 | } 74 | if(!liveCode.add(stmt)){ 75 | continue; 76 | } 77 | if(stmt instanceof If s){ 78 | Value cond = ConstantPropagation.evaluate(s.getCondition(), constants.getInFact(stmt)); 79 | if(cond.isConstant()){ 80 | for(Edge edge : cfg.getOutEdgesOf(stmt)) { 81 | if((cond.getConstant() == 1 && edge.getKind() == Edge.Kind.IF_TRUE) || 82 | (cond.getConstant() == 0 && edge.getKind() == Edge.Kind.IF_FALSE)) { 83 | queue.add(edge.getTarget()); 84 | } 85 | } 86 | }else{ 87 | queue.addAll(cfg.getSuccsOf(stmt)); 88 | } 89 | }else if(stmt instanceof SwitchStmt s){ 90 | Value val = ConstantPropagation.evaluate(s.getVar(), constants.getInFact(stmt)); 91 | if(val.isConstant()){ 92 | boolean hit = false; 93 | for(Pair pair : s.getCaseTargets()){ 94 | if(pair.first() == val.getConstant()){ 95 | hit = true; 96 | queue.add(pair.second()); 97 | } 98 | } 99 | if(!hit){ 100 | queue.add(s.getDefaultTarget()); 101 | } 102 | }else{ 103 | queue.addAll(cfg.getSuccsOf(stmt)); 104 | } 105 | }else{ 106 | queue.addAll(cfg.getSuccsOf(stmt)); 107 | } 108 | } 109 | deadCode.addAll(cfg.getNodes()); 110 | deadCode.removeAll(liveCode); 111 | deadCode.remove(cfg.getExit()); 112 | return deadCode; 113 | } 114 | 115 | /** 116 | * @return true if given RValue has no side effect, otherwise false. 117 | */ 118 | private static boolean hasNoSideEffect(RValue rvalue) { 119 | // new expression modifies the heap 120 | if (rvalue instanceof NewExp || 121 | // cast may trigger ClassCastException 122 | rvalue instanceof CastExp || 123 | // static field access may trigger class initialization 124 | // instance field access may trigger NPE 125 | rvalue instanceof FieldAccess || 126 | // array access may trigger NPE 127 | rvalue instanceof ArrayAccess) { 128 | return false; 129 | } 130 | if (rvalue instanceof ArithmeticExp) { 131 | ArithmeticExp.Op op = ((ArithmeticExp) rvalue).getOperator(); 132 | // may trigger DivideByZeroException 133 | return op != ArithmeticExp.Op.DIV && op != ArithmeticExp.Op.REM; 134 | } 135 | return true; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /A4/CHABuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.graph.callgraph; 24 | 25 | import pascal.taie.World; 26 | import pascal.taie.ir.proginfo.MethodRef; 27 | import pascal.taie.ir.stmt.Invoke; 28 | import pascal.taie.ir.stmt.Stmt; 29 | import pascal.taie.language.classes.ClassHierarchy; 30 | import pascal.taie.language.classes.JClass; 31 | import pascal.taie.language.classes.JMethod; 32 | import pascal.taie.language.classes.Subsignature; 33 | import pascal.taie.language.type.ClassType; 34 | import polyglot.ast.Call; 35 | 36 | import java.util.*; 37 | import java.util.stream.Stream; 38 | 39 | /** 40 | * Implementation of the CHA algorithm. 41 | */ 42 | class CHABuilder implements CGBuilder { 43 | 44 | private ClassHierarchy hierarchy; 45 | 46 | @Override 47 | public CallGraph build() { 48 | hierarchy = World.get().getClassHierarchy(); 49 | return buildCallGraph(World.get().getMainMethod()); 50 | } 51 | 52 | private CallGraph buildCallGraph(JMethod entry) { 53 | DefaultCallGraph callGraph = new DefaultCallGraph(); 54 | callGraph.addEntryMethod(entry); 55 | Queue workList = new LinkedList<>(); 56 | workList.add(entry); 57 | while (!workList.isEmpty()){ 58 | JMethod method = workList.poll(); 59 | if(callGraph.contains(method)){ 60 | continue; 61 | } 62 | callGraph.addReachableMethod(method); 63 | method.getIR().getStmts().stream(). 64 | filter(stmt -> stmt instanceof Invoke).forEach(stmt -> { 65 | Invoke callSite = (Invoke) stmt; 66 | CallKind kind = null; 67 | if(callSite.isInterface()) kind = CallKind.INTERFACE; 68 | else if(callSite.isSpecial()) kind = CallKind.SPECIAL; 69 | else if(callSite.isStatic()) kind = CallKind.STATIC; 70 | else if(callSite.isVirtual()) kind = CallKind.VIRTUAL; 71 | if(kind != null){ 72 | for(JMethod newMethod : resolve(callSite)){ 73 | callGraph.addEdge(new Edge<>(kind, callSite, newMethod)); 74 | workList.add(newMethod); 75 | } 76 | } 77 | }); 78 | } 79 | return callGraph; 80 | } 81 | 82 | /** 83 | * Resolves call targets (callees) of a call site via CHA. 84 | */ 85 | private Set resolve(Invoke callSite) { 86 | MethodRef methodRef = callSite.getMethodRef(); 87 | Set result = new HashSet<>(); 88 | if(callSite.isInterface() || callSite.isVirtual()){ 89 | JClass rootCls = methodRef.getDeclaringClass(); 90 | Queue queue = new LinkedList<>(); 91 | queue.add(rootCls); 92 | while(!queue.isEmpty()){ 93 | JClass cls = queue.poll(); 94 | JMethod dispatchedMethod = dispatch(cls, methodRef.getSubsignature()); 95 | if(dispatchedMethod != null){ 96 | result.add(dispatchedMethod); 97 | } 98 | if(cls.isInterface()){ 99 | queue.addAll(hierarchy.getDirectSubinterfacesOf(cls)); 100 | queue.addAll(hierarchy.getDirectImplementorsOf(cls)); 101 | }else{ 102 | queue.addAll(hierarchy.getDirectSubclassesOf(cls)); 103 | } 104 | } 105 | }else if(callSite.isSpecial()){ 106 | JMethod method = dispatch(methodRef.getDeclaringClass(), methodRef.getSubsignature()); 107 | if(method != null) { 108 | result.add(method); 109 | } 110 | }else if(callSite.isStatic()){ 111 | result.add(methodRef.getDeclaringClass().getDeclaredMethod(methodRef.getSubsignature())); 112 | } 113 | return result; 114 | } 115 | 116 | /** 117 | * Looks up the target method based on given class and method subsignature. 118 | * 119 | * @return the dispatched target method, or null if no satisfying method 120 | * can be found. 121 | */ 122 | private JMethod dispatch(JClass jclass, Subsignature subsignature) { 123 | JMethod method = jclass.getDeclaredMethod(subsignature); 124 | if(method != null && !method.isAbstract()){ 125 | return method; 126 | }else if(jclass.getSuperClass() == null){ 127 | return null; 128 | } 129 | return dispatch(jclass.getSuperClass(), subsignature); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /A4/InterConstantPropagation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.dataflow.inter; 24 | 25 | import jas.CP; 26 | import pascal.taie.analysis.dataflow.analysis.constprop.CPFact; 27 | import pascal.taie.analysis.dataflow.analysis.constprop.ConstantPropagation; 28 | import pascal.taie.analysis.dataflow.analysis.constprop.Value; 29 | import pascal.taie.analysis.graph.cfg.CFG; 30 | import pascal.taie.analysis.graph.cfg.CFGBuilder; 31 | import pascal.taie.analysis.graph.icfg.CallEdge; 32 | import pascal.taie.analysis.graph.icfg.CallToReturnEdge; 33 | import pascal.taie.analysis.graph.icfg.NormalEdge; 34 | import pascal.taie.analysis.graph.icfg.ReturnEdge; 35 | import pascal.taie.config.AnalysisConfig; 36 | import pascal.taie.ir.IR; 37 | import pascal.taie.ir.exp.InvokeExp; 38 | import pascal.taie.ir.exp.Var; 39 | import pascal.taie.ir.stmt.Invoke; 40 | import pascal.taie.ir.stmt.Stmt; 41 | import pascal.taie.language.classes.JMethod; 42 | 43 | import java.util.List; 44 | import java.util.concurrent.atomic.AtomicBoolean; 45 | 46 | /** 47 | * Implementation of interprocedural constant propagation for int values. 48 | */ 49 | public class InterConstantPropagation extends 50 | AbstractInterDataflowAnalysis { 51 | 52 | public static final String ID = "inter-constprop"; 53 | 54 | private final ConstantPropagation cp; 55 | 56 | public InterConstantPropagation(AnalysisConfig config) { 57 | super(config); 58 | cp = new ConstantPropagation(new AnalysisConfig(ConstantPropagation.ID)); 59 | } 60 | 61 | @Override 62 | public boolean isForward() { 63 | return cp.isForward(); 64 | } 65 | 66 | @Override 67 | public CPFact newBoundaryFact(Stmt boundary) { 68 | IR ir = icfg.getContainingMethodOf(boundary).getIR(); 69 | return cp.newBoundaryFact(ir.getResult(CFGBuilder.ID)); 70 | } 71 | 72 | @Override 73 | public CPFact newInitialFact() { 74 | return cp.newInitialFact(); 75 | } 76 | 77 | @Override 78 | public void meetInto(CPFact fact, CPFact target) { 79 | cp.meetInto(fact, target); 80 | } 81 | 82 | @Override 83 | protected boolean transferCallNode(Stmt stmt, CPFact in, CPFact out) { 84 | AtomicBoolean changed = new AtomicBoolean(false); 85 | in.forEach(((var, value) -> { 86 | if(out.update(var, value)){ 87 | changed.set(true); 88 | } 89 | })); 90 | return changed.get() ; 91 | } 92 | 93 | @Override 94 | protected boolean transferNonCallNode(Stmt stmt, CPFact in, CPFact out) { 95 | return cp.transferNode(stmt, in, out); 96 | } 97 | 98 | @Override 99 | protected CPFact transferNormalEdge(NormalEdge edge, CPFact out) { 100 | return out; 101 | } 102 | 103 | @Override 104 | protected CPFact transferCallToReturnEdge(CallToReturnEdge edge, CPFact out) { 105 | Invoke callSite = (Invoke) edge.getSource(); 106 | Var lVar = callSite.getLValue(); 107 | CPFact result = out.copy(); 108 | if(lVar != null){ 109 | result.remove(lVar); 110 | } 111 | return result; 112 | } 113 | 114 | @Override 115 | protected CPFact transferCallEdge(CallEdge edge, CPFact callSiteOut) { 116 | Invoke callSite = (Invoke) edge.getSource(); 117 | CPFact result = new CPFact(); 118 | List args = edge.getCallee().getIR().getParams(); 119 | assert args.size() == callSite.getRValue().getArgs().size(); 120 | for(int i = 0;i < args.size();i ++){ 121 | result.update(args.get(i), callSiteOut.get(callSite.getRValue().getArg(i))); 122 | } 123 | return result; 124 | } 125 | 126 | @Override 127 | protected CPFact transferReturnEdge(ReturnEdge edge, CPFact returnOut) { 128 | CPFact result = new CPFact(); 129 | Invoke callSite = (Invoke) edge.getCallSite(); 130 | Var lVar = callSite.getLValue(); 131 | if(lVar != null){ 132 | edge.getReturnVars().forEach(var -> { 133 | result.update(lVar, cp.meetValue(result.get(lVar), returnOut.get(var))); 134 | }); 135 | } 136 | return result; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /A4/InterSolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.dataflow.inter; 24 | 25 | import jas.CP; 26 | import pascal.taie.analysis.dataflow.analysis.constprop.CPFact; 27 | import pascal.taie.analysis.dataflow.fact.DataflowResult; 28 | import pascal.taie.analysis.graph.callgraph.Edge; 29 | import pascal.taie.analysis.graph.icfg.ICFG; 30 | import pascal.taie.analysis.graph.icfg.ICFGEdge; 31 | import pascal.taie.ir.stmt.Stmt; 32 | import pascal.taie.util.collection.SetQueue; 33 | 34 | import java.util.LinkedList; 35 | import java.util.Queue; 36 | import java.util.Set; 37 | import java.util.stream.Collectors; 38 | 39 | /** 40 | * Solver for inter-procedural data-flow analysis. 41 | * The workload of inter-procedural analysis is heavy, thus we always 42 | * adopt work-list algorithm for efficiency. 43 | */ 44 | class InterSolver { 45 | 46 | private final InterDataflowAnalysis analysis; 47 | 48 | private final ICFG icfg; 49 | 50 | private DataflowResult result; 51 | 52 | private Queue workList; 53 | 54 | InterSolver(InterDataflowAnalysis analysis, 55 | ICFG icfg) { 56 | this.analysis = analysis; 57 | this.icfg = icfg; 58 | } 59 | 60 | DataflowResult solve() { 61 | result = new DataflowResult<>(); 62 | initialize(); 63 | doSolve(); 64 | return result; 65 | } 66 | 67 | private void initialize() { 68 | for(Node node : icfg){ 69 | result.setOutFact(node, analysis.newInitialFact()); 70 | } 71 | icfg.entryMethods().forEach(method -> { 72 | Node entry = icfg.getEntryOf(method); 73 | result.setOutFact(entry, analysis.newBoundaryFact(entry)); 74 | }); 75 | } 76 | 77 | @SuppressWarnings("unchecked") 78 | private void doSolve() { 79 | Queue workList = new LinkedList<>(icfg.getNodes()); 80 | while(!workList.isEmpty()){ 81 | Node node = workList.poll(); 82 | CPFact in = new CPFact(); 83 | CPFact out = (CPFact) result.getOutFact(node); 84 | for(ICFGEdge edge : icfg.getInEdgesOf(node)){ 85 | analysis.meetInto(analysis.transferEdge(edge, result.getOutFact(edge.getSource())), (Fact) in); 86 | } 87 | if(analysis.transferNode(node, (Fact) in, (Fact) out)){ 88 | icfg.getSuccsOf(node).forEach(workList::offer); 89 | } 90 | result.setInFact(node, (Fact) in); 91 | result.setOutFact(node, (Fact) out); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /A5/Solver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.pta.ci; 24 | 25 | import org.apache.logging.log4j.LogManager; 26 | import org.apache.logging.log4j.Logger; 27 | import pascal.taie.World; 28 | import pascal.taie.analysis.graph.callgraph.CallGraphs; 29 | import pascal.taie.analysis.graph.callgraph.CallKind; 30 | import pascal.taie.analysis.graph.callgraph.DefaultCallGraph; 31 | import pascal.taie.analysis.graph.callgraph.Edge; 32 | import pascal.taie.analysis.pta.core.heap.HeapModel; 33 | import pascal.taie.analysis.pta.core.heap.Obj; 34 | import pascal.taie.ir.exp.Var; 35 | import pascal.taie.ir.stmt.*; 36 | import pascal.taie.language.classes.ClassHierarchy; 37 | import pascal.taie.language.classes.JMethod; 38 | import pascal.taie.language.type.Type; 39 | 40 | import java.util.List; 41 | 42 | class Solver { 43 | 44 | private static final Logger logger = LogManager.getLogger(Solver.class); 45 | 46 | private final HeapModel heapModel; 47 | 48 | private DefaultCallGraph callGraph; 49 | 50 | private PointerFlowGraph pointerFlowGraph; 51 | 52 | private WorkList workList; 53 | 54 | private StmtProcessor stmtProcessor; 55 | 56 | private ClassHierarchy hierarchy; 57 | 58 | Solver(HeapModel heapModel) { 59 | this.heapModel = heapModel; 60 | } 61 | 62 | /** 63 | * Runs pointer analysis algorithm. 64 | */ 65 | void solve() { 66 | initialize(); 67 | analyze(); 68 | } 69 | 70 | /** 71 | * Initializes pointer analysis. 72 | */ 73 | private void initialize() { 74 | workList = new WorkList(); 75 | pointerFlowGraph = new PointerFlowGraph(); 76 | callGraph = new DefaultCallGraph(); 77 | stmtProcessor = new StmtProcessor(); 78 | hierarchy = World.get().getClassHierarchy(); 79 | // initialize main method 80 | JMethod main = World.get().getMainMethod(); 81 | callGraph.addEntryMethod(main); 82 | addReachable(main); 83 | } 84 | 85 | /** 86 | * Processes new reachable method. 87 | */ 88 | private void addReachable(JMethod method) { 89 | if(!callGraph.contains(method)){ 90 | callGraph.addReachableMethod(method); 91 | method.getIR().getStmts().forEach(stmt -> stmt.accept(stmtProcessor)); 92 | } 93 | } 94 | 95 | /** 96 | * Processes statements in new reachable methods. 97 | */ 98 | private class StmtProcessor implements StmtVisitor { 99 | 100 | @Override 101 | public Void visit(New stmt) { 102 | Pointer ptr = pointerFlowGraph.getVarPtr(stmt.getLValue()); 103 | workList.addEntry(ptr, new PointsToSet(heapModel.getObj(stmt))); 104 | return null; 105 | } 106 | 107 | @Override 108 | public Void visit(Copy stmt) { 109 | addPFGEdge( 110 | pointerFlowGraph.getVarPtr(stmt.getRValue()), 111 | pointerFlowGraph.getVarPtr(stmt.getLValue()) 112 | ); 113 | return null; 114 | } 115 | 116 | @Override 117 | public Void visit(Invoke callSite) { 118 | if(callSite.isStatic()){ 119 | JMethod callee = resolveCallee(null, callSite); 120 | processSingleCall(callSite, callee); 121 | } 122 | return null; 123 | } 124 | 125 | @Override 126 | public Void visit(LoadField stmt) { 127 | if(stmt.isStatic()){ 128 | addPFGEdge( 129 | pointerFlowGraph.getStaticField(stmt.getFieldRef().resolve()), 130 | pointerFlowGraph.getVarPtr(stmt.getLValue()) 131 | ); 132 | } 133 | return null; 134 | } 135 | 136 | @Override 137 | public Void visit(StoreField stmt) { 138 | if(stmt.isStatic()) { 139 | addPFGEdge( 140 | pointerFlowGraph.getVarPtr(stmt.getRValue()), 141 | pointerFlowGraph.getStaticField(stmt.getFieldRef().resolve()) 142 | ); 143 | } 144 | return null; 145 | } 146 | } 147 | 148 | /** 149 | * Adds an edge "source -> target" to the PFG. 150 | */ 151 | private void addPFGEdge(Pointer source, Pointer target) { 152 | if(!pointerFlowGraph.getSuccsOf(source).contains(target)) { 153 | pointerFlowGraph.addEdge(source, target); 154 | PointsToSet pts = source.getPointsToSet(); 155 | if(!pts.isEmpty()){ 156 | workList.addEntry(target, pts); 157 | } 158 | } 159 | } 160 | 161 | /** 162 | * Processes work-list entries until the work-list is empty. 163 | */ 164 | private void analyze() { 165 | while(!workList.isEmpty()){ 166 | WorkList.Entry entry = workList.pollEntry(); 167 | Pointer pointer = entry.pointer(); 168 | PointsToSet pts = entry.pointsToSet(); 169 | PointsToSet delta = propagate(pointer, pts); 170 | if(pointer instanceof VarPtr ptr){ 171 | Var var = ptr.getVar(); 172 | delta.forEach(obj -> { 173 | // StoreField 174 | var.getStoreFields().forEach(stmt -> { 175 | addPFGEdge( 176 | pointerFlowGraph.getVarPtr(stmt.getRValue()), 177 | pointerFlowGraph.getInstanceField(obj, stmt.getFieldAccess().getFieldRef().resolve()) 178 | ); 179 | }); 180 | // LoadField 181 | var.getLoadFields().forEach(stmt -> { 182 | addPFGEdge( 183 | pointerFlowGraph.getInstanceField(obj, stmt.getFieldAccess().getFieldRef().resolve()), 184 | pointerFlowGraph.getVarPtr(stmt.getLValue()) 185 | ); 186 | }); 187 | // StoreArray 188 | var.getStoreArrays().forEach(stmt -> { 189 | addPFGEdge( 190 | pointerFlowGraph.getVarPtr(stmt.getRValue()), 191 | pointerFlowGraph.getArrayIndex(obj) 192 | ); 193 | }); 194 | // LoadArray 195 | var.getLoadArrays().forEach(stmt -> { 196 | addPFGEdge( 197 | pointerFlowGraph.getArrayIndex(obj), 198 | pointerFlowGraph.getVarPtr(stmt.getLValue()) 199 | ); 200 | }); 201 | // ProcessCall 202 | processCall(var, obj); 203 | }); 204 | } 205 | } 206 | } 207 | 208 | /** 209 | * Propagates pointsToSet to pt(pointer) and its PFG successors, 210 | * returns the difference set of pointsToSet and pt(pointer). 211 | */ 212 | private PointsToSet propagate(Pointer pointer, PointsToSet pts) { 213 | PointsToSet delta = new PointsToSet(); 214 | pts.objects() 215 | .filter(ptr -> !pointer.getPointsToSet().contains(ptr)) 216 | .forEach(delta::addObject); 217 | if(!delta.isEmpty()){ 218 | delta.forEach(obj -> pointer.getPointsToSet().addObject(obj)); 219 | pointerFlowGraph.getSuccsOf(pointer).forEach(succ -> workList.addEntry(succ, delta)); 220 | } 221 | return delta; 222 | } 223 | 224 | private void processSingleCall(Invoke callSite, JMethod callee){ 225 | if(!callGraph.getCalleesOf(callSite).contains(callee)){ 226 | CallKind kind = null; 227 | if(callSite.isInterface()) kind = CallKind.INTERFACE; 228 | else if(callSite.isSpecial()) kind = CallKind.SPECIAL; 229 | else if(callSite.isStatic()) kind = CallKind.STATIC; 230 | else if(callSite.isVirtual()) kind = CallKind.VIRTUAL; 231 | if(kind != null) { 232 | callGraph.addEdge(new Edge<>(kind, callSite, callee)); 233 | addReachable(callee); 234 | List args = callee.getIR().getParams(); 235 | assert args.size() == callSite.getRValue().getArgs().size(); 236 | for(int i = 0;i < args.size();i ++){ 237 | addPFGEdge( 238 | pointerFlowGraph.getVarPtr(callSite.getRValue().getArg(i)), 239 | pointerFlowGraph.getVarPtr(args.get(i)) 240 | ); 241 | } 242 | if(callSite.getLValue() != null){ 243 | callee.getIR().getReturnVars().forEach(ret -> { 244 | addPFGEdge( 245 | pointerFlowGraph.getVarPtr(ret), 246 | pointerFlowGraph.getVarPtr(callSite.getLValue()) 247 | ); 248 | }); 249 | } 250 | } 251 | } 252 | } 253 | 254 | /** 255 | * Processes instance calls when points-to set of the receiver variable changes. 256 | * 257 | * @param var the variable that holds receiver objects 258 | * @param recv a new discovered object pointed by the variable. 259 | */ 260 | private void processCall(Var var, Obj recv) { 261 | var.getInvokes().forEach(callSite -> { 262 | JMethod callee = resolveCallee(recv, callSite); 263 | workList.addEntry(pointerFlowGraph.getVarPtr(callee.getIR().getThis()), new PointsToSet(recv)); 264 | processSingleCall(callSite, callee); 265 | }); 266 | } 267 | 268 | /** 269 | * Resolves the callee of a call site with the receiver object. 270 | * 271 | * @param recv the receiver object of the method call. If the callSite 272 | * is static, this parameter is ignored (i.e., can be null). 273 | * @param callSite the call site to be resolved. 274 | * @return the resolved callee. 275 | */ 276 | private JMethod resolveCallee(Obj recv, Invoke callSite) { 277 | Type type = recv != null ? recv.getType() : null; 278 | return CallGraphs.resolveCallee(type, callSite); 279 | } 280 | 281 | CIPTAResult getResult() { 282 | return new CIPTAResult(pointerFlowGraph, callGraph); 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /A6/Solver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.pta.cs; 24 | 25 | import org.apache.logging.log4j.LogManager; 26 | import org.apache.logging.log4j.Logger; 27 | import pascal.taie.World; 28 | import pascal.taie.analysis.graph.callgraph.CallGraphs; 29 | import pascal.taie.analysis.graph.callgraph.CallKind; 30 | import pascal.taie.analysis.graph.callgraph.Edge; 31 | import pascal.taie.analysis.pta.PointerAnalysisResult; 32 | import pascal.taie.analysis.pta.PointerAnalysisResultImpl; 33 | import pascal.taie.analysis.pta.core.cs.CSCallGraph; 34 | import pascal.taie.analysis.pta.core.cs.context.Context; 35 | import pascal.taie.analysis.pta.core.cs.element.CSCallSite; 36 | import pascal.taie.analysis.pta.core.cs.element.CSManager; 37 | import pascal.taie.analysis.pta.core.cs.element.CSMethod; 38 | import pascal.taie.analysis.pta.core.cs.element.CSObj; 39 | import pascal.taie.analysis.pta.core.cs.element.CSVar; 40 | import pascal.taie.analysis.pta.core.cs.element.MapBasedCSManager; 41 | import pascal.taie.analysis.pta.core.cs.element.Pointer; 42 | import pascal.taie.analysis.pta.core.cs.selector.ContextSelector; 43 | import pascal.taie.analysis.pta.core.heap.HeapModel; 44 | import pascal.taie.analysis.pta.core.heap.Obj; 45 | import pascal.taie.analysis.pta.pts.PointsToSet; 46 | import pascal.taie.analysis.pta.pts.PointsToSetFactory; 47 | import pascal.taie.config.AnalysisOptions; 48 | import pascal.taie.ir.exp.Var; 49 | import pascal.taie.ir.stmt.Copy; 50 | import pascal.taie.ir.stmt.Invoke; 51 | import pascal.taie.ir.stmt.LoadField; 52 | import pascal.taie.ir.stmt.New; 53 | import pascal.taie.ir.stmt.StmtVisitor; 54 | import pascal.taie.ir.stmt.StoreField; 55 | import pascal.taie.language.classes.JMethod; 56 | import pascal.taie.language.type.Type; 57 | import java.util.List; 58 | 59 | class Solver { 60 | 61 | private static final Logger logger = LogManager.getLogger(Solver.class); 62 | 63 | private final AnalysisOptions options; 64 | 65 | private final HeapModel heapModel; 66 | 67 | private final ContextSelector contextSelector; 68 | 69 | private CSManager csManager; 70 | 71 | private CSCallGraph callGraph; 72 | 73 | private PointerFlowGraph pointerFlowGraph; 74 | 75 | private WorkList workList; 76 | 77 | private PointerAnalysisResult result; 78 | 79 | Solver(AnalysisOptions options, HeapModel heapModel, 80 | ContextSelector contextSelector) { 81 | this.options = options; 82 | this.heapModel = heapModel; 83 | this.contextSelector = contextSelector; 84 | } 85 | 86 | void solve() { 87 | initialize(); 88 | analyze(); 89 | } 90 | 91 | private void initialize() { 92 | csManager = new MapBasedCSManager(); 93 | callGraph = new CSCallGraph(csManager); 94 | pointerFlowGraph = new PointerFlowGraph(); 95 | workList = new WorkList(); 96 | // process program entry, i.e., main method 97 | Context defContext = contextSelector.getEmptyContext(); 98 | JMethod main = World.get().getMainMethod(); 99 | CSMethod csMethod = csManager.getCSMethod(defContext, main); 100 | callGraph.addEntryMethod(csMethod); 101 | addReachable(csMethod); 102 | } 103 | 104 | /** 105 | * Processes new reachable context-sensitive method. 106 | */ 107 | private void addReachable(CSMethod csMethod) { 108 | if(!callGraph.contains(csMethod)){ 109 | callGraph.addReachableMethod(csMethod); 110 | csMethod.getMethod().getIR().getStmts().forEach(stmt -> stmt.accept(new StmtProcessor(csMethod))); 111 | } 112 | } 113 | 114 | /** 115 | * Processes the statements in context-sensitive new reachable methods. 116 | */ 117 | private class StmtProcessor implements StmtVisitor { 118 | 119 | private final CSMethod csMethod; 120 | 121 | private final Context context; 122 | 123 | private StmtProcessor(CSMethod csMethod) { 124 | this.csMethod = csMethod; 125 | this.context = csMethod.getContext(); 126 | } 127 | 128 | @Override 129 | public Void visit(New stmt) { 130 | Pointer ptr = csManager.getCSVar(context, stmt.getLValue()); 131 | Obj obj = heapModel.getObj(stmt); 132 | Context ctx = contextSelector.selectHeapContext(csMethod, obj); 133 | PointsToSet pts = PointsToSetFactory.make(csManager.getCSObj(ctx, obj)); 134 | workList.addEntry(ptr, pts); 135 | return null; 136 | } 137 | 138 | @Override 139 | public Void visit(Copy stmt) { 140 | addPFGEdge( 141 | csManager.getCSVar(context, stmt.getRValue()), 142 | csManager.getCSVar(context, stmt.getLValue()) 143 | ); 144 | return null; 145 | } 146 | 147 | @Override 148 | public Void visit(Invoke callSite) { 149 | if(callSite.isStatic()){ 150 | JMethod callee = resolveCallee(null, callSite); 151 | CSCallSite csCallSite = csManager.getCSCallSite(context, callSite); 152 | Context calleeContext = contextSelector.selectContext(csCallSite, callee); 153 | processSingleCall(csCallSite, csManager.getCSMethod(calleeContext, callee)); 154 | } 155 | return null; 156 | } 157 | 158 | @Override 159 | public Void visit(LoadField stmt) { 160 | if(stmt.isStatic()){ 161 | addPFGEdge( 162 | csManager.getStaticField(stmt.getFieldRef().resolve()), 163 | csManager.getCSVar(context, stmt.getLValue()) 164 | ); 165 | } 166 | return null; 167 | } 168 | 169 | @Override 170 | public Void visit(StoreField stmt) { 171 | if(stmt.isStatic()) { 172 | addPFGEdge( 173 | csManager.getCSVar(context, stmt.getRValue()), 174 | csManager.getStaticField(stmt.getFieldRef().resolve()) 175 | ); 176 | } 177 | return null; 178 | } 179 | } 180 | 181 | /** 182 | * Adds an edge "source -> target" to the PFG. 183 | */ 184 | private void addPFGEdge(Pointer source, Pointer target) { 185 | if(!pointerFlowGraph.getSuccsOf(source).contains(target)) { 186 | pointerFlowGraph.addEdge(source, target); 187 | PointsToSet pts = source.getPointsToSet(); 188 | if(!pts.isEmpty()){ 189 | workList.addEntry(target, pts); 190 | } 191 | } 192 | } 193 | 194 | /** 195 | * Processes work-list entries until the work-list is empty. 196 | */ 197 | private void analyze() { 198 | while(!workList.isEmpty()){ 199 | WorkList.Entry entry = workList.pollEntry(); 200 | Pointer pointer = entry.pointer(); 201 | PointsToSet pts = entry.pointsToSet(); 202 | PointsToSet delta = propagate(pointer, pts); 203 | if(pointer instanceof CSVar ptr){ 204 | Var var = ptr.getVar(); 205 | Context ctx = ptr.getContext(); 206 | delta.forEach(obj -> { 207 | // StoreField 208 | var.getStoreFields().forEach(stmt -> { 209 | addPFGEdge( 210 | csManager.getCSVar(ctx, stmt.getRValue()), 211 | csManager.getInstanceField(obj, stmt.getFieldAccess().getFieldRef().resolve()) 212 | ); 213 | }); 214 | // LoadField 215 | var.getLoadFields().forEach(stmt -> { 216 | addPFGEdge( 217 | csManager.getInstanceField(obj, stmt.getFieldAccess().getFieldRef().resolve()), 218 | csManager.getCSVar(ctx, stmt.getLValue()) 219 | ); 220 | }); 221 | // StoreArray 222 | var.getStoreArrays().forEach(stmt -> { 223 | addPFGEdge( 224 | csManager.getCSVar(ctx, stmt.getRValue()), 225 | csManager.getArrayIndex(obj) 226 | ); 227 | }); 228 | // LoadArray 229 | var.getLoadArrays().forEach(stmt -> { 230 | addPFGEdge( 231 | csManager.getArrayIndex(obj), 232 | csManager.getCSVar(ctx, stmt.getLValue()) 233 | ); 234 | }); 235 | // ProcessCall 236 | processCall(ptr, obj); 237 | }); 238 | } 239 | } 240 | } 241 | 242 | /** 243 | * Propagates pointsToSet to pt(pointer) and its PFG successors, 244 | * returns the difference set of pointsToSet and pt(pointer). 245 | */ 246 | private PointsToSet propagate(Pointer pointer, PointsToSet pointsToSet) { 247 | PointsToSet delta = PointsToSetFactory.make(); 248 | pointsToSet.objects() 249 | .filter(ptr -> !pointer.getPointsToSet().contains(ptr)) 250 | .forEach(delta::addObject); 251 | if(!delta.isEmpty()){ 252 | delta.forEach(obj -> pointer.getPointsToSet().addObject(obj)); 253 | pointerFlowGraph.getSuccsOf(pointer).forEach(succ -> workList.addEntry(succ, delta)); 254 | } 255 | return delta; 256 | } 257 | 258 | private void processSingleCall(CSCallSite csCallSite, CSMethod callee){ 259 | Invoke callSite = csCallSite.getCallSite(); 260 | Context callerContext = csCallSite.getContext(); 261 | Context calleeContext = callee.getContext(); 262 | if(!callGraph.getCalleesOf(csCallSite).contains(callee)){ 263 | CallKind kind = null; 264 | if(callSite.isInterface()) kind = CallKind.INTERFACE; 265 | else if(callSite.isSpecial()) kind = CallKind.SPECIAL; 266 | else if(callSite.isStatic()) kind = CallKind.STATIC; 267 | else if(callSite.isVirtual()) kind = CallKind.VIRTUAL; 268 | if(kind != null) { 269 | callGraph.addEdge(new Edge<>(kind, csCallSite, callee)); 270 | addReachable(callee); 271 | List args = callee.getMethod().getIR().getParams(); 272 | assert args.size() == callSite.getRValue().getArgs().size(); 273 | for(int i = 0;i < args.size();i ++){ 274 | addPFGEdge( 275 | csManager.getCSVar(callerContext, callSite.getRValue().getArg(i)), 276 | csManager.getCSVar(calleeContext, args.get(i)) 277 | ); 278 | } 279 | if(callSite.getLValue() != null){ 280 | callee.getMethod().getIR().getReturnVars().forEach(ret -> { 281 | addPFGEdge( 282 | csManager.getCSVar(calleeContext, ret), 283 | csManager.getCSVar(callerContext, callSite.getLValue()) 284 | ); 285 | }); 286 | } 287 | } 288 | } 289 | } 290 | 291 | /** 292 | * Processes instance calls when points-to set of the receiver variable changes. 293 | * 294 | * @param recv the receiver variable 295 | * @param recvObj set of new discovered objects pointed by the variable. 296 | */ 297 | private void processCall(CSVar recv, CSObj recvObj) { 298 | recv.getVar().getInvokes().forEach(callSite -> { 299 | CSCallSite csCallSite = csManager.getCSCallSite(recv.getContext(), callSite); 300 | JMethod callee = resolveCallee(recvObj, callSite); 301 | Context calleeContext = contextSelector.selectContext(csCallSite, recvObj, callee); 302 | CSMethod csCallee = csManager.getCSMethod(calleeContext, callee); 303 | workList.addEntry( 304 | csManager.getCSVar(calleeContext, callee.getIR().getThis()), 305 | PointsToSetFactory.make(recvObj) 306 | ); 307 | processSingleCall(csCallSite, csCallee); 308 | }); 309 | } 310 | 311 | /** 312 | * Resolves the callee of a call site with the receiver object. 313 | * 314 | * @param recv the receiver object of the method call. If the callSite 315 | * is static, this parameter is ignored (i.e., can be null). 316 | * @param callSite the call site to be resolved. 317 | * @return the resolved callee. 318 | */ 319 | private JMethod resolveCallee(CSObj recv, Invoke callSite) { 320 | Type type = recv != null ? recv.getObject().getType() : null; 321 | return CallGraphs.resolveCallee(type, callSite); 322 | } 323 | 324 | PointerAnalysisResult getResult() { 325 | if (result == null) { 326 | result = new PointerAnalysisResultImpl(csManager, callGraph); 327 | } 328 | return result; 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /A6/_1CallSelector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.pta.core.cs.selector; 24 | 25 | import pascal.taie.analysis.pta.core.cs.context.Context; 26 | import pascal.taie.analysis.pta.core.cs.context.ListContext; 27 | import pascal.taie.analysis.pta.core.cs.element.CSCallSite; 28 | import pascal.taie.analysis.pta.core.cs.element.CSMethod; 29 | import pascal.taie.analysis.pta.core.cs.element.CSObj; 30 | import pascal.taie.analysis.pta.core.heap.Obj; 31 | import pascal.taie.language.classes.JMethod; 32 | 33 | /** 34 | * Implementation of 1-call-site sensitivity. 35 | */ 36 | public class _1CallSelector implements ContextSelector { 37 | 38 | @Override 39 | public Context getEmptyContext() { 40 | return ListContext.make(); 41 | } 42 | 43 | @Override 44 | public Context selectContext(CSCallSite callSite, JMethod callee) { 45 | return ListContext.make(callSite.getCallSite()); 46 | } 47 | 48 | @Override 49 | public Context selectContext(CSCallSite callSite, CSObj recv, JMethod callee) { 50 | return selectContext(callSite, callee); 51 | } 52 | 53 | @Override 54 | public Context selectHeapContext(CSMethod method, Obj obj) { 55 | return getEmptyContext(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /A6/_1ObjSelector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.pta.core.cs.selector; 24 | 25 | import pascal.taie.analysis.pta.core.cs.context.Context; 26 | import pascal.taie.analysis.pta.core.cs.context.ListContext; 27 | import pascal.taie.analysis.pta.core.cs.element.CSCallSite; 28 | import pascal.taie.analysis.pta.core.cs.element.CSMethod; 29 | import pascal.taie.analysis.pta.core.cs.element.CSObj; 30 | import pascal.taie.analysis.pta.core.heap.Obj; 31 | import pascal.taie.language.classes.JMethod; 32 | 33 | /** 34 | * Implementation of 1-object sensitivity. 35 | */ 36 | public class _1ObjSelector implements ContextSelector { 37 | 38 | @Override 39 | public Context getEmptyContext() { 40 | return ListContext.make(); 41 | } 42 | 43 | @Override 44 | public Context selectContext(CSCallSite callSite, JMethod callee) { 45 | return callSite.getContext(); 46 | } 47 | 48 | @Override 49 | public Context selectContext(CSCallSite callSite, CSObj recv, JMethod callee) { 50 | return ListContext.make(recv.getObject()); 51 | } 52 | 53 | @Override 54 | public Context selectHeapContext(CSMethod method, Obj obj) { 55 | return getEmptyContext(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /A6/_1TypeSelector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.pta.core.cs.selector; 24 | 25 | import pascal.taie.analysis.pta.core.cs.context.Context; 26 | import pascal.taie.analysis.pta.core.cs.context.ListContext; 27 | import pascal.taie.analysis.pta.core.cs.element.CSCallSite; 28 | import pascal.taie.analysis.pta.core.cs.element.CSMethod; 29 | import pascal.taie.analysis.pta.core.cs.element.CSObj; 30 | import pascal.taie.analysis.pta.core.heap.Obj; 31 | import pascal.taie.language.classes.JMethod; 32 | 33 | /** 34 | * Implementation of 1-type sensitivity. 35 | */ 36 | public class _1TypeSelector implements ContextSelector { 37 | 38 | @Override 39 | public Context getEmptyContext() { 40 | return ListContext.make(); 41 | } 42 | 43 | @Override 44 | public Context selectContext(CSCallSite callSite, JMethod callee) { 45 | return getEmptyContext(); 46 | } 47 | 48 | @Override 49 | public Context selectContext(CSCallSite callSite, CSObj recv, JMethod callee) { 50 | return ListContext.make(recv.getObject().getContainerType()); 51 | } 52 | 53 | @Override 54 | public Context selectHeapContext(CSMethod method, Obj obj) { 55 | return getEmptyContext(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /A6/_2CallSelector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.pta.core.cs.selector; 24 | 25 | import pascal.taie.analysis.pta.core.cs.context.Context; 26 | import pascal.taie.analysis.pta.core.cs.context.ListContext; 27 | import pascal.taie.analysis.pta.core.cs.element.CSCallSite; 28 | import pascal.taie.analysis.pta.core.cs.element.CSMethod; 29 | import pascal.taie.analysis.pta.core.cs.element.CSObj; 30 | import pascal.taie.analysis.pta.core.heap.Obj; 31 | import pascal.taie.ir.stmt.Invoke; 32 | import pascal.taie.language.classes.JMethod; 33 | 34 | /** 35 | * Implementation of 2-call-site sensitivity. 36 | */ 37 | public class _2CallSelector implements ContextSelector { 38 | 39 | @Override 40 | public Context getEmptyContext() { 41 | return ListContext.make(); 42 | } 43 | 44 | @Override 45 | public Context selectContext(CSCallSite callSite, JMethod callee) { 46 | Context oldContext = callSite.getContext(); 47 | if(oldContext.getLength() >= 1){ 48 | return ListContext.make(oldContext.getElementAt(oldContext.getLength() - 1), callSite.getCallSite()); 49 | } 50 | return ListContext.make(callSite.getCallSite()); 51 | } 52 | 53 | @Override 54 | public Context selectContext(CSCallSite callSite, CSObj recv, JMethod callee) { 55 | return selectContext(callSite, callee); 56 | } 57 | 58 | @Override 59 | public Context selectHeapContext(CSMethod method, Obj obj) { 60 | Context oldContext = method.getContext(); 61 | if(oldContext.getLength() >= 2){ 62 | return ListContext.make(oldContext.getElementAt(oldContext.getLength() - 1)); 63 | } 64 | return oldContext; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /A6/_2ObjSelector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.pta.core.cs.selector; 24 | 25 | import pascal.taie.analysis.pta.core.cs.context.Context; 26 | import pascal.taie.analysis.pta.core.cs.context.ListContext; 27 | import pascal.taie.analysis.pta.core.cs.element.CSCallSite; 28 | import pascal.taie.analysis.pta.core.cs.element.CSMethod; 29 | import pascal.taie.analysis.pta.core.cs.element.CSObj; 30 | import pascal.taie.analysis.pta.core.heap.Obj; 31 | import pascal.taie.language.classes.JMethod; 32 | 33 | /** 34 | * Implementation of 2-object sensitivity. 35 | */ 36 | public class _2ObjSelector implements ContextSelector { 37 | 38 | @Override 39 | public Context getEmptyContext() { 40 | return ListContext.make(); 41 | } 42 | 43 | @Override 44 | public Context selectContext(CSCallSite callSite, JMethod callee) { 45 | return callSite.getContext(); 46 | } 47 | 48 | @Override 49 | public Context selectContext(CSCallSite callSite, CSObj recv, JMethod callee) { 50 | Context oldContext = recv.getContext(); 51 | if(oldContext.getLength() >= 1){ 52 | return ListContext.make(oldContext.getElementAt(oldContext.getLength() - 1), recv.getObject()); 53 | } 54 | return ListContext.make(recv.getObject()); 55 | } 56 | 57 | @Override 58 | public Context selectHeapContext(CSMethod method, Obj obj) { 59 | Context oldContext = method.getContext(); 60 | if(oldContext.getLength() >= 2){ 61 | return ListContext.make(oldContext.getElementAt(oldContext.getLength() - 1)); 62 | } 63 | return oldContext; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /A6/_2TypeSelector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.pta.core.cs.selector; 24 | 25 | import pascal.taie.analysis.pta.core.cs.context.Context; 26 | import pascal.taie.analysis.pta.core.cs.context.ListContext; 27 | import pascal.taie.analysis.pta.core.cs.element.CSCallSite; 28 | import pascal.taie.analysis.pta.core.cs.element.CSMethod; 29 | import pascal.taie.analysis.pta.core.cs.element.CSObj; 30 | import pascal.taie.analysis.pta.core.heap.Obj; 31 | import pascal.taie.language.classes.JMethod; 32 | 33 | /** 34 | * Implementation of 2-type sensitivity. 35 | */ 36 | public class _2TypeSelector implements ContextSelector { 37 | 38 | @Override 39 | public Context getEmptyContext() { 40 | return ListContext.make(); 41 | } 42 | 43 | @Override 44 | public Context selectContext(CSCallSite callSite, JMethod callee) { 45 | return callSite.getContext(); 46 | } 47 | 48 | @Override 49 | public Context selectContext(CSCallSite callSite, CSObj recv, JMethod callee) { 50 | Context oldContext = recv.getContext(); 51 | if(oldContext.getLength() >= 1){ 52 | return ListContext.make(oldContext.getElementAt(oldContext.getLength() - 1), recv.getObject().getContainerType()); 53 | } 54 | return ListContext.make(recv.getObject().getContainerType()); 55 | } 56 | 57 | @Override 58 | public Context selectHeapContext(CSMethod method, Obj obj) { 59 | Context oldContext = method.getContext(); 60 | if(oldContext.getLength() >= 2){ 61 | return ListContext.make(oldContext.getElementAt(oldContext.getLength() - 1)); 62 | } 63 | return oldContext; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /A7/ConstantPropagation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.dataflow.analysis.constprop; 24 | 25 | import pascal.taie.analysis.dataflow.analysis.AbstractDataflowAnalysis; 26 | import pascal.taie.analysis.graph.cfg.CFG; 27 | import pascal.taie.analysis.pta.core.heap.Obj; 28 | import pascal.taie.config.AnalysisConfig; 29 | import pascal.taie.ir.exp.*; 30 | import pascal.taie.ir.proginfo.FieldRef; 31 | import pascal.taie.ir.stmt.DefinitionStmt; 32 | import pascal.taie.ir.stmt.LoadField; 33 | import pascal.taie.ir.stmt.Stmt; 34 | import pascal.taie.ir.stmt.StoreField; 35 | import pascal.taie.language.classes.JClass; 36 | import pascal.taie.language.type.PrimitiveType; 37 | import pascal.taie.language.type.Type; 38 | import pascal.taie.util.collection.Pair; 39 | 40 | import java.util.Map; 41 | import java.util.concurrent.atomic.AtomicBoolean; 42 | 43 | import static pascal.taie.analysis.dataflow.inter.InterConstantPropagation.pta; 44 | import static pascal.taie.analysis.dataflow.inter.InterConstantPropagation.valMap; 45 | 46 | public class ConstantPropagation extends 47 | AbstractDataflowAnalysis { 48 | 49 | public static final String ID = "constprop"; 50 | 51 | public ConstantPropagation(AnalysisConfig config) { 52 | super(config); 53 | } 54 | 55 | @Override 56 | public boolean isForward() { 57 | return true; 58 | } 59 | 60 | @Override 61 | public CPFact newBoundaryFact(CFG cfg) { 62 | CPFact fact = new CPFact(); 63 | cfg.getIR().getParams().forEach(var -> { 64 | if(canHoldInt(var)) { 65 | fact.update(var, Value.getNAC()); 66 | } 67 | }); 68 | return fact; 69 | } 70 | 71 | @Override 72 | public CPFact newInitialFact() { 73 | return new CPFact(); 74 | } 75 | 76 | @Override 77 | public void meetInto(CPFact fact, CPFact target) { 78 | fact.forEach(((var, value) -> { 79 | target.update(var, meetValue(value, target.get(var))); 80 | })); 81 | } 82 | 83 | /** 84 | * Meets two Values. 85 | */ 86 | public static Value meetValue(Value v1, Value v2) { 87 | if(v1.isConstant() && v2.isConstant()){ 88 | if(v1.equals(v2)){ 89 | return Value.makeConstant(v1.getConstant()); 90 | }else{ 91 | return Value.getNAC(); 92 | } 93 | }else if(v1.isNAC() || v2.isNAC()){ 94 | return Value.getNAC(); 95 | }else if(v1.isConstant() && v2.isUndef()){ 96 | return Value.makeConstant(v1.getConstant()); 97 | }else if(v2.isConstant() && v1.isUndef()){ 98 | return Value.makeConstant(v2.getConstant()); 99 | } 100 | return Value.getUndef(); 101 | } 102 | 103 | @Override 104 | public boolean transferNode(Stmt stmt, CPFact in, CPFact out) { 105 | AtomicBoolean changed = new AtomicBoolean(false); 106 | in.forEach(((var, value) -> { 107 | if(out.update(var, value)){ 108 | changed.set(true); 109 | } 110 | })); 111 | if(stmt instanceof DefinitionStmt s){ 112 | if(s.getLValue() instanceof Var var && canHoldInt(var)) { 113 | CPFact inCopy = in.copy(); 114 | Value removedVal = inCopy.get(var); 115 | inCopy.remove(var); 116 | Value newVal = evaluate(s.getRValue(), in); 117 | out.update(var, newVal); 118 | return !removedVal.equals(newVal) || changed.get(); 119 | } 120 | } 121 | return changed.get(); 122 | } 123 | 124 | /** 125 | * @return true if the given variable can hold integer value, otherwise false. 126 | */ 127 | public static boolean canHoldInt(Var var) { 128 | Type type = var.getType(); 129 | if (type instanceof PrimitiveType) { 130 | switch ((PrimitiveType) type) { 131 | case BYTE: 132 | case SHORT: 133 | case INT: 134 | case CHAR: 135 | case BOOLEAN: 136 | return true; 137 | } 138 | } 139 | return false; 140 | } 141 | 142 | /** 143 | * Evaluates the {@link Value} of given expression. 144 | * 145 | * @param exp the expression to be evaluated 146 | * @param in IN fact of the statement 147 | * @return the resulting {@link Value} 148 | */ 149 | public static Value evaluate(Exp exp, CPFact in) { 150 | if(exp instanceof IntLiteral e){ 151 | return Value.makeConstant(e.getValue()); 152 | }else if(exp instanceof Var var){ 153 | if(in.get(var).isConstant()){ 154 | return Value.makeConstant(in.get(var).getConstant()); 155 | } 156 | return in.get(var); 157 | }else if(exp instanceof BinaryExp b){ 158 | Value v1 = evaluate(b.getOperand1(), in); 159 | Value v2 = evaluate(b.getOperand2(), in); 160 | if(v2.isConstant() && v2.getConstant() == 0 161 | && b.getOperator() instanceof ArithmeticExp.Op op){ 162 | if(op == ArithmeticExp.Op.DIV || op == ArithmeticExp.Op.REM){ 163 | return Value.getUndef(); 164 | } 165 | } 166 | if(v1.isConstant() && v2.isConstant()){ 167 | int c1 = v1.getConstant(), c2 = v2.getConstant(); 168 | if(b.getOperator() instanceof ArithmeticExp.Op op){ 169 | switch (op){ 170 | case ADD -> { 171 | return Value.makeConstant(c1 + c2); 172 | } 173 | case SUB -> { 174 | return Value.makeConstant(c1 - c2); 175 | } 176 | case MUL -> { 177 | return Value.makeConstant(c1 * c2); 178 | } 179 | case DIV -> { 180 | return Value.makeConstant(c1 / c2); 181 | } 182 | case REM -> { 183 | return Value.makeConstant(c1 % c2); 184 | } 185 | } 186 | }else if(b.getOperator() instanceof ShiftExp.Op op){ 187 | switch (op){ 188 | case SHL -> { 189 | return Value.makeConstant(c1 << c2); 190 | } 191 | case SHR -> { 192 | return Value.makeConstant(c1 >> c2); 193 | } 194 | case USHR -> { 195 | return Value.makeConstant(c1 >>> c2); 196 | } 197 | } 198 | }else if(b.getOperator() instanceof BitwiseExp.Op op){ 199 | switch (op){ 200 | case OR -> { 201 | return Value.makeConstant(c1 | c2); 202 | } 203 | case AND -> { 204 | return Value.makeConstant(c1 & c2); 205 | } 206 | case XOR -> { 207 | return Value.makeConstant(c1 ^ c2); 208 | } 209 | } 210 | }else if(b.getOperator() instanceof ConditionExp.Op op){ 211 | switch (op){ 212 | case EQ -> { 213 | return Value.makeConstant(c1 == c2 ? 1 : 0); 214 | } 215 | case NE -> { 216 | return Value.makeConstant(c1 != c2 ? 1 : 0); 217 | } 218 | case LT -> { 219 | return Value.makeConstant(c1 < c2 ? 1 : 0); 220 | } 221 | case GT -> { 222 | return Value.makeConstant(c1 > c2 ? 1 : 0); 223 | } 224 | case LE -> { 225 | return Value.makeConstant(c1 <= c2 ? 1 : 0); 226 | } 227 | case GE -> { 228 | return Value.makeConstant(c1 >= c2 ? 1 : 0); 229 | } 230 | } 231 | } 232 | }else if(v1.isNAC() || v2.isNAC()){ 233 | return Value.getNAC(); 234 | } 235 | return Value.getUndef(); 236 | }else if(exp instanceof InstanceFieldAccess access){ 237 | Value val = Value.getUndef(); 238 | for(Obj obj : pta.getPointsToSet(access.getBase())){ 239 | val = meetValue(val, valMap.getOrDefault(new Pair<>(obj, access.getFieldRef()), Value.getUndef())); 240 | } 241 | return val; 242 | }else if(exp instanceof StaticFieldAccess access){ 243 | return valMap.getOrDefault( 244 | new Pair<>(access.getFieldRef().getDeclaringClass(), access.getFieldRef()), 245 | Value.getUndef() 246 | ); 247 | }else if(exp instanceof ArrayAccess access){ 248 | Value index = evaluate(access.getIndex(), in); 249 | Value val = Value.getUndef(); 250 | if(index.isConstant()){ 251 | for(Obj obj : pta.getPointsToSet(access.getBase())){ 252 | val = meetValue(val, valMap.getOrDefault(new Pair<>(obj, index), Value.getUndef())); 253 | val = meetValue(val, valMap.getOrDefault(new Pair<>(obj, Value.getNAC()), Value.getUndef())); 254 | } 255 | }else if(index.isNAC()){ 256 | for(Obj obj : pta.getPointsToSet(access.getBase())){ 257 | for(Map.Entry, Value> entry : valMap.entrySet()){ 258 | Pair accessPair = entry.getKey(); 259 | if(accessPair.first().equals(obj) && accessPair.second() instanceof Value){ 260 | val = meetValue(val, entry.getValue()); 261 | } 262 | } 263 | } 264 | } 265 | return val; 266 | } 267 | return Value.getNAC(); 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /A7/InterConstantPropagation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.dataflow.inter; 24 | 25 | import pascal.taie.World; 26 | import pascal.taie.analysis.dataflow.analysis.constprop.CPFact; 27 | import pascal.taie.analysis.dataflow.analysis.constprop.ConstantPropagation; 28 | import pascal.taie.analysis.dataflow.analysis.constprop.Value; 29 | import pascal.taie.analysis.graph.cfg.CFGBuilder; 30 | import pascal.taie.analysis.graph.icfg.CallEdge; 31 | import pascal.taie.analysis.graph.icfg.CallToReturnEdge; 32 | import pascal.taie.analysis.graph.icfg.NormalEdge; 33 | import pascal.taie.analysis.graph.icfg.ReturnEdge; 34 | import pascal.taie.analysis.pta.PointerAnalysisResult; 35 | import pascal.taie.analysis.pta.core.cs.element.CSObj; 36 | import pascal.taie.analysis.pta.core.cs.element.CSVar; 37 | import pascal.taie.analysis.pta.core.heap.Obj; 38 | import pascal.taie.config.AnalysisConfig; 39 | import pascal.taie.ir.IR; 40 | import pascal.taie.ir.exp.InstanceFieldAccess; 41 | import pascal.taie.ir.exp.StaticFieldAccess; 42 | import pascal.taie.ir.exp.Var; 43 | import pascal.taie.ir.proginfo.FieldRef; 44 | import pascal.taie.ir.stmt.Invoke; 45 | import pascal.taie.ir.stmt.LoadField; 46 | import pascal.taie.ir.stmt.Stmt; 47 | import pascal.taie.ir.stmt.StoreField; 48 | import pascal.taie.language.classes.JClass; 49 | import pascal.taie.language.classes.JMethod; 50 | import pascal.taie.language.type.Type; 51 | import pascal.taie.util.collection.Pair; 52 | 53 | import java.util.*; 54 | import java.util.concurrent.atomic.AtomicBoolean; 55 | 56 | /** 57 | * Implementation of interprocedural constant propagation for int values. 58 | */ 59 | public class InterConstantPropagation extends 60 | AbstractInterDataflowAnalysis { 61 | 62 | public static final String ID = "inter-constprop"; 63 | 64 | private final ConstantPropagation cp; 65 | 66 | public static final Map> aliasMap = new HashMap<>(); 67 | public static final Map, Value> valMap = new HashMap<>(); 68 | public static final Map, Set> staticLoadFields = new HashMap<>(); 69 | public static PointerAnalysisResult pta; 70 | 71 | public InterConstantPropagation(AnalysisConfig config) { 72 | super(config); 73 | cp = new ConstantPropagation(new AnalysisConfig(ConstantPropagation.ID)); 74 | } 75 | 76 | @Override 77 | protected void initialize() { 78 | String ptaId = getOptions().getString("pta"); 79 | pta = World.get().getResult(ptaId); 80 | // You can do initialization work here 81 | // for(CSVar var : pta.getCSVars()){ 82 | // for(CSObj obj : pta.getPointsToSet(var)){ 83 | // Set s = aliasMap.getOrDefault(obj.getObject(), new HashSet<>()); 84 | // s.add(var.getVar()); 85 | // aliasMap.put(obj.getObject(), s); 86 | // } 87 | // } 88 | for(Var var : pta.getVars()){ 89 | for(Obj obj : pta.getPointsToSet(var)){ 90 | Set s = aliasMap.getOrDefault(obj, new HashSet<>()); 91 | s.add(var); 92 | aliasMap.put(obj, s); 93 | } 94 | } 95 | icfg.getNodes().forEach(stmt -> { 96 | if(stmt instanceof LoadField s && s.getFieldAccess() instanceof StaticFieldAccess access){ 97 | Pair accessPair = new Pair<>(access.getFieldRef().getDeclaringClass(), access.getFieldRef()); 98 | Set set = staticLoadFields.getOrDefault(accessPair, new HashSet<>()); 99 | set.add(s); 100 | staticLoadFields.put(accessPair, set); 101 | } 102 | }); 103 | } 104 | 105 | @Override 106 | public boolean isForward() { 107 | return cp.isForward(); 108 | } 109 | 110 | @Override 111 | public CPFact newBoundaryFact(Stmt boundary) { 112 | IR ir = icfg.getContainingMethodOf(boundary).getIR(); 113 | return cp.newBoundaryFact(ir.getResult(CFGBuilder.ID)); 114 | } 115 | 116 | @Override 117 | public CPFact newInitialFact() { 118 | return cp.newInitialFact(); 119 | } 120 | 121 | @Override 122 | public void meetInto(CPFact fact, CPFact target) { 123 | cp.meetInto(fact, target); 124 | } 125 | 126 | @Override 127 | protected boolean transferCallNode(Stmt stmt, CPFact in, CPFact out) { 128 | AtomicBoolean changed = new AtomicBoolean(false); 129 | in.forEach(((var, value) -> { 130 | if(out.update(var, value)){ 131 | changed.set(true); 132 | } 133 | })); 134 | return changed.get() ; 135 | } 136 | 137 | @Override 138 | protected boolean transferNonCallNode(Stmt stmt, CPFact in, CPFact out) { 139 | return cp.transferNode(stmt, in, out); 140 | } 141 | 142 | @Override 143 | protected CPFact transferNormalEdge(NormalEdge edge, CPFact out) { 144 | return out; 145 | } 146 | 147 | @Override 148 | protected CPFact transferCallToReturnEdge(CallToReturnEdge edge, CPFact out) { 149 | Invoke callSite = (Invoke) edge.getSource(); 150 | Var lVar = callSite.getLValue(); 151 | CPFact result = out.copy(); 152 | if(lVar != null){ 153 | result.remove(lVar); 154 | } 155 | return result; 156 | } 157 | 158 | @Override 159 | protected CPFact transferCallEdge(CallEdge edge, CPFact callSiteOut) { 160 | Invoke callSite = (Invoke) edge.getSource(); 161 | CPFact result = new CPFact(); 162 | List args = edge.getCallee().getIR().getParams(); 163 | assert args.size() == callSite.getRValue().getArgs().size(); 164 | for(int i = 0;i < args.size();i ++){ 165 | result.update(args.get(i), callSiteOut.get(callSite.getRValue().getArg(i))); 166 | } 167 | return result; 168 | } 169 | 170 | @Override 171 | protected CPFact transferReturnEdge(ReturnEdge edge, CPFact returnOut) { 172 | CPFact result = new CPFact(); 173 | Invoke callSite = (Invoke) edge.getCallSite(); 174 | Var lVar = callSite.getLValue(); 175 | if(lVar != null){ 176 | edge.getReturnVars().forEach(var -> { 177 | result.update(lVar, cp.meetValue(result.get(lVar), returnOut.get(var))); 178 | }); 179 | } 180 | return result; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /A7/InterSolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.dataflow.inter; 24 | 25 | import pascal.taie.analysis.dataflow.analysis.constprop.CPFact; 26 | import pascal.taie.analysis.dataflow.analysis.constprop.ConstantPropagation; 27 | import pascal.taie.analysis.dataflow.analysis.constprop.Value; 28 | import pascal.taie.analysis.dataflow.fact.DataflowResult; 29 | import pascal.taie.analysis.graph.icfg.ICFG; 30 | import pascal.taie.analysis.graph.icfg.ICFGEdge; 31 | import pascal.taie.analysis.pta.core.heap.Obj; 32 | import pascal.taie.ir.exp.ArrayAccess; 33 | import pascal.taie.ir.exp.InstanceFieldAccess; 34 | import pascal.taie.ir.exp.StaticFieldAccess; 35 | import pascal.taie.ir.exp.Var; 36 | import pascal.taie.ir.proginfo.FieldRef; 37 | import pascal.taie.ir.stmt.*; 38 | import pascal.taie.language.classes.JClass; 39 | import pascal.taie.util.collection.Pair; 40 | import java.util.*; 41 | import java.util.concurrent.atomic.AtomicBoolean; 42 | 43 | import static pascal.taie.analysis.dataflow.inter.InterConstantPropagation.*; 44 | 45 | /** 46 | * Solver for inter-procedural data-flow analysis. 47 | * The workload of inter-procedural analysis is heavy, thus we always 48 | * adopt work-list algorithm for efficiency. 49 | */ 50 | class InterSolver { 51 | 52 | private final InterDataflowAnalysis analysis; 53 | 54 | private final ICFG icfg; 55 | 56 | private DataflowResult result; 57 | 58 | private Queue workList; 59 | 60 | InterSolver(InterDataflowAnalysis analysis, 61 | ICFG icfg) { 62 | this.analysis = analysis; 63 | this.icfg = icfg; 64 | } 65 | 66 | DataflowResult solve() { 67 | result = new DataflowResult<>(); 68 | initialize(); 69 | doSolve(); 70 | return result; 71 | } 72 | 73 | private void initialize() { 74 | for(Node node : icfg){ 75 | result.setOutFact(node, analysis.newInitialFact()); 76 | } 77 | icfg.entryMethods().forEach(method -> { 78 | Node entry = icfg.getEntryOf(method); 79 | result.setOutFact(entry, analysis.newBoundaryFact(entry)); 80 | }); 81 | } 82 | 83 | private Value meetValue(Value v1, Value v2) { 84 | if(v1.isConstant() && v2.isConstant()){ 85 | if(v1.equals(v2)){ 86 | return Value.makeConstant(v1.getConstant()); 87 | }else{ 88 | return Value.getNAC(); 89 | } 90 | }else if(v1.isNAC() || v2.isNAC()){ 91 | return Value.getNAC(); 92 | }else if(v1.isConstant() && v2.isUndef()){ 93 | return Value.makeConstant(v1.getConstant()); 94 | }else if(v2.isConstant() && v1.isUndef()){ 95 | return Value.makeConstant(v2.getConstant()); 96 | } 97 | return Value.getUndef(); 98 | } 99 | 100 | @SuppressWarnings("unchecked") 101 | private void handleStoreField(Stmt stmt, CPFact in){ 102 | if(stmt instanceof StoreField s){ 103 | if(!ConstantPropagation.canHoldInt(s.getRValue())) return; 104 | if(s.getFieldAccess() instanceof InstanceFieldAccess access) { 105 | Var base = access.getBase(); 106 | pta.getPointsToSet(base).forEach(obj -> { 107 | Pair accessPair = new Pair<>(obj, s.getFieldRef()); 108 | Value newVal = ConstantPropagation.evaluate(s.getRValue(), in); 109 | Value oldVal = valMap.getOrDefault(accessPair, Value.getUndef()); 110 | newVal = meetValue(oldVal, newVal); 111 | valMap.put(accessPair, newVal); 112 | if(!oldVal.equals(newVal)){ 113 | Set alias = aliasMap.get(obj); 114 | alias.forEach(var -> { 115 | var.getLoadFields().stream() 116 | .filter(loadStmt -> loadStmt.getFieldAccess().getFieldRef().equals(s.getFieldRef())) 117 | .forEach(loadStmt -> workList.offer((Node) loadStmt)); 118 | }); 119 | } 120 | }); 121 | }else if(s.getFieldAccess() instanceof StaticFieldAccess access){ 122 | JClass clz = access.getFieldRef().getDeclaringClass(); 123 | Pair accessPair = new Pair<>(clz, s.getFieldRef()); 124 | Value oldVal = valMap.getOrDefault(accessPair, Value.getUndef()); 125 | Value newVal = ConstantPropagation.evaluate(s.getRValue(), in); 126 | newVal = meetValue(oldVal, newVal); 127 | valMap.put(accessPair, newVal); 128 | if (!oldVal.equals(newVal)) { 129 | staticLoadFields.getOrDefault(accessPair, new HashSet<>()).forEach(loadStmt -> { 130 | workList.offer((Node) loadStmt); 131 | }); 132 | } 133 | } 134 | } 135 | } 136 | 137 | @SuppressWarnings("unchecked") 138 | private void handleStoreArray(Stmt stmt, CPFact in){ 139 | if(stmt instanceof StoreArray s){ 140 | if(!ConstantPropagation.canHoldInt(s.getRValue())) return; 141 | ArrayAccess access = s.getArrayAccess(); 142 | Value index = ConstantPropagation.evaluate(access.getIndex(), in); 143 | if(index.isUndef()) return; // Ignore UNDEF 144 | Var base = access.getBase(); 145 | pta.getPointsToSet(base).forEach(obj -> { 146 | Pair accessPair = new Pair<>(obj, index); 147 | Value newVal = ConstantPropagation.evaluate(s.getRValue(), in); 148 | Value oldVal = valMap.getOrDefault(accessPair, Value.getUndef()); 149 | newVal = meetValue(oldVal, newVal); 150 | valMap.put(accessPair, newVal); 151 | if(!oldVal.equals(newVal)){ 152 | Set alias = aliasMap.get(obj); 153 | alias.forEach(var -> { 154 | var.getLoadArrays().forEach(loadStmt -> workList.offer((Node) loadStmt)); 155 | }); 156 | } 157 | }); 158 | } 159 | } 160 | 161 | @SuppressWarnings("unchecked") 162 | private void doSolve() { 163 | workList = new LinkedList<>(icfg.getNodes()); 164 | while(!workList.isEmpty()){ 165 | Node node = workList.poll(); 166 | CPFact in = new CPFact(); 167 | CPFact out = (CPFact) result.getOutFact(node); 168 | for(ICFGEdge edge : icfg.getInEdgesOf(node)){ 169 | analysis.meetInto(analysis.transferEdge(edge, result.getOutFact(edge.getSource())), (Fact) in); 170 | } 171 | handleStoreField((Stmt) node, in); 172 | handleStoreArray((Stmt) node, in); 173 | if(analysis.transferNode(node, (Fact) in, (Fact) out)){ 174 | icfg.getSuccsOf(node).forEach(workList::offer); 175 | } 176 | result.setInFact(node, (Fact) in); 177 | result.setOutFact(node, (Fact) out); 178 | } 179 | } 180 | 181 | } 182 | -------------------------------------------------------------------------------- /A8/Solver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.pta.cs; 24 | 25 | import org.apache.logging.log4j.LogManager; 26 | import org.apache.logging.log4j.Logger; 27 | import pascal.taie.World; 28 | import pascal.taie.analysis.graph.callgraph.CallGraphs; 29 | import pascal.taie.analysis.graph.callgraph.CallKind; 30 | import pascal.taie.analysis.graph.callgraph.Edge; 31 | import pascal.taie.analysis.pta.PointerAnalysisResult; 32 | import pascal.taie.analysis.pta.PointerAnalysisResultImpl; 33 | import pascal.taie.analysis.pta.core.cs.CSCallGraph; 34 | import pascal.taie.analysis.pta.core.cs.context.Context; 35 | import pascal.taie.analysis.pta.core.cs.element.CSCallSite; 36 | import pascal.taie.analysis.pta.core.cs.element.CSManager; 37 | import pascal.taie.analysis.pta.core.cs.element.CSMethod; 38 | import pascal.taie.analysis.pta.core.cs.element.CSObj; 39 | import pascal.taie.analysis.pta.core.cs.element.CSVar; 40 | import pascal.taie.analysis.pta.core.cs.element.MapBasedCSManager; 41 | import pascal.taie.analysis.pta.core.cs.element.Pointer; 42 | import pascal.taie.analysis.pta.core.cs.selector.ContextSelector; 43 | import pascal.taie.analysis.pta.core.heap.HeapModel; 44 | import pascal.taie.analysis.pta.core.heap.Obj; 45 | import pascal.taie.analysis.pta.plugin.taint.TaintAnalysiss; 46 | import pascal.taie.analysis.pta.pts.PointsToSet; 47 | import pascal.taie.analysis.pta.pts.PointsToSetFactory; 48 | import pascal.taie.config.AnalysisOptions; 49 | import pascal.taie.ir.exp.InvokeInstanceExp; 50 | import pascal.taie.ir.exp.Var; 51 | import pascal.taie.ir.stmt.Copy; 52 | import pascal.taie.ir.stmt.Invoke; 53 | import pascal.taie.ir.stmt.LoadField; 54 | import pascal.taie.ir.stmt.New; 55 | import pascal.taie.ir.stmt.StmtVisitor; 56 | import pascal.taie.ir.stmt.StoreField; 57 | import pascal.taie.language.classes.JMethod; 58 | import pascal.taie.language.type.Type; 59 | 60 | import java.util.*; 61 | 62 | public class Solver { 63 | 64 | private static final Logger logger = LogManager.getLogger(Solver.class); 65 | 66 | private final AnalysisOptions options; 67 | 68 | private final HeapModel heapModel; 69 | 70 | private final ContextSelector contextSelector; 71 | 72 | private CSManager csManager; 73 | 74 | private CSCallGraph callGraph; 75 | 76 | private PointerFlowGraph pointerFlowGraph; 77 | 78 | private WorkList workList; 79 | 80 | private TaintAnalysiss taintAnalysis; 81 | 82 | private PointerAnalysisResult result; 83 | 84 | private Map> possibleTaintTransfers; 85 | 86 | Solver(AnalysisOptions options, HeapModel heapModel, 87 | ContextSelector contextSelector) { 88 | this.options = options; 89 | this.heapModel = heapModel; 90 | this.contextSelector = contextSelector; 91 | this.possibleTaintTransfers = new HashMap<>(); 92 | } 93 | 94 | public AnalysisOptions getOptions() { 95 | return options; 96 | } 97 | 98 | public ContextSelector getContextSelector() { 99 | return contextSelector; 100 | } 101 | 102 | public CSManager getCSManager() { 103 | return csManager; 104 | } 105 | 106 | void solve() { 107 | initialize(); 108 | analyze(); 109 | taintAnalysis.onFinish(); 110 | } 111 | 112 | private void initialize() { 113 | csManager = new MapBasedCSManager(); 114 | callGraph = new CSCallGraph(csManager); 115 | pointerFlowGraph = new PointerFlowGraph(); 116 | workList = new WorkList(); 117 | taintAnalysis = new TaintAnalysiss(this); 118 | // process program entry, i.e., main method 119 | Context defContext = contextSelector.getEmptyContext(); 120 | JMethod main = World.get().getMainMethod(); 121 | CSMethod csMethod = csManager.getCSMethod(defContext, main); 122 | callGraph.addEntryMethod(csMethod); 123 | addReachable(csMethod); 124 | } 125 | 126 | /** 127 | * Processes new reachable context-sensitive method. 128 | */ 129 | private void addReachable(CSMethod csMethod) { 130 | if(!callGraph.contains(csMethod)){ 131 | callGraph.addReachableMethod(csMethod); 132 | csMethod.getMethod().getIR().getStmts().forEach(stmt -> stmt.accept(new StmtProcessor(csMethod))); 133 | 134 | } 135 | } 136 | 137 | /** 138 | * Processes the statements in context-sensitive new reachable methods. 139 | */ 140 | private class StmtProcessor implements StmtVisitor { 141 | 142 | private final CSMethod csMethod; 143 | 144 | private final Context context; 145 | 146 | private StmtProcessor(CSMethod csMethod) { 147 | this.csMethod = csMethod; 148 | this.context = csMethod.getContext(); 149 | } 150 | 151 | @Override 152 | public Void visit(New stmt) { 153 | Pointer ptr = csManager.getCSVar(context, stmt.getLValue()); 154 | Obj obj = heapModel.getObj(stmt); 155 | Context ctx = contextSelector.selectHeapContext(csMethod, obj); 156 | PointsToSet pts = PointsToSetFactory.make(csManager.getCSObj(ctx, obj)); 157 | workList.addEntry(ptr, pts); 158 | return null; 159 | } 160 | 161 | @Override 162 | public Void visit(Copy stmt) { 163 | addPFGEdge( 164 | csManager.getCSVar(context, stmt.getRValue()), 165 | csManager.getCSVar(context, stmt.getLValue()) 166 | ); 167 | return null; 168 | } 169 | 170 | @Override 171 | public Void visit(Invoke callSite) { 172 | if(callSite.isStatic()){ 173 | JMethod callee = resolveCallee(null, callSite); 174 | CSCallSite csCallSite = csManager.getCSCallSite(context, callSite); 175 | Context calleeContext = contextSelector.selectContext(csCallSite, callee); 176 | processSingleCall(csCallSite, csManager.getCSMethod(calleeContext, callee)); 177 | transferTaint(csCallSite, callee, null); 178 | } 179 | csMethod.getMethod().getIR().getStmts().forEach(stmt -> { 180 | if(stmt instanceof Invoke invoke){ 181 | invoke.getInvokeExp().getArgs().forEach(arg -> { 182 | CSVar var = csManager.getCSVar(context, arg); 183 | Set invokes = possibleTaintTransfers.getOrDefault(var, new HashSet<>()); 184 | invokes.add(invoke); 185 | possibleTaintTransfers.put(var, invokes); 186 | }); 187 | } 188 | }); 189 | return null; 190 | } 191 | 192 | @Override 193 | public Void visit(LoadField stmt) { 194 | if(stmt.isStatic()){ 195 | addPFGEdge( 196 | csManager.getStaticField(stmt.getFieldRef().resolve()), 197 | csManager.getCSVar(context, stmt.getLValue()) 198 | ); 199 | } 200 | return null; 201 | } 202 | 203 | @Override 204 | public Void visit(StoreField stmt) { 205 | if(stmt.isStatic()) { 206 | addPFGEdge( 207 | csManager.getCSVar(context, stmt.getRValue()), 208 | csManager.getStaticField(stmt.getFieldRef().resolve()) 209 | ); 210 | } 211 | return null; 212 | } 213 | } 214 | 215 | private void transferTaint(CSCallSite csCallSite, JMethod callee, CSVar base){ 216 | taintAnalysis.handleTaintTransfer(csCallSite, callee, base).forEach(varObjPair -> { 217 | Var var = varObjPair.first(); 218 | Obj obj = varObjPair.second(); 219 | CSObj csObj = csManager.getCSObj(contextSelector.getEmptyContext(), obj); 220 | Pointer ptr = csManager.getCSVar(csCallSite.getContext(), var); 221 | workList.addEntry(ptr, PointsToSetFactory.make(csObj)); 222 | }); 223 | } 224 | 225 | /** 226 | * Adds an edge "source -> target" to the PFG. 227 | */ 228 | private void addPFGEdge(Pointer source, Pointer target) { 229 | if(!pointerFlowGraph.getSuccsOf(source).contains(target)) { 230 | pointerFlowGraph.addEdge(source, target); 231 | PointsToSet pts = source.getPointsToSet(); 232 | if(!pts.isEmpty()){ 233 | workList.addEntry(target, pts); 234 | } 235 | } 236 | } 237 | 238 | /** 239 | * Processes work-list entries until the work-list is empty. 240 | */ 241 | private void analyze() { 242 | while(!workList.isEmpty()){ 243 | WorkList.Entry entry = workList.pollEntry(); 244 | Pointer pointer = entry.pointer(); 245 | PointsToSet pts = entry.pointsToSet(); 246 | PointsToSet delta = propagate(pointer, pts); 247 | if(pointer instanceof CSVar csVar){ 248 | Var var = csVar.getVar(); 249 | Context ctx = csVar.getContext(); 250 | delta.forEach(obj -> { 251 | // StoreField 252 | var.getStoreFields().forEach(stmt -> { 253 | addPFGEdge( 254 | csManager.getCSVar(ctx, stmt.getRValue()), 255 | csManager.getInstanceField(obj, stmt.getFieldAccess().getFieldRef().resolve()) 256 | ); 257 | }); 258 | // LoadField 259 | var.getLoadFields().forEach(stmt -> { 260 | addPFGEdge( 261 | csManager.getInstanceField(obj, stmt.getFieldAccess().getFieldRef().resolve()), 262 | csManager.getCSVar(ctx, stmt.getLValue()) 263 | ); 264 | }); 265 | // StoreArray 266 | var.getStoreArrays().forEach(stmt -> { 267 | addPFGEdge( 268 | csManager.getCSVar(ctx, stmt.getRValue()), 269 | csManager.getArrayIndex(obj) 270 | ); 271 | }); 272 | // LoadArray 273 | var.getLoadArrays().forEach(stmt -> { 274 | addPFGEdge( 275 | csManager.getArrayIndex(obj), 276 | csManager.getCSVar(ctx, stmt.getLValue()) 277 | ); 278 | }); 279 | // ProcessCall 280 | processCall(csVar, obj); 281 | // TaintTransfer 282 | if(taintAnalysis.isTaint(obj.getObject())){ 283 | possibleTaintTransfers.getOrDefault(csVar, new HashSet<>()).forEach(invoke -> { 284 | CSCallSite csCallSite = csManager.getCSCallSite(ctx, invoke); 285 | if(invoke.getInvokeExp() instanceof InvokeInstanceExp exp){ 286 | CSVar recv = csManager.getCSVar(ctx, exp.getBase()); 287 | result.getPointsToSet(recv).forEach(recvObj -> { 288 | JMethod callee = resolveCallee(recvObj, invoke); 289 | transferTaint(csCallSite, callee, recv); 290 | }); 291 | }else{ 292 | JMethod callee = resolveCallee(null, invoke); 293 | transferTaint(csCallSite, callee, null); 294 | } 295 | }); 296 | } 297 | }); 298 | } 299 | } 300 | } 301 | 302 | /** 303 | * Propagates pointsToSet to pt(pointer) and its PFG successors, 304 | * returns the difference set of pointsToSet and pt(pointer). 305 | */ 306 | private PointsToSet propagate(Pointer pointer, PointsToSet pointsToSet) { 307 | PointsToSet delta = PointsToSetFactory.make(); 308 | pointsToSet.objects() 309 | .filter(ptr -> !pointer.getPointsToSet().contains(ptr)) 310 | .forEach(delta::addObject); 311 | if(!delta.isEmpty()){ 312 | delta.forEach(obj -> pointer.getPointsToSet().addObject(obj)); 313 | pointerFlowGraph.getSuccsOf(pointer).forEach(succ -> workList.addEntry(succ, delta)); 314 | } 315 | return delta; 316 | } 317 | 318 | private void processSingleCall(CSCallSite csCallSite, CSMethod callee){ 319 | Invoke callSite = csCallSite.getCallSite(); 320 | Obj obj = taintAnalysis.handleTaintSource(callSite, callee.getMethod()); 321 | Var lVar = csCallSite.getCallSite().getLValue(); 322 | if(obj != null && lVar != null){ 323 | CSObj csObj = csManager.getCSObj(contextSelector.getEmptyContext(), obj); 324 | Pointer ptr = csManager.getCSVar(csCallSite.getContext(), lVar); 325 | workList.addEntry(ptr, PointsToSetFactory.make(csObj)); 326 | } 327 | Context callerContext = csCallSite.getContext(); 328 | Context calleeContext = callee.getContext(); 329 | if(!callGraph.getCalleesOf(csCallSite).contains(callee)){ 330 | CallKind kind = null; 331 | if(callSite.isInterface()) kind = CallKind.INTERFACE; 332 | else if(callSite.isSpecial()) kind = CallKind.SPECIAL; 333 | else if(callSite.isStatic()) kind = CallKind.STATIC; 334 | else if(callSite.isVirtual()) kind = CallKind.VIRTUAL; 335 | if(kind != null) { 336 | callGraph.addEdge(new Edge<>(kind, csCallSite, callee)); 337 | addReachable(callee); 338 | List args = callee.getMethod().getIR().getParams(); 339 | assert args.size() == callSite.getRValue().getArgs().size(); 340 | for(int i = 0;i < args.size();i ++){ 341 | addPFGEdge( 342 | csManager.getCSVar(callerContext, callSite.getRValue().getArg(i)), 343 | csManager.getCSVar(calleeContext, args.get(i)) 344 | ); 345 | } 346 | if(callSite.getLValue() != null){ 347 | callee.getMethod().getIR().getReturnVars().forEach(ret -> { 348 | addPFGEdge( 349 | csManager.getCSVar(calleeContext, ret), 350 | csManager.getCSVar(callerContext, callSite.getLValue()) 351 | ); 352 | }); 353 | } 354 | } 355 | } 356 | } 357 | 358 | /** 359 | * Processes instance calls when points-to set of the receiver variable changes. 360 | * 361 | * @param recv the receiver variable 362 | * @param recvObj set of new discovered objects pointed by the variable. 363 | */ 364 | private void processCall(CSVar recv, CSObj recvObj) { 365 | recv.getVar().getInvokes().forEach(callSite -> { 366 | CSCallSite csCallSite = csManager.getCSCallSite(recv.getContext(), callSite); 367 | JMethod callee = resolveCallee(recvObj, callSite); 368 | Context calleeContext = contextSelector.selectContext(csCallSite, recvObj, callee); 369 | CSMethod csCallee = csManager.getCSMethod(calleeContext, callee); 370 | workList.addEntry( 371 | csManager.getCSVar(calleeContext, callee.getIR().getThis()), 372 | PointsToSetFactory.make(recvObj) 373 | ); 374 | processSingleCall(csCallSite, csCallee); 375 | transferTaint(csCallSite, callee, recv); 376 | }); 377 | } 378 | 379 | /** 380 | * Resolves the callee of a call site with the receiver object. 381 | * 382 | * @param recv the receiver object of the method call. If the callSite 383 | * is static, this parameter is ignored (i.e., can be null). 384 | * @param callSite the call site to be resolved. 385 | * @return the resolved callee. 386 | */ 387 | public JMethod resolveCallee(CSObj recv, Invoke callSite) { 388 | Type type = recv != null ? recv.getObject().getType() : null; 389 | return CallGraphs.resolveCallee(type, callSite); 390 | } 391 | 392 | public PointerAnalysisResult getResult() { 393 | if (result == null) { 394 | result = new PointerAnalysisResultImpl(csManager, callGraph); 395 | } 396 | return result; 397 | } 398 | } 399 | -------------------------------------------------------------------------------- /A8/TaintAnalysiss.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Tai-e: A Static Analysis Framework for Java 3 | * 4 | * Copyright (C) 2022 Tian Tan 5 | * Copyright (C) 2022 Yue Li 6 | * 7 | * This file is part of Tai-e. 8 | * 9 | * Tai-e is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License 11 | * as published by the Free Software Foundation, either version 3 12 | * of the License, or (at your option) any later version. 13 | * 14 | * Tai-e is distributed in the hope that it will be useful,but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 17 | * Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with Tai-e. If not, see . 21 | */ 22 | 23 | package pascal.taie.analysis.pta.plugin.taint; 24 | 25 | import org.apache.logging.log4j.LogManager; 26 | import org.apache.logging.log4j.Logger; 27 | import pascal.taie.World; 28 | import pascal.taie.analysis.graph.callgraph.CallGraph; 29 | import pascal.taie.analysis.pta.PointerAnalysisResult; 30 | import pascal.taie.analysis.pta.core.cs.context.Context; 31 | import pascal.taie.analysis.pta.core.cs.element.*; 32 | import pascal.taie.analysis.pta.core.heap.Obj; 33 | import pascal.taie.analysis.pta.cs.Solver; 34 | import pascal.taie.ir.exp.Var; 35 | import pascal.taie.ir.stmt.Invoke; 36 | import pascal.taie.language.classes.JMethod; 37 | import pascal.taie.language.type.Type; 38 | import pascal.taie.util.collection.Pair; 39 | import java.util.*; 40 | 41 | public class TaintAnalysiss { 42 | 43 | private static final Logger logger = LogManager.getLogger(TaintAnalysiss.class); 44 | 45 | private final TaintManager manager; 46 | 47 | private final TaintConfig config; 48 | 49 | private final Solver solver; 50 | 51 | private final CSManager csManager; 52 | 53 | private final Context emptyContext; 54 | 55 | public TaintAnalysiss(Solver solver) { 56 | manager = new TaintManager(); 57 | this.solver = solver; 58 | csManager = solver.getCSManager(); 59 | emptyContext = solver.getContextSelector().getEmptyContext(); 60 | config = TaintConfig.readConfig( 61 | solver.getOptions().getString("taint-config"), 62 | World.get().getClassHierarchy(), 63 | World.get().getTypeSystem()); 64 | logger.info(config); 65 | } 66 | 67 | public boolean isTaint(Obj obj) { 68 | return manager.isTaint(obj); 69 | } 70 | 71 | // Call (source) 72 | public Obj handleTaintSource(Invoke callSite, JMethod callee){ 73 | Type type = callee.getReturnType(); 74 | Source source = new Source(callee, type); 75 | if(config.getSources().contains(source)){ 76 | return manager.makeTaint(callSite, type); 77 | } 78 | return null; 79 | } 80 | 81 | public Set> handleTaintTransfer(CSCallSite csCallSite, JMethod callee, CSVar base){ 82 | Invoke callSite = csCallSite.getCallSite(); 83 | Var lVar = callSite.getLValue(); 84 | PointerAnalysisResult ptaResult = solver.getResult(); 85 | Set> result = new HashSet<>(); 86 | TaintTransfer transfer; 87 | if(base != null) { 88 | // Call (base-to-result) 89 | Type resultType = callee.getReturnType(); 90 | transfer = new TaintTransfer(callee, TaintTransfer.BASE, TaintTransfer.RESULT, resultType); 91 | if(config.getTransfers().contains(transfer) && lVar != null){ 92 | Set basePts = ptaResult.getPointsToSet(base); 93 | basePts.forEach(csObj -> { 94 | if(manager.isTaint(csObj.getObject())){ 95 | result.add(new Pair<>(lVar, 96 | manager.makeTaint(manager.getSourceCall(csObj.getObject()), resultType))); 97 | } 98 | }); 99 | } 100 | // Call (arg-to-base) 101 | Type baseType = base.getType(); 102 | List args = callSite.getInvokeExp().getArgs(); 103 | for (int i = 0; i < args.size(); i++) { 104 | Var arg = args.get(i); 105 | Set argPts = ptaResult.getPointsToSet(csManager.getCSVar(csCallSite.getContext(), arg)); 106 | transfer = new TaintTransfer(callee, i, TaintTransfer.BASE, baseType); 107 | if (config.getTransfers().contains(transfer)) { 108 | argPts.forEach(csObj -> { 109 | if(manager.isTaint(csObj.getObject())){ 110 | result.add(new Pair<>(base.getVar(), 111 | manager.makeTaint(manager.getSourceCall(csObj.getObject()), baseType))); 112 | } 113 | }); 114 | } 115 | } 116 | } 117 | // Call (arg-to-result) 118 | List args = callSite.getInvokeExp().getArgs(); 119 | Type resultType = callee.getReturnType(); 120 | for (int i = 0; i < args.size(); i++) { 121 | Var arg = args.get(i); 122 | Set argPts = ptaResult.getPointsToSet(csManager.getCSVar(csCallSite.getContext(), arg)); 123 | transfer = new TaintTransfer(callee, i, TaintTransfer.RESULT, resultType); 124 | if (config.getTransfers().contains(transfer)) { 125 | argPts.forEach(csObj -> { 126 | if(manager.isTaint(csObj.getObject())){ 127 | result.add(new Pair<>(lVar, 128 | manager.makeTaint(manager.getSourceCall(csObj.getObject()), resultType))); 129 | } 130 | }); 131 | } 132 | } 133 | return result; 134 | } 135 | 136 | public void onFinish() { 137 | Set taintFlows = collectTaintFlows(); 138 | solver.getResult().storeResult(getClass().getName(), taintFlows); 139 | } 140 | 141 | private Set collectTaintFlows() { 142 | Set taintFlows = new TreeSet<>(); 143 | PointerAnalysisResult result = solver.getResult(); 144 | CallGraph callGraph = result.getCSCallGraph(); 145 | callGraph.reachableMethods().forEach(csMethod -> { 146 | callGraph.getCallersOf(csMethod).forEach(csCallSite -> { 147 | Invoke callSite = csCallSite.getCallSite(); 148 | JMethod callee = csMethod.getMethod(); 149 | List args = callSite.getInvokeExp().getArgs(); 150 | for(int i = 0;i < args.size();i ++){ 151 | Var arg = args.get(i); 152 | Sink sink = new Sink(callee, i); 153 | if(config.getSinks().contains(sink)){ 154 | int index = i; 155 | result.getPointsToSet(arg).forEach(obj -> { 156 | if(manager.isTaint(obj)){ 157 | taintFlows.add(new TaintFlow(manager.getSourceCall(obj), callSite, index)); 158 | } 159 | }); 160 | } 161 | } 162 | }); 163 | }); 164 | return taintFlows; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tai-e-solutions 2 | My solutions to NJU Static Program Analysis assignments: https://tai-e.pascal-lab.net/en/intro/overview.html 3 | 4 | I made it public for learning purposes only. **DO NOT PLAGIARIZE.** 5 | --------------------------------------------------------------------------------