VS2013 - C++碰到一个诡异的内存访问错误,很怀疑是 VS 的问题,要被逼疯了···求提点 T_T

2015-07-26 14:33:20 +08:00
 acros
先交代下环境吧。个人在做一个游戏的小功能(算是练习吧),用的cocos2d-x引擎,前些天从3.6版本升级到3.7(引擎内部好像有内存管理相关的改动),出现了一个奇怪的bug。
平台是win7 64 + VS 2013 community updater 5。 工程target都是x86 machine

下午再去xcode下搭建一个试试去,看看是不是ide的问题。

就是这个
https://github.com/acros/cocos2dx_qte

问题是这样的:
cocos2d-x里有个类叫Scene,我派生了class MainGameScene : public Scene,派生类中成员变量就加了两个RefPtr指针mUiLayer和mGameLayer。(注:RefPtr是cocos2d-x一个轻量级的shared_ptr类似存在)

通过VS的工具输出,确认Scene和MainGameScene的内存布局如下(这里就给出类末尾一段内容):
1> 708 | | _physicsWorld
1> 712 | | _navMesh
1> 716 | | _navMeshDebugCamera
1> | +---
1> 720 | ?$RefPtr@VLayer@cocos2d@@ mGameLayer
1> 724 | ?$RefPtr@VLayer@cocos2d@@ mUiLayer
1> +---

_navMesh和_navMeshDebugCamera是Scene类最后两个成员变量。
720偏移之前都是Scene的,这个表是正确的。

这个工程里面,cocos2d-x引擎部分是导出成一个dll的,然后主项目去加载它,MainGameScene这个类是在我自己的项目里面创建的。然而将一个指向MainGameScene的Scene*类型传到引擎代码中时,对于scene*内存的读取就发生了诡异的变化!
见下图:


可以看到:scene*的地址是0x060BBC88,加上前面计算的720偏移量,0x060BBF58地址应该是mGameLayer的地址,实际这时通过scene*访问到_navMesh变量时,取到的是mGameLayer地址!!!

图中下方窗口还可以看到,我加了个类型转换后再访问,地址就对了····>_<

(*((qte.exe!cocos2d::Scene*)(&(*((qte.exe!MainGameScene*)(scene))))))._navMesh
和&(scene)->_navMesh 取到的地址差 8 ??????

看起来虚表并没有被破坏掉,而且编译器计算类内成员offset时,这个offset怎么会算错,个人完全没头绪啊····(类成员地址不是类地址+offset计算的吗?)

注:scene*指针只在项目dll工程里面访问才会出现这个错误的偏移计算,我之前想过是不是项目配置错了,但问题是,什么东西配置错了会导致这种错误呢?!
2091 次点击
所在节点    C
26 条回复
jukka
2015-07-26 17:23:30 +08:00
show me your code.
XiXiLocked
2015-07-26 17:26:01 +08:00
你看直接读navMesh是有值的,但是指针转换之后读的navMesh是NULL,说明转的有问题
信口开河一把,
scene的内存布局是
scene::vptr
scene::members ...
MainGameScene的里面有并不继承于scene的虚函数,所以他的虚表插在了前面,于是布局大概是这样
scene:vptr
MainGameScene::vptr <--这里多了虚表指针的8
scene::members ...
MainGameScene::members ...
上面说的没有把握,但是你可以看看之前的成员变量的地址验证一下
acros
2015-07-26 17:39:13 +08:00
@jukka 上面git地址就是啊。
acros
2015-07-26 17:40:06 +08:00
@XiXiLocked
_navMesh应该是空的。mGaneLayer不是null
acros
2015-07-26 17:40:50 +08:00
@XiXiLocked 我去验证下..
finab
2015-07-26 17:56:03 +08:00
代码出问题
我从不怀疑编译器或IDE,肯定是我的问题!
就是这么自信 ~~~
fo2w
2015-07-26 18:04:52 +08:00
虽然说vs确实有bug, 但我不相信大多数人碰得到
Athrob
2015-07-26 18:07:04 +08:00
确定不是代码的问题?我相信vs
nozama
2015-07-26 18:56:03 +08:00
vs2012 bug像这种“明明是对的,结果就是不对”倒是遇到过几次,在2013和appcode都没问题。也有几次,是变量忘了初始化引起的bug,clang会自动初始化为0,VC却是随机值。
lcsky
2015-07-26 19:05:38 +08:00
可能是遗漏了某些概念,我随便拍拍脑袋能想到相关的可能有:
1、struct、class成员的默认内存对齐方式(#pragma pack)
2、不清楚C++其实是没有ABI兼容性的

后面这个问题会导致不同的C++编译器、编译器版本、甚至只是不同的编译参数生成的二进制代码不兼容。你看系统库都是纯C接口的发现没有?因为纯C有函数调用的ABI兼容性标准:stdcall、cdecl、fastcall。而C++是彻底没有ABI兼容性的,能“差不多对上”只是运气好,或者编译器版本、参数完全一样。

所以重点恐怕是检查你dll和主程序的编译参数有何区别
acros
2015-07-26 19:14:52 +08:00
@Athrob
@nozama
@fo2w
我也认为代码出错可能性更大。 一般代码灵异问题都是内存初始化或者溢出一类导致的,这次是摸不着头脑了....从内存布局上看,没有被覆盖的问题....回头再查查vs类底层虚表有没错误,哎,没学好汇编和编译原理,到底层就非常吃力。
husinhu
2015-07-26 20:59:46 +08:00
同意@lcksy 如果真是ABI不同或者编译选项不同,建议同一编译选项,加一层SceneAdaptor来decouple
lingo233
2015-07-26 21:06:32 +08:00
我受不了了明明2015已经发布了竟然不升级,要被逼疯了(╯-_-)╯╧╧
nozama
2015-07-26 21:29:20 +08:00
也许还有一种可能, 也是vs2012的bug: 某个源文件会莫名其妙被copy一份, 然后无论怎么修改, 编译的仍是原来的那个文件.
于是就可能出现: 头文件更新了, dll其实还是以前的, 然后按照偏移量访问某个字段, 实际上是访问到了另一个字段.
endrollex
2015-07-26 22:09:46 +08:00
http://blog.csdn.net/smstong/article/details/24455371
如果C++编译器不能根据类声明推算出类型转换时的指针调整方式时,如果使用了强制类型转换,那么编译器只是简单的默默无作为
bombless
2015-07-26 23:18:23 +08:00
以前见到有个人有类似的问题,貌似是同一个变量名在不同的命名空间用上了,然后链接的时候出错(或者是调试器显示的有问题,忘记具体情况了)
mljack
2015-07-26 23:25:22 +08:00
检查下dll和主程序的工程设置中预编译宏是否一致,感觉像 #ifdef xxx 造成的问题,c/c++编译器对于一些.h 和.lib里的class是否一致并不做完整的检查。

仔细看了一下,应该是编译 dll 时没定义CC_USE_NAVMESH,而使用 dll 时又定义了CC_USE_NAVMESH造成的。
tushiner
2015-07-26 23:29:28 +08:00
我开发的时候也是用网易云音乐听歌
acros
2015-07-26 23:29:33 +08:00
@mljack 这个我确认过了。如果CC_USE_NAVMESH关闭掉,读取错误的地址还是偏移8(这时候就是_navMesh前面的变量读取错误了),应该不是具体变量造成的。
xdeng
2015-07-26 23:31:09 +08:00
有个东西 叫 字节对齐

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/208440

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX