wine的bugzilla上有这么一个关于wine的bug:
Bug 27468 - QQ International crashes on attempted login
http://bugs.winehq.org/show_bug.cgi?id=27468
这个bug其实很多中文用户遇到过的,就是wine QQ鼠标一点击密码窗口就崩溃.
这个bug在现实中存在很久了,但是直到最近才有人去报.
( 题外话:实际上,很多中文用户特有的问题,也是存在很久却一直没有人去报告, 大部分中文用户的报bug意识不强 )
当我想重现这个bug的时候,一开始却怎么也重现不了,
让我怀疑报bug的人是不是做了不该做的事情(比如用winetricks装了native的dll)却没有写清楚
一个偶然的机会, 我第一次重现了这个bug.
当时我在测试多个不同的wine版本,包括 Ubuntu中的wine 1.3.37, Ubuntu中的wine 1.4-rc1,
以及我自己编译的多个介于1.3.37和1.4-rc1的wine版本.
我发现,在以上的某些版本中, 我可以重现这个bug.
只要能重现bug,就已经成功了一半.
这时候,关键是要找出重现的 *模式*
有两种完美的模式:
一种是bug只在新版本的wine中能重现, 而在老版本中不会出现, 这时候, 我们可以通过二分查找找到第一个引起bug的版本,定位到关键的补丁.
对于这种情况, git的bisect命令是一个强大的帮手, 专门用来做regression测试.
另一种模式是, bug只在ubuntu编译好的包中能重现, 而在自己编译的包中不能重现, 这时候,就可以从ubuntu的打包脚步和参数中寻找思路.
不幸的是, 我当时观察到的情况, 不属于以上两种模式, 而是几乎随机的.
到这一步, 我解决问题很大程度是靠运气的: 我偶然发现, 每当这个bug重现的时候, QQ主进程会崩溃, 而伴随的另一个进程会hang住不退出.
而只要有一个进程不退出, 进程依赖的动态库就不会被卸载. 这时候, 即使我重新安装wine, 新的动态库也不会被装载进去, 因为旧的同名的动态库没退出过.
在这种情况下, 测试的结果就不能准确反映问题了.
发现这点后, 我在每次测试完都运行 wineserver -k , 确保wine完全退出, 很快就从测试中观察到 *简单的模式* 了:
这个bug只在ubuntu的二进制包中存在, 在我自己编译的版本中不存在.
到这里, 就需要仔细研究ubuntu的二进制包和我自己编译的包有什么差别了.
可能有影响的差别,包括一些ubuntu特有的patch, ubuntu特有的配置文件,
ubuntu的preinstall/postinstall脚本, 以及ubuntu的wine二进制包所用的编译参数等.
具体的排查过程没必要详细记录下来, 都是一些枯燥的苦力活, 只有一点很重要, 就是任何时候 *二分查找* 的思想都能节省很多时间,
能二分的地方一定要二分, 不能二分创造条件也要二分 :)
排查的结论是, ubuntu的wine package用了gcc的 -O2 参数进行优化, 而我自己编译的包为了节省编译时间使用的是
-O0, 只要把我自己的编译参数改成 -O2就可以重现这个bug了.
有了这部分信息, 接下来就是对比-O2 和 -O0的区别了.
直接从崩溃的backtrace就可以定位到一个叫call_hook_proc的函数,
而具体的调试过程中则发现call_hook_proc这个函数在-O2优化编译的时候不见了.
到这里,才真正开始有必要读代码, 并且主要只需要读 dlls/user32/hook.c 这一个文件的局部代码.
在原bug链接中我给出了两种workaround的方法, 用来防止 call_hook_proc 被优化没了.
我目前所能做的大概就这些.
对于如何真正修复这个bug, 我目前还不是很懂, 如果有其他朋友有兴趣研究请指教 :)
我不确定的是, 这是 hook.c中的bug,还是gcc的bug, 还是winegcc的bug . 但是按照我的理解, 不管是哪种情况,
都不可能等到读完wine和gcc的所有的代码之后才开始hack.
上面的叙述没有穿插代码进去,所以不是很完整, 想完整知道问题来龙去脉的朋友可以先看一下原bug链接然后自己动手试一下:
http://bugs.winehq.org/show_bug.cgi?id=27468
从原bug链接中,也可以看到我从头到尾犯了不少错误, 庆幸的是别人指出我的错误让我学习到了很多东西.
这里也可以看出我鼓励别人多分享,多贡献,积极报bug或提交补丁的一个原因:
做这些事情免不了犯错,但是可以从错误中学习. 也希望有朋友继续指出我的错误 :)
--
Regards,
Qian Hong
-
Sent from Ubuntu
http://www.ubuntu.com/
wow!太厉害了,不得不佩服一下。
--
您收到此邮件是因为您订阅了 Google 网上论坛的“广州 GNU/Linux 用户组”论坛。
要向此网上论坛发帖,请发送电子邮件至 gz...@googlegroups.com。
要取消订阅此网上论坛,请发送电子邮件至 gzlug+un...@googlegroups.com。
若有更多问题,请通过 http://groups.google.com/group/gzlug?hl=zh-CN 访问此网上论坛。
原bug链接有workaround的方法, 昨晚写到这里的时候室友都要睡觉了, 补充一下:
方法一, 重新以 CFLAGS=-O0 编译;
方法二, 在call_hook函数中加入这么一行:
TRACE("call_hook_proc is %p\n", call_hook_proc);
然后重新编译
这样不管用什么优化级别, 都能保证 call_hook_proc这个函数不会丢失.
注意, 这两种方法都只是workaround, 不是fix. 完美的做法是给上游发补丁解决这个问题.
目前影响QQ使用的bug我能重现的有五个:
http://bugs.winehq.org/show_bug.cgi?id=27468
http://bugs.winehq.org/show_bug.cgi?id=29636
http://bugs.winehq.org/show_bug.cgi?id=29638
http://bugs.winehq.org/show_bug.cgi?id=29683
http://bugs.winehq.org/show_bug.cgi?id=16325
每一个bug中提到了相应的workaround方法. 有另一个需要自己修改代码和编译的bug, 是QQ状态自动切换为离开的问题.
除了这两个需要自己编译才能解决问题的bug, 其他三个分别是 riched20的问题, iexplore的问题 和 字体 的问题.
字体的问题可以到网上搜workaround, 不过这个问题有机会在最近几个月内解决.
剩下两个问题可以用 winetricks riched20 和 winetricks ie8 来workaround.
还是想说一下, 对于普通用户, bugzilla才是寻找解决问题方法的最终极地方, 很多bug都已经有人找到临时的解决方法了.
wine bugzilla中还有其他关于QQ的bug, 但是我重现不了.
--您收到此邮件是因为您订阅了 Google 网上论坛的“广州 GNU/Linux 用户组”论坛。
要向此网上论坛发帖,请发送电子邮件至 gz...@googlegroups.com。
要取消订阅此网上论坛,请发送电子邮件至 gzlug+un...@googlegroups.com。
若有更多问题,请通过 http://groups.google.com/group/gzlug?hl=zh-CN 访问此网上论坛。
在我看来,是gcc认为这个函数没有被使用,然后把他优化掉了。我现在没有条件调试,你可以试一下给这个函数加入如下的属性:
__attribute__ ((used))
看下gcc在O2的时候是否能保留他。
--
"""
Keep It Simple,Stupid.
"""
Chinese Name: 白杨
Nick Name: Hamo
Homepage: http://hamobai.com/
GPG KEY ID: 0xA4691A33
Key fingerprint = 09D5 2D78 8E2B 0995 CF8E 4331 33C4 3D24 A469 1A33
谢谢Hamo,好久不见 ^_^
加了 __attribute__ ((used)) 之后, 这个函数在 -O2 下编译仍然被保留, 在winedbg调试器中添加
call_hook_proc断点已经能成功找到这个函数, 在运行的时候也不会崩溃了.
这里我有一个问题搞不明白, 就是gcc把一个有用的函数优化没了, 是不是gcc的bug呢?
我英文也不好, 建议多报bug, 英文就慢慢进步了 :)
英文不好更要把学习Linux当作逼自己学习英文的机会.
> 这里我有一个问题搞不明白, 就是gcc把一个有用的函数优化没了, 是不是gcc的bug呢?
Gcc的优化,是基于它内部的一套引擎,来找出需要优化的地方。但是,既然是程序进行的,就肯定有不完美的地方。无用函数的消除,是说gcc自己分析了源代码,发现有些函数根本没有在代码中调用过。但是,它有一些情况是没考虑的,比如汇编代码中的调用,比如外部程序的调用。这不算一般意义上的bug,这只能算是现在gcc代码优化模型的缺陷。
>
> --
> Regards,
> Qian Hong
-O0, 只要把我自己的编译参数改成 -O2就可以重现这个bug了.
不能这样说,任何软件都是一个系统工程,总会遇到各种各样的bug,
并且这些bug可能由各种各样的原因引起。Debug本来就是一种非常讲究技巧的活动。从软件给出的蛛丝马迹中找到真正引起bug所对应的代码是非常需要经验和思考的。但是,找到bug之后的修复过程,则几乎是纯粹的语言和代码层面,为什么原来的代码会产生bug,怎么修复这个bug并且不或尽可能少的产生其他的问题,就需要对语言和代码以及像这个的编译器的工作原理要有清楚的理解。
谢谢, 我重新看了一下, 发现还不是我原来想的那么简单.
我做了个实验, 先确认一件事: 一个没有使用的static函数, 在gcc -O0 下不会被优化掉, 但在 gcc -O2 下会被优化没了.
这里所说的优化没了, 是指反汇编代码中完全不含有该函数, 包括这个函数的符号和这个函数内部的语句.
接下来, 我对比了O0和O2两种优化级别下, hook.o 中和call_hook_proc函数相关的汇编代码,
发现call_hook_proc这个符号虽然在O2下没了,但是call_hook_proc内部的语句依然存在,
只不过这些语句被嵌入到call_hook函数中了,因为call_hook函数是整个hook.c中唯一一个有机会调用call_hook_proc的函数
我把反汇编代码贴在这里:
http://paste.ubuntu.com/844711/
重新查看崩溃的backtrace, 我发现直接原因并不是调用一个不存在的函数, 而是访问一个不允许访问的内存地址 ( info=0x10 ,
info是指向结构体的指针)
backtrace在这里: http://paste.ubuntu.com/844685/
再次调试发现, 等价于 call_hook_proc的那段汇编代码曾经被调用过至少一次, 然后在第二次调用还是第三次调用后才发生崩溃的 (记不清了)
目前我还不能诊断出根本的问题在哪里. 有兴趣的朋友可以一起看看 :)
谢谢Hamo, 如果这个问题能研究出结果我就发个patch~ 不过最近Wine 1.4即将发布, 代码进入冻结期, 不会轻易接受补丁.
生病了, 睡觉去...
>
>> 这里我有一个问题搞不明白, 就是gcc把一个有用的函数优化没了, 是不是gcc的bug呢?
> Gcc的优化,是基于它内部的一套引擎,来找出需要优化的地方。但是,既然是程序进行的,就肯定有不完美的地方。无用函数的消除,是说gcc自己分析了源代码,发现有些函数根本没有在代码中调用过。但是,它有一些情况是没考虑的,比如汇编代码中的调用,比如外部程序的调用。这不算一般意义上的bug,这只能算是现在gcc代码优化模型的缺陷。
--
Regards,
Qian Hong
-
如果我的分享造成这样的误导,那就不是我的本意了.
我想传达的只是积极主动点去做就好了,不要顾虑太多.
至于技术方面,我的看法是, 不要去太多关注什么什么重要这样的问题, 这些问题可能太空泛, 想多了也不会带来进步,
我更推荐的方式是先动手去做,在做的过程中多思考多查资料, 在做完之后多总结, 这样可以总结出 "我学到了什么什么具体的技巧,
语言和代码方面又学到了什么什么具体的知识". 同样, 读别人的分享, 自己也可以总结一下 "学到了什么什么技巧和逻辑,
学到什么什么语言和代码", 但没有必要非得得出一个 "什么比什么更加重要" 的结论.
发现call_hook_proc这个符号虽然在O2下没了,但是call_hook_proc内部的语句依然存在,
只不过这些语句被嵌入到call_hook函数中了,因为call_hook函数是整个hook.c中唯一一个有机会调用call_hook_proc的函数
重新查看崩溃的backtrace, 我发现直接原因并不是调用一个不存在的函数, 而是访问一个不允许访问的内存地址 ( info=0x10 ,
info是指向结构体的指针)
backtrace在这里: http://paste.ubuntu.com/844685/
--
您收到此邮件是因为您订阅了 Google 网上论坛的“广州 GNU/Linux 用户组”论坛。
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 gzlug+un...@googlegroups.com。
要向此网上论坛发帖,请发送电子邮件至 gz...@googlegroups.com。
通过以下网址访问此论坛:http://groups.google.com/group/gzlug?hl=zh-CN。
要查看更多选项,请访问 https://groups.google.com/groups/opt_out。
--
您收到此邮件是因为您订阅了 Google 网上论坛的“广州 GNU/Linux 用户组”论坛。
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 gzlug+un...@googlegroups.com。
要向此网上论坛发帖,请发送电子邮件至 gz...@googlegroups.com。
通过以下网址访问此论坛:http://groups.google.com/group/gzlug?hl=zh-CN。
要查看更多选项,请访问 https://groups.google.com/groups/opt_out。
--
您收到此邮件是因为您订阅了 Google 网上论坛的“广州 GNU/Linux 用户组”论坛。
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 gzlug+un...@googlegroups.com。
要向此网上论坛发帖,请发送电子邮件至 gz...@googlegroups.com。
通过以下网址访问此论坛:http://groups.google.com/group/gzlug?hl=zh-CN。
要查看更多选项,请访问 https://groups.google.com/groups/opt_out。
--
您收到此邮件是因为您订阅了 Google 网上论坛的“广州 GNU/Linux 用户组”论坛。
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 gzlug+un...@googlegroups.com。
要向此网上论坛发帖,请发送电子邮件至 gz...@googlegroups.com。
通过以下网址访问此论坛:http://groups.google.com/group/gzlug?hl=zh-CN。
要查看更多选项,请访问 https://groups.google.com/groups/opt_out。
大家好,挖一下坟。这个帖子是一年前发布的,相关的bug则是一年半前报告的:
http://bugs.winehq.org/show_bug.cgi?id=27468
(报bug的是一位在佛山教英语的外教。。。)
我刚刚发了邮件介绍两位认识,Bill Chen可以试试把他拉过来参加 gzlug 的线下聚会 :)
hiphen,说好的gzlug英语专场呢?
什么时候gzlug能够长期有两个以上的外国人参加现下聚会,估计外国人就会很快增多起来。。