所以我试图在烟灰中插入一个RuntimeException,并且我已经写了一个方法来帮助我做到这一点:
private static final RefType STRING_TYPE = RefType.v("java.lang.String");
private static final RefType ERROR_TYPE = RefType.v("java.lang.Error");
/**
* Given an error message and a method body, constructs stmts necessary for throwing a Runtime Exception.
* @param errMsg the error message
* @param body the body from which the exception will be thrown
* @return the statements that will throw the runtime exception when executed
*/
public List<Stmt> runtimeException(String errMsg, Body body) {
List<Stmt> stmts = new LinkedList<>();
LocalGenerator lg = new LocalGenerator(body);
Local exceptionLocal = lg.generateLocal(ERROR_TYPE);
stmts.add(
Jimple.v().newAssignStmt(
exceptionLocal,
Jimple.v().newNewExpr(ERROR_TYPE)
)
);
SootMethodRef exceptionInit = ERROR_TYPE.getSootClass().getMethod("<init>", Collections.singletonList((Type)STRING_TYPE)).makeRef();
stmts.add(
Jimple.v().newInvokeStmt(
Jimple.v().newSpecialInvokeExpr(
exceptionLocal,
exceptionInit,
StringConstant.v(errMsg)
)
)
);
stmts.add(Jimple.v().newThrowStmt(exceptionLocal));
return stmts;
}
基于找到的示例here。
我试着像这样使用它:
Stmt stmt = ...;
List<Stmt> stmts = new LinkedList<>();
Local dataLocal;
boolean DEBUG_VERIFY_DATA_NOT_NULL = True;
//... (fill ``stmts`` with statements to insert after ``stmt``)
UnitBox errorSkipBox;
Stmt skipTarget;
if(DEBUG_VERIFY_DATA_NOT_NULL) {
String errMsg = "data is null but shouldn't be";
errorSkipBox = Jimple.v().newStmtBox(null);
stmts.add(
Jimple.v().newAssignStmt(
dataLocal,
Jimple.v().newInstanceFieldRef(thisRef,dataField.makeRef())
)
);
stmts.add(
Jimple.v().newIfStmt(
Jimple.v().newNeExpr(
dataLocal,
NullConstant.v()
),
errorSkipBox
)
);
stmts.addAll(SootUtil.v().runtimeException(errMsg,body));
skipTarget = Jimple.v().newNopStmt();
stmts.add(skipTarget);
}
units.insertAfter(stmts,stmt);
if (DEBUG_VERIFY_DATA_NOT_NULL){
errorSkipBox.setUnit(skipTarget);
}
现在的问题是......没有抛出任何异常。
既不是这样,也不是我用newNeExpr
替换newEqExpr
,也不是完全删除if-check。
那么抛出这个异常的正确方法是什么?
更新
生成的支票代码示例(如果我从newEqExpr
中提出newNeExpr
,ifnonnull
将更改为ifnull
):
parc.MyClass(parc.lang.Class<? extends T>, boolean, java.lang.String, java.lang.String...);
descriptor: (Lparc/some/Thing;Lparc/lang/Class;ZLjava/lang/String;[Ljava/lang/String;)V
flags: ACC_VARARGS
Code:
stack=2, locals=7, args_size=6
0: new #43 // class parc/lang/Data
3: astore 6
5: aload_0
6: invokespecial #46 // Method java/lang/Object."<init>":()V
9: aload_0
10: aload 6
12: putfield #48 // Field data:Lparc/lang/Data;
15: aload_0
16: getfield #48 // Field data:Lparc/lang/Data;
19: astore 6
21: aload 6
23: ifnonnull 41
26: new #50 // class java/lang/Error
29: astore 6
31: aload 6
33: ldc #52 // String data is null but shouldn't be
35: invokespecial #55 // Method java/lang/Error."<init>":(Ljava/lang/String;)V
38: aload 6
40: athrow
41: nop
// ...
93: return
LineNumberTable:
line 19: 5
line 20: 50
line 21: 55
line 22: 60
line 23: 66
line 23: 73
line 23: 80
line 23: 87
line 24: 93
StackMapTable: number_of_entries = 1
frame_type = 255 /* full_frame */
offset_delta = 41
locals = [ class parc/MyClass, class parc/some/Thing, class parc/lang/Class, int, class java/lang/String, class "[Ljava/lang/String;", class parc/lang/Data ]
stack = []
Signature: #276 // (Lparc/lang/Class<+TT;>;ZLjava/lang/String;[Ljava/lang/String;)V