博客

  • for douban

    doubanclaim016a1cb97bb3d39b

  • 一个VARIANT引发的bug

    昨天一位同事跟领导讨论过程中提到,他认为微软Visual c++6.0编译器的最大优化有bug。因为以前没有使用最大优化的时候代码没有问题,把project setting改成最大优化以后就出现bug了。

    因为这个max speed optimization设置修改是我提出来的,所以感觉有必要看看原因到底是什么。因为我是不相信这种“微软编译器优化能导致接口调用出错”的说法,往往此类问题就出在我们自己的代码上面。

    在这个同事的电脑上重现了一下这个问题,然后回到我自己电脑上,果然也可以重现,这就有点意思了。

    在代码中加入断点,发现是某个接口函数调用失败,这也是那个同事所谓的“最大速度优化导致接口调用失败”说法的起源,不过我相信,这之前的代码一定已经有问题了。

    查看运行时的调用栈,在几个相关函数加入log信息,然后跑了一遍错误的情况(setting为最大优化),再跑一次结果正确的情况(setting为不优化)。然后使用winmerge比较两次log的文本,发现它们俩有不同的输入参数。

    为何同样的代码,只是修改了project setting就有不同的结果呢?难道真的是VC++出了问题被我这个同事抓到bug?

    我又跑了几次错误的情况,发现输入参数字符串的最后一部分是随机变化的(正常情况应该是不变的)。我记起一种可能性,当我们使用最大优化的时候,某些没有初始化的变量会有这种可能。

    从调用栈上溯,发现这个参数是来自另外一个接口,它的调用方式类似这样:

    CComVariant var;
    p->GetAddr(&var);
    CString str.Format("aaaa %d", var.uiVal);

    uiVal的定义是unsigned short,也就是一个2Bytes数据,可是查看GetAddr()这个函数,里面代码类似这样:

    HRESULT CAaaa::GetAddr(VARIANT* pVar)
    {      
         CComVariant var(m_addr); // 这里的m_addr的声明是BYTE m_addr;
         return var.Detach(pVar);
    }

    好像能抓到一些问题的原因了。我们查看VARIANT的定义可以发现它内部包含了一个union,里面有BYTE bVal;有unsigned short uiVal;有unsigned long ulVal;

    OK,原因很清楚了。我们在GetAddr中赋值的时候,只(使用)设置了VARIANT的联合中1个BYTE的数据,而我们在后面的代码里使用uiVal形式,实际上读取了2个BYTE,高位部分的数据是无效的。通过观察随机数的16进制格式也可以发现,正确数据应该为0x00,我们得到的错误结果都是0x5800,0x6300,0xCC00这样的。

    知道了问题的原因该如何修改呢?有两种办法,一个是在结果中也是使用bVal,这是最好的办法。另外,如果要使用比赋值时数据长度更宽的类型,一定要通过var.ChangeType(VT_UI2);这样的类型转换,保证高位部分数据有效。

    改完了这部分代码,程序在最大优化的设置下一样运行正确,根本就不是什么设置导致的问题,就是代码有问题。

    另外非常需要注意的是,这种bug跟优化不优化没有任何联系,而是跟CComVariant以及VARIANT这种复杂数据结构里面的union有关系,CComVariant好像没有对VARIANT的数值成员做清零操作,而是调用了VariantInit()。使用union的时候都需要注意类似的情况。

    我构造了一个test case可以在不设置最大优化的情况下一样出现类似问题。如果认为这是“最大速度优化导致接口调用失败”,只是看到了一种表象,真正的原因离着远呢。

  • Lua源代码阅读分析问题列表

    我个人的习惯是带着问题去研究一个新题目,比如这次阅读Lua代码,暂列下面这些问题。

    1)什么是基于栈、基于寄存器的虚拟机(VM)设计?Lua如何实现基于寄存器的设计?

    2)Lua如何解析一段代码,生成中间代码?

    3)Lua如何使用VM运行中间代码?

    4)Lua如何实现GC机制?

    5)ipairs与pairs的不同(这是前几天写代码时发现的)?

    6)Lua如何实现闭包功能?

    7)Lua如何实现协程功能?

    8)Lua与c语言交互时栈的变化?

    9)如何为Lua增加一个continue关键字?

    10)Lua代码中常用的C语言编程技巧有那些?

    11)table如何实现的?

    12)如何实现的hook机制?

    13)如何实现的debug机制?

    暂列这些,以后再添。

  • Implement Object-Oriented in Lua

    Lua is not a Object-Oriented language. If we want to use concepts like “class, constructor, desctructor, member function”, we must use table or metatable to simulate.

    <Programming In Lua> introduces a method to implement OO in lua. http://www.lua.org/pil/16.html

    (更多…)

  • 前一阵的一些胶片

    92140037

    92140036

    92140035

    92140027

    92140014

    92140011

    92140009

    92140005

    照片已经说明一切。

    奥林巴斯mju2+sunny100。这个胶卷的效果非常惊人,出片率相当高,值得再买一些。