1/* 2 * Copyright (c) 2024-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { Scene } from '../../Scene'; 17import { DataflowProblem, FlowFunction } from './DataflowProblem'; 18import { Local } from '../base/Local'; 19import { Value } from '../base/Value'; 20import { ClassType, UndefinedType } from '../base/Type'; 21import { ArkAssignStmt, ArkInvokeStmt, Stmt } from '../base/Stmt'; 22import { ArkMethod } from '../model/ArkMethod'; 23import { Constant } from '../base/Constant'; 24import { AbstractRef, ArkInstanceFieldRef, ArkStaticFieldRef } from '../base/Ref'; 25import { DataflowSolver } from './DataflowSolver'; 26import { ArkInstanceInvokeExpr, ArkStaticInvokeExpr } from '../base/Expr'; 27import { FileSignature, NamespaceSignature } from '../model/ArkSignature'; 28import { ArkClass } from '../model/ArkClass'; 29import { LocalEqual, RefEqual } from './Util'; 30import { INSTANCE_INIT_METHOD_NAME, STATIC_INIT_METHOD_NAME } from '../common/Const'; 31import { ArkField } from '../model/ArkField'; 32import Logger, { LOG_MODULE_TYPE } from '../../utils/logger'; 33 34const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'Scene'); 35 36export class UndefinedVariableChecker extends DataflowProblem<Value> { 37 zeroValue: Constant = new Constant('undefined', UndefinedType.getInstance()); 38 entryPoint: Stmt; 39 entryMethod: ArkMethod; 40 scene: Scene; 41 classMap: Map<FileSignature | NamespaceSignature, ArkClass[]>; 42 globalVariableMap: Map<FileSignature | NamespaceSignature, Local[]>; 43 outcomes: Outcome[] = []; 44 constructor(stmt: Stmt, method: ArkMethod) { 45 super(); 46 this.entryPoint = stmt; 47 this.entryMethod = method; 48 this.scene = method.getDeclaringArkFile().getScene(); 49 this.classMap = this.scene.getClassMap(); 50 this.globalVariableMap = this.scene.getGlobalVariableMap(); 51 } 52 53 getEntryPoint(): Stmt { 54 return this.entryPoint; 55 } 56 57 getEntryMethod(): ArkMethod { 58 return this.entryMethod; 59 } 60 61 private isUndefined(val: Value): boolean { 62 if (val instanceof Constant) { 63 let constant: Constant = val as Constant; 64 if (constant.getType() instanceof UndefinedType) { 65 return true; 66 } 67 } 68 return false; 69 } 70 71 getNormalFlowFunction(srcStmt: Stmt, tgtStmt: Stmt): FlowFunction<Value> { 72 let checkerInstance: UndefinedVariableChecker = this; 73 return new (class implements FlowFunction<Value> { 74 getDataFacts(dataFact: Value): Set<Value> { 75 let ret: Set<Value> = new Set(); 76 if (checkerInstance.getEntryPoint() === srcStmt && checkerInstance.getZeroValue() === dataFact) { 77 ret.add(checkerInstance.getZeroValue()); 78 return ret; 79 } 80 if (srcStmt instanceof ArkAssignStmt) { 81 checkerInstance.insideNormalFlowFunction(ret, srcStmt, dataFact); 82 } 83 return ret; 84 } 85 })(); 86 } 87 88 insideNormalFlowFunction(ret: Set<Value>, srcStmt: ArkAssignStmt, dataFact: Value): void { 89 if (!this.factEqual(srcStmt.getDef()!, dataFact)) { 90 if (!(dataFact instanceof Local && dataFact.getName() === srcStmt.getDef()!.toString())) { 91 ret.add(dataFact); 92 } 93 } 94 let ass: ArkAssignStmt = srcStmt as ArkAssignStmt; 95 let assigned: Value = ass.getLeftOp(); 96 let rightOp: Value = ass.getRightOp(); 97 if (this.getZeroValue() === dataFact) { 98 if (this.isUndefined(rightOp)) { 99 ret.add(assigned); 100 } 101 } else if (this.factEqual(rightOp, dataFact) || rightOp.getType() instanceof UndefinedType) { 102 ret.add(assigned); 103 } else if (rightOp instanceof ArkInstanceFieldRef) { 104 const base = rightOp.getBase(); 105 if (base === dataFact || (!base.getDeclaringStmt() && base.getName() === dataFact.toString())) { 106 this.outcomes.push(new Outcome(rightOp, ass)); 107 logger.info('undefined base'); 108 logger.info(srcStmt.toString()); 109 logger.info(srcStmt.getOriginPositionInfo().toString()); 110 } 111 } else if (dataFact instanceof ArkInstanceFieldRef && rightOp === dataFact.getBase()) { 112 const field = new ArkInstanceFieldRef(srcStmt.getLeftOp() as Local, dataFact.getFieldSignature()); 113 ret.add(field); 114 } 115 } 116 117 getCallFlowFunction(srcStmt: Stmt, method: ArkMethod): FlowFunction<Value> { 118 let checkerInstance: UndefinedVariableChecker = this; 119 return new (class implements FlowFunction<Value> { 120 getDataFacts(dataFact: Value): Set<Value> { 121 const ret: Set<Value> = new Set(); 122 if (checkerInstance.getZeroValue() === dataFact) { 123 checkerInstance.insideCallFlowFunction(ret, method); 124 } else { 125 const callExpr = srcStmt.getExprs()[0]; 126 if ( 127 callExpr instanceof ArkInstanceInvokeExpr && 128 dataFact instanceof ArkInstanceFieldRef && 129 callExpr.getBase().getName() === dataFact.getBase().getName() 130 ) { 131 // todo:base转this 132 const thisRef = new ArkInstanceFieldRef( 133 new Local('this', new ClassType(method.getDeclaringArkClass().getSignature())), 134 dataFact.getFieldSignature() 135 ); 136 ret.add(thisRef); 137 } else if ( 138 callExpr instanceof ArkStaticInvokeExpr && 139 dataFact instanceof ArkStaticFieldRef && 140 callExpr.getMethodSignature().getDeclaringClassSignature() === dataFact.getFieldSignature().getDeclaringSignature() 141 ) { 142 ret.add(dataFact); 143 } 144 } 145 checkerInstance.addParameters(srcStmt, dataFact, method, ret); 146 return ret; 147 } 148 })(); 149 } 150 151 insideCallFlowFunction(ret: Set<Value>, method: ArkMethod): void { 152 ret.add(this.getZeroValue()); 153 // 加上调用函数能访问到的所有静态变量,如果不考虑多线程,加上所有变量,考虑则要统计之前已经处理过的变量并排除 154 for (const field of method.getDeclaringArkClass().getStaticFields(this.classMap)) { 155 if (field.getInitializer() === undefined) { 156 ret.add(new ArkStaticFieldRef(field.getSignature())); 157 } 158 } 159 for (const local of method.getDeclaringArkClass().getGlobalVariable(this.globalVariableMap)) { 160 ret.add(local); 161 } 162 // 加上所有未定义初始值的属性 163 if (method.getName() === INSTANCE_INIT_METHOD_NAME || method.getName() === STATIC_INIT_METHOD_NAME) { 164 for (const field of method.getDeclaringArkClass().getFields()) { 165 this.addUndefinedField(field, method, ret); 166 } 167 } 168 } 169 170 addUndefinedField(field: ArkField, method: ArkMethod, ret: Set<Value>): void { 171 let defined = false; 172 for (const stmt of method.getCfg()!.getStmts()) { 173 const def = stmt.getDef(); 174 if (def instanceof ArkInstanceFieldRef && def.getFieldSignature() === field.getSignature()) { 175 defined = true; 176 break; 177 } 178 } 179 if (!defined) { 180 const fieldRef = new ArkInstanceFieldRef(new Local('this', new ClassType(method.getDeclaringArkClass().getSignature())), field.getSignature()); 181 ret.add(fieldRef); 182 } 183 } 184 185 addParameters(srcStmt: Stmt, dataFact: Value, method: ArkMethod, ret: Set<Value>): void { 186 const callStmt = srcStmt as ArkInvokeStmt; 187 const args = callStmt.getInvokeExpr().getArgs(); 188 for (let i = 0; i < args.length; i++) { 189 if (args[i] === dataFact || (this.isUndefined(args[i]) && this.getZeroValue() === dataFact)) { 190 const realParameter = [...method.getCfg()!.getBlocks()][0].getStmts()[i].getDef(); 191 if (realParameter) { 192 ret.add(realParameter); 193 } 194 } else if (dataFact instanceof ArkInstanceFieldRef && dataFact.getBase().getName() === args[i].toString()) { 195 const realParameter = [...method.getCfg()!.getBlocks()][0].getStmts()[i].getDef(); 196 if (realParameter) { 197 const retRef = new ArkInstanceFieldRef(realParameter as Local, dataFact.getFieldSignature()); 198 ret.add(retRef); 199 } 200 } 201 } 202 } 203 204 getExitToReturnFlowFunction(srcStmt: Stmt, tgtStmt: Stmt, callStmt: Stmt): FlowFunction<Value> { 205 let checkerInstance: UndefinedVariableChecker = this; 206 return new (class implements FlowFunction<Value> { 207 getDataFacts(dataFact: Value): Set<Value> { 208 let ret: Set<Value> = new Set<Value>(); 209 if (dataFact === checkerInstance.getZeroValue()) { 210 ret.add(checkerInstance.getZeroValue()); 211 } 212 return ret; 213 } 214 })(); 215 } 216 217 getCallToReturnFlowFunction(srcStmt: Stmt, tgtStmt: Stmt): FlowFunction<Value> { 218 let checkerInstance: UndefinedVariableChecker = this; 219 return new (class implements FlowFunction<Value> { 220 getDataFacts(dataFact: Value): Set<Value> { 221 const ret: Set<Value> = new Set(); 222 if (checkerInstance.getZeroValue() === dataFact) { 223 ret.add(checkerInstance.getZeroValue()); 224 } 225 const defValue = srcStmt.getDef(); 226 if (!(defValue && defValue === dataFact)) { 227 ret.add(dataFact); 228 } 229 return ret; 230 } 231 })(); 232 } 233 234 createZeroValue(): Value { 235 return this.zeroValue; 236 } 237 238 getZeroValue(): Value { 239 return this.zeroValue; 240 } 241 242 factEqual(d1: Value, d2: Value): boolean { 243 if (d1 instanceof Constant && d2 instanceof Constant) { 244 return d1 === d2; 245 } else if (d1 instanceof Local && d2 instanceof Local) { 246 return LocalEqual(d1, d2); 247 } else if (d1 instanceof AbstractRef && d2 instanceof AbstractRef) { 248 return RefEqual(d1, d2); 249 } 250 return false; 251 } 252 253 public getOutcomes(): Outcome[] { 254 return this.outcomes; 255 } 256} 257 258export class UndefinedVariableSolver extends DataflowSolver<Value> { 259 constructor(problem: UndefinedVariableChecker, scene: Scene) { 260 super(problem, scene); 261 } 262} 263 264class Outcome { 265 value: Value; 266 stmt: Stmt; 267 constructor(v: Value, s: Stmt) { 268 this.value = v; 269 this.stmt = s; 270 } 271} 272