根据内存布局定位的一个fastdfs坑
在使用fastdfs时,编写数据上传代码时,遇到一个坑。最终根据指针对应的内存布局定位到一个其client API的一个坑,值得记录一下。
具体是在 tracker_connect_server() 这个API上,其是一个宏,具体定义如下
#define tracker_connect_server(pTrackerServer, err_no) \
tracker_connect_server_ex(pTrackerServer, g_fdfs_connect_timeout, err_no)
tracker_connect_server_exs 声明如下
ConnectionInfo *tracker_connect_server_ex(ConnectionInfo *pTrackerServer, const int connect_timeout, int *err_no);
在tracker_proto.c中实现,其返回值将在后面数据上传操作中的链接句柄。
当配置不使用连接池的时候,连接操作成功时,会将 pTrackerServer 参数原样返回,一般使用者会习惯性地保存该指针句柄供后用。我自己仿照着范例代码使用,结果就掉坑里了。
如此设计实现,就极易产生勿用,如下:
当 tracker_connect_server_ex() 的 pTrackerServer 参数传递的对象,后续被销毁之后,用户是不知道刚才通过返回值拿到的指针句柄指向的对象是已经不复存在的。
后续继续使用该已经失效的指针句柄进行数据上传操作时,结果就不可预知了。
实际上在其工程test目录下的范例代码 dfs_func.c 中, upload_file() 函数 pTrackerServer 参数就传递了一个栈上的临时对象,但其在 upload_file() 中立即使用返回值的指针句柄调用 storage_upload_by_filebuff1() 进行数据上传,所以对应返回值指针句柄指向的对象,在此过程中都一直有效,而没有造成问题。
但自己就没有这么幸运了。我类似地仿照 upload_file() 给 tracker_connect_server() 传递了一个栈上的临时对象时,拿到其返回值做保存之后,将从当前调用函数返回了,
后续使用刚才保存的指针句柄调用 storage_do_upload_file1() 进行数据上传操作,总是出现下面的错误打印
[2016-03-05 17:46:26] ERROR - file: storage_client.c, line: 933, send data to storage server :0 fail, errno: 88, error info: Socket operation on non-socket
于是就开始了一番debug,可从 tracker_connect_server() 调用返回的地方,一路确认到调用 storage_do_upload_file1() 的地方,该指针句柄值都没有发生变化,但其指向的内存却被异常地清零了,一时见鬼了!后来在 gdb 中对给 storage_do_upload_file1() 传递的前两个参数值 print 了一把,发现了一点端倪,如下
(gdb) p ((struct fastdfs_priv*)&dfs[1])->tracker_conn
$4 = (ConnectionInfo *) 0x613150
(gdb) p ((struct fastdfs_priv*)&dfs[1])->storage_conn
$5 = (ConnectionInfo *) 0x7fffffffe4e0
(gdb)
根据地址区间,很明显 tracker_conn 指向的内存在堆上,而 storage_conn 指向的内存在栈里!这就奇了怪,storage_conn 值源头是来自 tracker_connect_server() 啊,难道其给我返回了一个栈上的临时对象地址?其作者应该不会犯这种弱智错误吧?去看了 tracker_connect_server_ex() 的代码之后,顿时吐血!太坑了吧!作者自己难道没想过上面的这些问题么?而且还在范例代码中,这么用?明显误导人么??!!!
知道原因之后,立即将 tracker_connect_server() 第一个参数传递的对象改为不是临时的后,问题解决!
刚才的问题,之所以能发现突破点,还是根据指针值对应的内存布局来确定的。这又一次说明了内存等的相关的基础知识是非常重要的!!!
根据内存布局定位的一个fastdfs坑的更多相关文章
- 内存对齐与ANSI C中struct型数据的内存布局 【转】
转自:http://blog.chinaunix.net/uid-25909619-id-3032209.html 当在C中定义了一个结构类型时,它的大小是否等于各字段(field)大小之和?编译器将 ...
- 内存对齐与ANSI C中struct型数据的内存布局
当在C中定义了一个结构类型时,它的大小是否等于各字段(field)大小之和?编译器将如何在内存中放置这些字段?ANSI C对结构体的内存布局有什么要求?而我们的程序又能否依赖这种布局?这些问题或许对不 ...
- 浅析内存对齐与ANSI C中struct型数据的内存布局-内存对齐规则
这些问题或许对不少朋友来说还有点模糊,那么本文就试着探究它们背后的秘密. 首先,至少有一点可以肯定,那就是ANSI C保证结构体中各字段在内存中出现的位置是随它们的声明顺序依次递增的,并且第一个字段的 ...
- HotSpot源码分析之C++对象的内存布局
HotSpot采用了OOP-Klass模型来描述Java类和对象.OOP(Ordinary Object Pointer)指的是普通对象指针,而Klass用来描述对象的具体类型.为了更好理解这个模型, ...
- jvm学习记录-对象的创建、对象的内存布局、对象的访问定位
简述 今天继续写<深入理解java虚拟机>的对象创建的理解.这次和上次隔的时间有些长,是因为有些东西确实不好理解,就查阅各种资料,然后弄明白了才来做记录. (此文中所阐述的内容都是以Hot ...
- 浅谈Java虚拟机内存中的对象创建,内存布局,访问定位
参考于 深入理解Java虚拟机 这里介绍HotSpot虚拟机(自带的虚拟机) 1.对象的创建 对于程序员来说,创建对象的方法: User user1 = new User(); User user2 ...
- HotSpot虚拟机对象探秘(对象创建,对象内存布局,对象访问定位)
以常用的HotSpot虚拟机和JAVA内存区域堆为例,探讨对象的创建,对象的内存布局以及对象的访问定位 一.对象的创建 1)类加载:虚拟机遇到一条new指令时,先检测这个指令的参数能否在常量池中定位到 ...
- Java对象的创建、内存布局和访问定位
在Java运行时数据区中,我们知道了虚拟机内存的概况,本文介绍虚拟机内存中的数据的其它细节,如对象如何创建.如何布局以及如何访问. 基于实用的原则,这里以HotSpot虚拟机和常用的内存区域Java堆 ...
- Java对象创建的过程及对象的内存布局与访问定位
这里以HotSpot为例,且所说的对象指普通的Java对象,不包括数组和Class对象等. 1.对象创建的过程 1.类加载.解析.初始化:虚拟机遇到new时先检查此指令的参数是否能在常量池中找到类的符 ...
随机推荐
- erlang服务器启动,有情况会报,enif_send: env==NULL no ono-SMP VMAborted 的错误报告?
问题的原因所在: 1:因为你当前使用的主机是一个单核的主机(不会自动启动): 2:多核上如果不设置-smp enable是不会有什么问题的,因为从OTP R12B开始,如果操作系统报告有多于1个的CP ...
- nRF24L01芯片控制——迈向无线的第一步
nRF24L01芯片是一款专供单片机的射频收发芯片.工作于2.4GHz~2.5GHz ISM频段.融合了shockburst技术. 我先列出该芯片的硬件参数资料: 至于每个引脚的具体用途,可以参见技术 ...
- js中Array的一些扩展
IE下很多Array的方法都不被支持.每次都要写.所以记下来,以免忘记: 以下是对Array的一些扩展,在FF ,google 下是不需要加的. /** * 方法Array.filter(functi ...
- 个人纪录(初)----Ueditor文本编辑器的引用
源码下载地址:http://ueditor.baidu.com/website/ 打开源码参考.html 把ueditor引入自己的web项目下. 在需要引入文本的地方写个div,设置样式等. 并且在 ...
- Winform 支持高清屏(High DPI) 设置
http://www.cnblogs.com/weiym/p/3555068.htmlhttp://crsouza.com/2015/04/how-to-fix-blurry-windows-form ...
- Bootstrap <基础二十五>警告(Alerts)
警告(Alerts)以及 Bootstrap 所提供的用于警告的 class.警告(Alerts)向用户提供了一种定义消息样式的方式.它们为典型的用户操作提供了上下文信息反馈. 您可以为警告框添加一个 ...
- Unique Paths II
这题在Unique Paths的基础上增加了一些obstacle的位置,应该说增加的难度不大,但是写的时候对细节的要求多了很多,比如,第一列的初始化会受到之前行的第一列的结果的制约.另外对第一行的初始 ...
- LINUX centos 忘记密码
entos7采用的是grub2,和centos6.x进入单用户的方法不同.但是因为用的是真机环境无法截图,所以只是大概描述以下思路. init方法 1.centos7的grub2界面会有两个入口,正常 ...
- 纯js开发防win7日历控件
不久前项目开发中遇到需要用js实现选择日期的需求,百度了下,确实一大把一大把的,但多少还是有些不符合当前需求,遂down了一份最接近的,然后修修改改,基本符合了... 先上几张效果图~~~ 需要输入时 ...
- 【转】Tomcat的默认访问路径
放在外网的应用,用户多是直接输入域名访问,相信没有哪个后面还加个尾巴,而Tomcat的默认目录是ROOT,所以我们需要更改其默认目录. 更改Tomcat的默认目录很简单,只需要修改server.xml ...