在使用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坑的更多相关文章

  1. 内存对齐与ANSI C中struct型数据的内存布局 【转】

    转自:http://blog.chinaunix.net/uid-25909619-id-3032209.html 当在C中定义了一个结构类型时,它的大小是否等于各字段(field)大小之和?编译器将 ...

  2. 内存对齐与ANSI C中struct型数据的内存布局

    当在C中定义了一个结构类型时,它的大小是否等于各字段(field)大小之和?编译器将如何在内存中放置这些字段?ANSI C对结构体的内存布局有什么要求?而我们的程序又能否依赖这种布局?这些问题或许对不 ...

  3. 浅析内存对齐与ANSI C中struct型数据的内存布局-内存对齐规则

    这些问题或许对不少朋友来说还有点模糊,那么本文就试着探究它们背后的秘密. 首先,至少有一点可以肯定,那就是ANSI C保证结构体中各字段在内存中出现的位置是随它们的声明顺序依次递增的,并且第一个字段的 ...

  4. HotSpot源码分析之C++对象的内存布局

    HotSpot采用了OOP-Klass模型来描述Java类和对象.OOP(Ordinary Object Pointer)指的是普通对象指针,而Klass用来描述对象的具体类型.为了更好理解这个模型, ...

  5. jvm学习记录-对象的创建、对象的内存布局、对象的访问定位

    简述 今天继续写<深入理解java虚拟机>的对象创建的理解.这次和上次隔的时间有些长,是因为有些东西确实不好理解,就查阅各种资料,然后弄明白了才来做记录. (此文中所阐述的内容都是以Hot ...

  6. 浅谈Java虚拟机内存中的对象创建,内存布局,访问定位

    参考于 深入理解Java虚拟机 这里介绍HotSpot虚拟机(自带的虚拟机) 1.对象的创建 对于程序员来说,创建对象的方法: User user1 = new User(); User user2 ...

  7. HotSpot虚拟机对象探秘(对象创建,对象内存布局,对象访问定位)

    以常用的HotSpot虚拟机和JAVA内存区域堆为例,探讨对象的创建,对象的内存布局以及对象的访问定位 一.对象的创建 1)类加载:虚拟机遇到一条new指令时,先检测这个指令的参数能否在常量池中定位到 ...

  8. Java对象的创建、内存布局和访问定位

    在Java运行时数据区中,我们知道了虚拟机内存的概况,本文介绍虚拟机内存中的数据的其它细节,如对象如何创建.如何布局以及如何访问. 基于实用的原则,这里以HotSpot虚拟机和常用的内存区域Java堆 ...

  9. Java对象创建的过程及对象的内存布局与访问定位

    这里以HotSpot为例,且所说的对象指普通的Java对象,不包括数组和Class对象等. 1.对象创建的过程 1.类加载.解析.初始化:虚拟机遇到new时先检查此指令的参数是否能在常量池中找到类的符 ...

随机推荐

  1. 【编辑器】【Sublime Text】使用笔记

    1.安装 官网下载即可 2.插件 sublime-text - Sublime Text 怎么高亮 Markdown 的文件语法 设置Sublime为VIM模式 如何在sublime 里面设置 ver ...

  2. 用markdown学习写出总结

    # PS### 快捷键:CTRL+N(新建)CTRL+1. **切片**- 套索,磁性套索,椭圆,矩形选框.2. **印章** 仿制图章工具,图案图章工具3. 钢笔4. 油漆桶5. 吸管工具, *** ...

  3. SharePoint 2010 + 左侧导航(Left Nav Bar)二级菜单的修改

    SharePoint 2010 + 修改左侧导航类似顶部导航菜单的样式 查找aspmenu的控件,ID为“V4QuickLaunchMenu”,修改分别将属性“StaticDisplayLevels” ...

  4. 使用php-cs-fixer格式化你的代码

    在开发中,我们会有意识的遵行一套规范来保证团队代码的一致性.PSR是我们PHP遵循的共同规范. 在这里,推荐一个代码格式化工具php-cs-fixer,可以一键把代码格式化为PSR-2的标准. 安装: ...

  5. [导读]Learning from Imbalanced Classes

    原文:Learning from Imbalanced Classes 数据不平衡是一个非常经典的问题,数据挖掘.计算广告.NLP等工作经常遇到.该文总结了可能有效的方法,值得参考: Do nothi ...

  6. C++多线程3

    #include "stdafx.h" #include <windows.h> #include <process.h> int g_count; ; u ...

  7. memo的一般方法

    str := '好时代卡卡卡的水平佛单师傅开锁'; Memo1.Lines.Add(str); // 在最后加一行字符串 Memo1.Lines.Delete(x); // 删除x+1行字符串 Mem ...

  8. tesseract 编译与使用(windows)

    tesseract是google的一个开源OCR项目,项目地址已经迁移到github(现在 2016/09),地址 https://github.com/tesseract-ocr/tesseract ...

  9. 【python】闭包、@修饰符(装饰器)、

    闭包:(返回函数的行为叫闭包??) #函数也是对象,所以可以被传递 def line_conf(a,b): def line(x): return a*x+b return line line1=li ...

  10. mvc 导入,导出excel

    最近主要做导入excel 在网上查询了代码 public FileResult DownLoadExcelJiZuChaXunGenRenXiaoFeiJiLu() { DataTable dt = ...