soot-oss / SootUp

A new version of Soot with a completely overhauled architecture
https://soot-oss.github.io/SootUp/
GNU Lesser General Public License v2.1
586 stars 78 forks source link

AsmMethodSource produces code with undefined but used variables #631

Closed cgobel closed 1 year ago

cgobel commented 1 year ago

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.

cgobel commented 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

swissiety commented 1 year ago

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?

Liyw979 commented 1 year ago

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. image 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;
swissiety commented 1 year ago

possible duplicate of #698? ( both fail in context of a virtualinvoke)

swissiety commented 1 year ago

Hi @Liyw979, please share your SootUp setup so we can investigate this issue better.

Liyw979 commented 1 year ago

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());
    }
}
swissiety commented 1 year ago

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.

Liyw979 commented 1 year ago

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. image