Closed cgobel closed 1 year ago
Here, the function "contains" is broken. It references a local l4 but this local is never defined. During bytecode parsing it was defined but somehow it got optimised away by the framework. kotlin.collections.AbstractCollection.jimple.txt
If I compare it with Javas implementation (which seems to work) basically the equivalent assignment of
virtualinvoke l0.<java.util.AbstractCollection: java.util.Iterator iterator()>();
is missing.
Which version of SootUp do you use? Which version of the kotlin stdlib do you use? Or even better: can you extract&upload the .class file of kotlins AbstractCollection?
Having the same issue here!
I am using SootUp 1.1.2
to analyse https://repo1.maven.org/maven2/cn/hutool/hutool-db/5.7.18/hutool-db-5.7.18.jar.
Inside body of <cn.hutool.db.sql.SqlBuilder: cn.hutool.db.sql.SqlBuilder insert(cn.hutool.db.Entity,java.lang.String)>
tableName
is used but undefined.
source code
public SqlBuilder insert(Entity entity, String dialectName) {
// 验证
validateEntity(entity);
final boolean isOracle = DialectName.ORACLE.match(dialectName);// 对Oracle的特殊处理
final StringBuilder fieldsPart = new StringBuilder();
final StringBuilder placeHolder = new StringBuilder();
entity.forEach((field, value) -> {
if (StrUtil.isNotBlank(field)) {
if (fieldsPart.length() > 0) {
// 非第一个参数,追加逗号
fieldsPart.append(", ");
placeHolder.append(", ");
}
fieldsPart.append((null != wrapper) ? wrapper.wrap(field) : field);
if (isOracle && OracleDialect.isNextVal(value)) {
// Oracle的特殊自增键,通过字段名.nextval获得下一个值
placeHolder.append(value);
} else {
// 普通字段使用占位符
placeHolder.append("?");
this.paramValues.add(value);
}
}
});
// issue#1656@Github Phoenix兼容
if (DialectName.PHOENIX.match(dialectName)) {
sql.append("UPSERT INTO ");
} else {
sql.append("INSERT INTO ");
}
String tableName = entity.getTableName();
if (null != this.wrapper) {
// 包装表名 entity = wrapper.wrap(entity);
tableName = this.wrapper.wrap(tableName);
}
sql.append(tableName)
.append(" (").append(fieldsPart).append(") VALUES (")//
.append(placeHolder).append(")");
return this;
}
jimple representation
cn.hutool.db.Entity entity;
cn.hutool.db.sql.SqlBuilder this;
java.lang.String dialectName;
unknown $stack10, $stack11, $stack12, $stack13, $stack14, $stack15, $stack16, $stack17, $stack18, $stack19, $stack20, $stack21, $stack22, $stack23, $stack24, $stack25, $stack26, $stack27, $stack28, $stack29, $stack30, $stack31, $stack32, $stack33, $stack34, $stack35, $stack36, $stack37, $stack7, $stack8, $stack9, fieldsPart, isOracle, placeHolder, tableName;
this := @this: cn.hutool.db.sql.SqlBuilder;
entity := @parameter0: cn.hutool.db.Entity;
dialectName := @parameter1: java.lang.String;
staticinvoke <cn.hutool.db.sql.SqlBuilder: void validateEntity(cn.hutool.db.Entity)>(entity);
$stack7 = <cn.hutool.db.dialect.DialectName: cn.hutool.db.dialect.DialectName ORACLE>;
isOracle = virtualinvoke $stack7.<cn.hutool.db.dialect.DialectName: boolean match(java.lang.String)>(dialectName);
$stack8 = new java.lang.StringBuilder;
specialinvoke $stack8.<java.lang.StringBuilder: void <init>()>();
fieldsPart = $stack8;
$stack9 = new java.lang.StringBuilder;
specialinvoke $stack9.<java.lang.StringBuilder: void <init>()>();
placeHolder = $stack9;
$stack10 = dynamicinvoke accept <java.util.function.BiConsumer (cn.hutool.db.sql.SqlBuilder,java.lang.StringBuilder,java.lang.StringBuilder,boolean)>(this, fieldsPart, placeHolder, isOracle) <java.lang.invoke.LambdaMetafactory: java.lang.invoke.CallSite metafactory(java.lang.invoke.MethodHandles$Lookup,java.lang.String,java.lang.invoke.MethodType,java.lang.invoke.MethodType,java.lang.invoke.MethodHandle,java.lang.invoke.MethodType)>(methodtype: void __METHODTYPE__(java.lang.Object,java.lang.Object), handle: <cn.hutool.db.sql.SqlBuilder: void lambda$insert$0(java.lang.StringBuilder,java.lang.StringBuilder,boolean,java.lang.String,java.lang.Object)>, methodtype: void __METHODTYPE__(java.lang.String,java.lang.Object));
virtualinvoke entity.<cn.hutool.db.Entity: void forEach(java.util.function.BiConsumer)>($stack10);
$stack11 = <cn.hutool.db.dialect.DialectName: cn.hutool.db.dialect.DialectName PHOENIX>;
$stack12 = virtualinvoke $stack11.<cn.hutool.db.dialect.DialectName: boolean match(java.lang.String)>(dialectName);
if $stack12 == 0 goto label1;
$stack32 = this.<cn.hutool.db.sql.SqlBuilder: java.lang.StringBuilder sql>;
$stack33 = virtualinvoke $stack32.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>("UPSERT INTO ");
goto label2;
label1:
$stack13 = this.<cn.hutool.db.sql.SqlBuilder: java.lang.StringBuilder sql>;
$stack14 = virtualinvoke $stack13.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>("INSERT INTO ");
label2:
$stack34 = entity;
$stack35 = virtualinvoke entity.<cn.hutool.db.Entity: java.lang.String getTableName()>();
$stack37 = null;
$stack36 = this;
$stack15 = this.<cn.hutool.db.sql.SqlBuilder: cn.hutool.db.sql.Wrapper wrapper>;
if $stack37 == $stack15 goto label3;
$stack23 = this.<cn.hutool.db.sql.SqlBuilder: cn.hutool.db.sql.Wrapper wrapper>;
tableName = virtualinvoke $stack23.<cn.hutool.db.sql.Wrapper: java.lang.String wrap(java.lang.String)>(tableName);
label3:
$stack24 = this;
$stack16 = this.<cn.hutool.db.sql.SqlBuilder: java.lang.StringBuilder sql>;
$stack25 = tableName;
$stack17 = virtualinvoke $stack16.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>($stack25);
$stack26 = " (";
$stack18 = virtualinvoke $stack17.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>($stack26);
$stack27 = fieldsPart;
$stack19 = virtualinvoke $stack18.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.CharSequence)>($stack27);
$stack28 = ") VALUES (";
$stack20 = virtualinvoke $stack19.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>($stack28);
$stack29 = placeHolder;
$stack21 = virtualinvoke $stack20.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.CharSequence)>($stack29);
$stack30 = ")";
$stack22 = virtualinvoke $stack21.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>($stack30);
$stack31 = this;
return $stack31;
possible duplicate of #698? ( both fail in context of a virtualinvoke)
Hi @Liyw979, please share your SootUp setup so we can investigate this issue better.
Thank you @swissiety . It's strange that I am having different jimple output in my current machine. I will check tomorrow. Is the following jimple output the same as yours?
{
cn.hutool.db.Entity entity;
cn.hutool.db.sql.SqlBuilder this;
java.lang.String dialectName;
unknown $stack11, $stack12, $stack13, $stack14, $stack15, $stack16, $stack17, $stack18, $stack19, $stack20, $stack21, $stack22, $stack23, $stack24, $stack25, $stack26, $stack27, $stack28, $stack29, $stack30, $stack31, $stack32, $stack33, $stack34, $stack35, $stack36, $stack37, $stack38, $stack39, $stack40, $stack41, $stack42, $stack43, $stack44, $stack45, $stack46, $stack47, $stack48, $stack49, $stack50, $stack51, $stack52, $stack53, $stack54, $stack55, $stack56, $stack57, $stack58, $stack59, $stack60, $stack61, $stack62, $stack63, $stack64, $stack65, $stack66, $stack67, $stack68, $stack69, $stack70, $stack71, $stack72, $stack73, $stack74, $stack75, $stack76, entry, field, fieldsPart, isFirst, isOracle, l9, placeHolder, value;
this := @this: cn.hutool.db.sql.SqlBuilder;
entity := @parameter0: cn.hutool.db.Entity;
dialectName := @parameter1: java.lang.String;
staticinvoke <cn.hutool.db.sql.SqlBuilder: void validateEntity(cn.hutool.db.Entity)>(entity);
$stack11 = this.<cn.hutool.db.sql.SqlBuilder: cn.hutool.db.sql.Wrapper wrapper>;
if null == $stack11 goto label01;
$stack68 = this.<cn.hutool.db.sql.SqlBuilder: cn.hutool.db.sql.Wrapper wrapper>;
$stack69 = virtualinvoke entity.<cn.hutool.db.Entity: java.lang.String getTableName()>();
$stack70 = virtualinvoke $stack68.<cn.hutool.db.sql.Wrapper: java.lang.String wrap(java.lang.String)>($stack69);
$stack71 = virtualinvoke entity.<cn.hutool.db.Entity: cn.hutool.db.Entity setTableName(java.lang.String)>($stack70);
label01:
$stack12 = <cn.hutool.db.dialect.DialectName: cn.hutool.db.dialect.DialectName ORACLE>;
$stack72 = dialectName;
$stack73 = virtualinvoke $stack12.<cn.hutool.db.dialect.DialectName: boolean match(java.lang.String)>(dialectName);
$stack13 = new java.lang.StringBuilder;
specialinvoke $stack13.<java.lang.StringBuilder: void <init>()>();
fieldsPart = $stack13;
$stack14 = new java.lang.StringBuilder;
specialinvoke $stack14.<java.lang.StringBuilder: void <init>()>();
placeHolder = $stack14;
$stack74 = 1;
isFirst = $stack74;
$stack75 = entity;
$stack15 = virtualinvoke $stack75.<cn.hutool.db.Entity: java.util.Set entrySet()>();
$stack76 = interfaceinvoke $stack15.<java.util.Set: java.util.Iterator iterator()>();
label02:
$stack42 = l9;
$stack16 = interfaceinvoke $stack42.<java.util.Iterator: boolean hasNext()>();
if $stack16 == 0 goto label09;
$stack39 = interfaceinvoke l9.<java.util.Iterator: java.lang.Object next()>();
entry = (java.util.Map$Entry) $stack39;
$stack40 = interfaceinvoke entry.<java.util.Map$Entry: java.lang.Object getKey()>();
field = (java.lang.String) $stack40;
value = interfaceinvoke entry.<java.util.Map$Entry: java.lang.Object getValue()>();
$stack41 = staticinvoke <cn.hutool.core.util.StrUtil: boolean isNotBlank(java.lang.CharSequence)>(field);
if $stack41 == 0 goto label08;
if isFirst == 0 goto label03;
isFirst = 0;
goto label04;
label03:
$stack43 = virtualinvoke fieldsPart.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>(", ");
$stack44 = virtualinvoke placeHolder.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>(", ");
label04:
$stack64 = this;
$stack45 = this.<cn.hutool.db.sql.SqlBuilder: java.util.List fields>;
$stack65 = field;
$stack46 = interfaceinvoke $stack45.<java.util.List: boolean add(java.lang.Object)>($stack65);
$stack62 = fieldsPart;
$stack67 = null;
$stack66 = this;
$stack47 = this.<cn.hutool.db.sql.SqlBuilder: cn.hutool.db.sql.Wrapper wrapper>;
if $stack67 == $stack47 goto label05;
$stack60 = this.<cn.hutool.db.sql.SqlBuilder: cn.hutool.db.sql.Wrapper wrapper>;
$stack61 = virtualinvoke $stack60.<cn.hutool.db.sql.Wrapper: java.lang.String wrap(java.lang.String)>(field);
goto label06;
label05:
$stack61 = field;
label06:
$stack48 = virtualinvoke $stack62.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>($stack61);
$stack63 = isOracle;
if $stack63 == 0 goto label07;
$stack52 = value instanceof java.lang.String;
if $stack52 == 0 goto label07;
$stack57 = (java.lang.String) value;
$stack58 = staticinvoke <cn.hutool.core.util.StrUtil: boolean endWithIgnoreCase(java.lang.CharSequence,java.lang.CharSequence)>($stack57, ".nextval");
if $stack58 == 0 goto label07;
$stack59 = virtualinvoke placeHolder.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.Object)>(value);
goto label08;
label07:
$stack54 = placeHolder;
$stack53 = "?";
$stack49 = virtualinvoke $stack54.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>($stack53);
$stack55 = this;
$stack50 = this.<cn.hutool.db.sql.SqlBuilder: java.util.List paramValues>;
$stack56 = value;
$stack51 = interfaceinvoke $stack50.<java.util.List: boolean add(java.lang.Object)>($stack56);
label08:
goto label02;
label09:
$stack17 = <cn.hutool.db.dialect.DialectName: cn.hutool.db.dialect.DialectName PHOENIX>;
$stack18 = virtualinvoke $stack17.<cn.hutool.db.dialect.DialectName: boolean match(java.lang.String)>(dialectName);
if $stack18 == 0 goto label10;
$stack29 = this.<cn.hutool.db.sql.SqlBuilder: java.lang.StringBuilder sql>;
$stack30 = virtualinvoke $stack29.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>("UPSERT INTO ");
goto label11;
label10:
$stack19 = this.<cn.hutool.db.sql.SqlBuilder: java.lang.StringBuilder sql>;
$stack20 = virtualinvoke $stack19.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>("INSERT INTO ");
label11:
$stack31 = this;
$stack21 = this.<cn.hutool.db.sql.SqlBuilder: java.lang.StringBuilder sql>;
$stack32 = entity;
$stack22 = virtualinvoke $stack32.<cn.hutool.db.Entity: java.lang.String getTableName()>();
$stack23 = virtualinvoke $stack21.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>($stack22);
$stack33 = " (";
$stack24 = virtualinvoke $stack23.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>($stack33);
$stack34 = fieldsPart;
$stack25 = virtualinvoke $stack24.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.CharSequence)>($stack34);
$stack35 = ") VALUES (";
$stack26 = virtualinvoke $stack25.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>($stack35);
$stack36 = placeHolder;
$stack27 = virtualinvoke $stack26.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.CharSequence)>($stack36);
$stack37 = ")";
$stack28 = virtualinvoke $stack27.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>($stack37);
$stack38 = this;
return $stack38;
}
maven
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>java-tmp</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.core</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.java.core</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.java.sourcecode</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.java.bytecode</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.jimple.parser</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.callgraph</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.analysis</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
main method
public class Main {
public static void main(String[] args) {
AnalysisInputLocation<JavaSootClass> inputLocation = new JavaClassPathAnalysisInputLocation("/Users/liyw/Downloads/hutool-db-5.7.18.jar");
JavaLanguage language = new JavaLanguage(8);
Project<JavaSootClass, JavaView> project = JavaProject.builder(language).addInputLocation(inputLocation).build();
JavaView view = project.createView();
MethodSignature sig = view.getIdentifierFactory().getMethodSignature("insert", "cn.hutool.db.sql.SqlBuilder", "cn.hutool.db.sql.SqlBuilder", List.of("cn.hutool.db.Entity", "java.lang.String"));
SootMethod method = view.getMethod(sig).get();
System.out.println(method);
System.out.println(method.getBody());
}
}
Thats exactly why I asked for your setup ;) Im currently on my Phone and can't check it in Detail but the Label numbering looks similar. it would be interesting to know why its different.. the other described Situation with the missing password Local assignment occured.
reproduced with maven
<dependencies>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.core</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.java.core</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.java.sourcecode</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.java.bytecode</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.jimple.parser</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.callgraph</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.analysis</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
java
public class Main {
public static void main(String[] args) {
AnalysisInputLocation<JavaSootClass> inputLocation = new JavaClassPathAnalysisInputLocation("D:\\code_sample\\hutool-db-jar2");
JavaLanguage language = new JavaLanguage(8);
Project<JavaSootClass, JavaView> project = JavaProject.builder(language)
.addInputLocation(inputLocation)
.build();
JavaView view = project.createView();
MethodSignature sig = view.getIdentifierFactory()
.getMethodSignature("<init>", "cn.hutool.db.ds.pooled.PooledConnection", "void", List.of("cn.hutool.db.ds.pooled.PooledDataSource"));
SootMethod method = view.getMethod(sig).get();
System.out.println(method);
System.out.println(method.getBody());
}
}
jimple representation of <cn.hutool.db.ds.pooled.PooledConnection: void <init>(cn.hutool.db.ds.pooled.PooledDataSource)>
{
cn.hutool.db.ds.pooled.PooledConnection this;
cn.hutool.db.ds.pooled.PooledDataSource ds;
unknown $stack10, $stack11, $stack12, $stack13, $stack14, $stack15, $stack16, $stack17, $stack18, $stack19, $stack20, $stack21, $stack7, $stack8, $stack9, config, connProps, info, password, user;
this := @this: cn.hutool.db.ds.pooled.PooledConnection;
ds := @parameter0: cn.hutool.db.ds.pooled.PooledDataSource;
specialinvoke this.<cn.hutool.db.ds.pooled.ConnectionWraper: void <init>()>();
this.<cn.hutool.db.ds.pooled.PooledConnection: cn.hutool.db.ds.pooled.PooledDataSource ds> = ds;
config = virtualinvoke ds.<cn.hutool.db.ds.pooled.PooledDataSource: cn.hutool.db.ds.pooled.DbConfig getConfig()>();
$stack7 = new cn.hutool.setting.dialect.Props;
specialinvoke $stack7.<cn.hutool.setting.dialect.Props: void <init>()>();
info = $stack7;
user = virtualinvoke config.<cn.hutool.db.ds.pooled.DbConfig: java.lang.String getUser()>();
if user == null goto label1;
$stack18 = virtualinvoke info.<cn.hutool.setting.dialect.Props: java.lang.Object setProperty(java.lang.String,java.lang.String)>("user", user);
label1:
$stack19 = config;
$stack20 = virtualinvoke config.<cn.hutool.db.ds.pooled.DbConfig: java.lang.String getPass()>();
$stack21 = password;
if $stack21 == null goto label2;
$stack14 = virtualinvoke info.<cn.hutool.setting.dialect.Props: java.lang.Object setProperty(java.lang.String,java.lang.String)>("password", password);
label2:
$stack15 = config;
$stack16 = virtualinvoke config.<cn.hutool.db.ds.pooled.DbConfig: java.util.Properties getConnProps()>();
$stack17 = connProps;
$stack8 = staticinvoke <cn.hutool.core.map.MapUtil: boolean isNotEmpty(java.util.Map)>($stack17);
if $stack8 == 0 goto label3;
virtualinvoke info.<cn.hutool.setting.dialect.Props: void putAll(java.util.Map)>(connProps);
label3:
$stack13 = this;
$stack11 = config;
$stack9 = virtualinvoke $stack11.<cn.hutool.db.ds.pooled.DbConfig: java.lang.String getUrl()>();
$stack12 = info;
$stack10 = staticinvoke <java.sql.DriverManager: java.sql.Connection getConnection(java.lang.String,java.util.Properties)>($stack9, $stack12);
this.<cn.hutool.db.ds.pooled.PooledConnection: java.sql.Connection raw> = $stack10;
return;
}
inside <cn.hutool.db.ds.pooled.PooledConnection: void <init>(cn.hutool.db.ds.pooled.PooledDataSource)>
password
and connProps
are undefined.
I have a problem converting kotlin.collections.AbstractCollection to Jimple. Unfortunately, the contains() method is translated in a version where a local is accessed but never defined due to some internal updates made on the stack and local variables during parsing. The definition statement for this local is replaced by nothing during parsing but other statements that use this local stay unchanged.