• 记一次调试


    这是我最近几个月来遇到的最棘手的一个问题:
    * 昨天花了4个小时找出第一层次的原因
    这个纠结啊,本来和老婆说好准时下班回家吃饭的,结果被这个问题拖了老久。

    这是一个gradle的plugin,用来resolve公司内部的dependency的,弄完了跑测试项目的,抛一个NPE,而且NPE还不在自己的代码里面。好吧,把gradle的源代码翻出来看,如果是自己传进去的一个值是null,解决起来也还ok了。结果到里面一看,那是一个loop里面,迭代map的时候出的错 - 可以算是NPE中的最坏情况了把。仔细查看一下代码,好吧,是迭代环境变量的。那行,在自己的代码里把环境变量都打出来谁是null吧。结果全ok,看来是顺序问题,在我打出来的时候,那个null的还是设上呢。既然是环境变量被设,那就在自己的代码里搜搜看有没有可疑点吧,还真找到个地方,一print还是真是在那个地方把PATH设成了null。

    照理犯罪现场找到了,解决也就三下两下的事了,于是我打算解决完,发完code review再走。结果发现那个null是被这么设上的:
    env_path = plugin_ext.getCompileTimeJNI(jniPaths)

    这是groovy语言,plugin_ext是一个gradle的plugin的extension,getCompileTimeJNI是定义在extension中的一个closure,我死活检查getCompileTimeJNI,他也绝对不可能返回null,如果有exception的话,也应该抛出来,而不是返回null。

    仔细检查代码,理清逻辑,打印结果,还是毫无头绪,无奈已经7:30多了,还是先回去吧。

    * 今天早上大概也两个小时吧,找出的根本原因
    周六早上起来, 多少还惦记着这件事,再看看吧。
    终于,在观察打印出来的结果时,我注意到一个细节:在打印plugin_ext.getCompileTimeJNI的时候:
    第一次是closure的地址
    然后调用closure:plugin_ext.getCompileTimeJNI(jniPaths)
    第二次就是一个Set了

    这说明这个closure的调用有点蹊跷,我已经检查过了closure的实现本身没有问题,那么问题就在这简简单单的一句closure的调用上。 这花了我很长的时间去发现并相信着其实不是一个函数调用,而是一个赋值:
    plugin_ext.getCompileTimeJNI(jniPaths)
    就是
    plugin_ext.getCompileTimeJNI = jniPaths
    我不知道为什么gradle要发明这么坑爹的语法 - 这绝对是编码质量与效率的杀手,但是不管怎样,根源问题是找到了:
    env_path = plugin_ext.getCompileTimeJNI(jniPaths)
    这个赋值语句永远返回null

    * 暂时有了一个workaround,还没有比较official的解决方案(if there is one)
    你当然可以plugin_ext.getCompileTimeJNI,call,这是这改变了原有api的调用方式,是个breaking change,而且巨丑无比。

    我觉得这是设计有点问题,也在咨询gradle官方:http://forums.gradle.org/gradle/topics/call_plugin_extension_property_becomes_an_assignment

    目前的workaround,还是基于gradle对extension的奇葩设计:
    * 如果你的closure是定义在extension里面的,调用即赋值,挂
    * 如果你的closure没在extension定义中,而是在后面使用时加上去的,调用还是调用,ok
    所有workaround就是把getCompileTimeJNI移出extension的定义,在外面加。

  • 相关阅读:
    单例模式及C++实现代码
    Nginx学习笔记4 源码分析
    探讨C++ 变量生命周期、栈分配方式、类内存布局、Debug和Release程序的区别2
    SVM学习资料
    11 款最好 CSS 框架
    发布Activex全过程
    Integer.parseInt(String s, int radix)方法介绍(修正版)
    Windows 各种计时函数总结(QueryPerformanceCounter可以达到微秒)
    不断摸索发现用 andy 模拟器很不错,感觉跟真机差不多
    Qt中提高sqlite的读写速度(使用事务一次性写入100万条数据)
  • 原文地址:https://www.cnblogs.com/baiyanhuang/p/3813469.html
Copyright © 2020-2023  润新知