升级2005SP1引起的问题

前两天下了份chrome的源代想编译来看看。根据它的构建指引先要把VS2005升级到SP1。如是花了一下午替机器上的VS2005打了SP1,中途因开的东西太多,磁盘空间不够,失败了两次,第三次才打成功。

第二天要调一个服务器程序上的bug,如是我在本机build了一个服务器程序,上传到外网一跑,崩了。偶滴个神,最最可怕的事情发生了。

赶快查原因,因为没怎么动代码,我用debug的工具定位了一下很快找到了原因。

原来打了VS2005的SP1补丁以后,居然连VC runtime的那三个dll的版本也升级了。这样我新编译出来的服务器程序用到了新的runtime,而服务器程序依赖的ACE动态链接库是在没打SP1之前编译的,用的是老的runtime。

本来这也是可以相安无事的,大家都在不同的模块中嘛。偏偏服务器代码中调用了一个ACE的函数,函数需要传进去一个指针的引用,ACE内部会在堆上分配空间,再用这个指针带出去,而且该函数的文档上标明,调用者要负责detele这个指针指向的内存。因为服务器程序和ACE动态链接库使用的是不同的两个runtime,而堆是由runtime维护的。这样在调用者去delete那个指针指向的空间时,悲剧就发生了。

原因是找到了,但是要解决起来就没这么容易了。照理我只要把ACE也用打了SP1的VS2005重build一次就OK了,可是服务端是和客户端是共用同一个ACE动态链接库的,而且这个ACE是经过定制编译的。这样子的话,客户端的程序也要用打了SP1的VS2005来重build一下。问题是客户端还包括了一些钩子DLL,还有一部分是用驱动实现的,这些是不是也要全部重build。Oh no!万一重build后出现什么灵异问题怎么办?不敢想象。

我们的客户端的所有组成部分都是在一台公用的build机上构建的,这样可以保持环境单一。可偏偏就是服务器端,由于环境配置复杂(主要是用到了oracle的数据库),又只有我一个人开发,所以一直在我的机器上build。唉,要是全部统一build也不会出这样的悲剧了。

最后,木有办法,只能把我本机的VS2005卸载,然后重装,去掉这个邪恶的SP1,一切恢复正常。只是又浪费了我一天的工夫,由此得出以下重要的经验教训。

1、升级开发环境之前一定要了解下升级包的具体改动有哪些,会不会对开发工作造成大的影响。

2、所有相关的代码一定要统一构建。一定要,切记。让构建不受个别开发人员环境的影响。

3、内存的申请和释放要统一,由其是不要跨模块的边界。

这次违反第三点的是ACE的代码,至少它这个方法的实现不是太严谨。我以前也范过一次类似的错误。其实好的方法是让调用者申请内存,并把指向内存的指针传进来,这样内存的分配和释放都由调用者负责,即使调用跨了模块的边界。这样即使不同模块使用的是不同的runtime,也不会有问题。如果调用方无法确认要分配内存的大小,可以调两次,第一次用空指针,让被调方把需要申请的大小传出来。其实在windows api中很多地方使用了这种方式。

One Comment

  1. dongkai 说:

    呵呵,又学到了,以后我也会注意这种情况。

Leave a Reply