吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4096|回复: 3
收起左侧

[Android 分享] 【转】让人纠结的finally

  [复制链接]
ThomasKing 发表于 2014-7-7 19:33
最近分析某一apk,被其中的各种try-catch-finally块虐得死去活来,有木有。。。
由于喜欢刨根,各种谷歌都没有给出解释。 一番研究之后,发现确实有些蹊跷。(本人水平有限,不喜勿喷,谢谢)

切入正题:
try{}catch反编译后,格式:   
    eg: .catch Ljava/io/FileNotFoundException; {:try_start_0 .. :try_end_0} :catch_0
加上finally,那就多一行声明:
   eg: .catchall {:try_start_0 .. :try_end_0} :catchall_0
大家都知道,finally块中的代码始终都要执行,那么是不是类似goto到finally块中去执行代码呢? 可惜不是,是直接复制了3份。
比如:
  try {
    FileInputStream stream = new FileInputStream(new File("/mnt/sdcard/test.txt"));
  } catch (FileNotFoundException e) {
    e.printStackTrace();
  }finally{
    System.out.println("Fin");
  }
smali:
:try_start_0
    new-instance v1, Ljava/io/FileInputStream;

    new-instance v2, Ljava/io/File;

    const-string v3, "/mnt/sdcard/test.txt"

    invoke-direct {v2, v3}, Ljava/io/File;-><init>(Ljava/lang/String;)V

    invoke-direct {v1, v2}, Ljava/io/FileInputStream;-><init>(Ljava/io/File;)V
    :try_end_0
    .catchall {:try_start_0 .. :try_end_0} :catchall_0
    .catch Ljava/io/FileNotFoundException; {:try_start_0 .. :try_end_0} :catch_0

    .line 28
    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;

    const-string v2, "Fin"

    invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V


    .line 30
    :goto_0
    return-void

    .line 24
    :catch_0
    move-exception v0

    .line 26
    .local v0, e:Ljava/io/FileNotFoundException;
    :try_start_1
    invoke-virtual {v0}, Ljava/io/FileNotFoundException;->printStackTrace()V
    :try_end_1
    .catchall {:try_start_1 .. :try_end_1} :catchall_0

    .line 28
    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;

    const-string v2, "Fin"

    invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

    goto :goto_0

    .line 27
    .end local v0           #e:Ljava/io/FileNotFoundException;

    :catchall_0
    move-exception v1

    .line 28
    sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;

    const-string v3, "Fin"

    invoke-virtual {v2, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

    .line 29
    throw v1

(由于黄色看不清,这里修改为红色)

不难发现,正常执行流程和catch块中增加了finally中的代码,而且二者是同一个出口。(goto_0)
那黄色(第三块红色)那块是什么???
经过多次测试,只要catch块中调用了函数,就会隐式生成一个try,且只有.catchall
:try_start_1
    invoke-virtual {v0}, Ljava/io/FileNotFoundException;->printStackTrace()V
:try_end_1
.catchall {:try_start_1 .. :try_end_1} :catchall_0

catchall_n一般结构是:
move-exception vm
......
throw vm

另外,经过多次动态调试smali,都没有出现程序进入.catchall_n模块。估计是没有构造出相应的触发条件。由于运行时异常不需要显式声明,猜测可能运行时异常触发。故构造一下代码:
  public void fun(int flag) throws IllegalArgumentException
  {
    switch(flag){
      case 1: throw new IllegalArgumentException();
      case 2: throw new RuntimeException();
      default: break;
    }
  }
  public void Test(int flag)
  {
    try {
      fun(flag);   
      foo();
    } catch (Exception e) {
      foo();
    }finally{
      Log.i("Finally", "Exit");
    }
  }
  public void foo(){
    throw new RuntimeException();
  }
由于Log.i("Finally", "Exit");会被拷贝三份,故修改.catall中的输出,进行区别。具体如下:
    :catchall_1a
    move-exception v1

    .line 39
    const-string v2, "Finally"

    const-string v3, "Exit_Finally"
修改"Exit"为"Exit_Finally"

    invoke-static {v2, v3}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I

    .line 40
    throw v1
onCreate分别测试调用Test(0)和Test(1),均打印出"Exit_Finally",并未打印出"Exit"。


这下终于明白了.catchall的作用,确实保证了finally块中的代码一定会被执行。

PS:要是多重try-catch-finally嵌套,而且finally块中有很多代码,那就。。。 万恶的finally块,虐了我千百遍。。。                                                                       

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

fishyoyo 发表于 2014-7-7 19:41
不明觉厉 围观大神
453100956 发表于 2014-7-8 14:22 来自手机
大爱如花和似玉 发表于 2014-7-10 02:40
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 11:30

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表