Gcc编译时无优化参数,以前曾经被-O坑过。

#include<stdio.h>
#include<string.h>

intmain()
{
charurl[512];
sprintf(url,"218.26.242.56/0/0/1023/6d6168bf1a7294ae0e1c071171adcd48.mp4");
printf("%s\n",url);
char*p=url;

strcpy(p+15,p+22);
printf("%s\n",url);
return0;
}

打印结果应该如下

218.26.242.56/0/0/1023/6d6168bf1a7294ae0e1c071171adcd48.mp4

218.26.242.56/06d6168bf1a7294ae0e1c071171adcd48.mp4

但是在centos6.3系统下,gcc4.4.7

打印结果会是

218.26.242.56/0/0/1023/6d6168bf1a7294ae0e1c071171adcd48.mp4

218.26.242.56/0/f1a7294a1a7294ae0e1c071171adcd48.mp4

目前实验redhat5.05.7centos7.2系统下都不会出现问题,唯有6.x(试了6.0、6.3、6.7)gcc4.4.7会有问题

下载4.4.7源码

wget http://ftp.gnu.org/gnu/gcc/gcc-4.4.7/gcc-4.4.7.tar.bz2

代码如下

externvoidabort(void);
externintinside_main;

char*
strcpy(char*d,constchar*s)
{
char*r=d;
#ifdefined__OPTIMIZE__&&!defined__OPTIMIZE_SIZE__
if(inside_main)
abort();
#endif
while((*d++=*s++));
returnr;
}

理论上不应该出现如此问题

Centos6.xstrcpy源码为汇编码

char*strcpy(char*dest,constchar*src)
{
return__kernel_strcpy(dest,src);
}
staticinlinechar*__kernel_strcpy(char*dest,constchar*src)
{
char*xdest=dest;

asmvolatile("\n"
"1:move.b(%1)+,(%0)+\n"
"jne1b"
:"+a"(dest),"+a"(src)
::"memory");
returnxdest;
}

同样看不出有什么问题。

将系统函数修改为自定义函数,使用一样的代码,结果均为正确。

网络上也找到过另外一种优化版本的strcpy代码,使用寄存器加速效果,在网上找到的号称gcc的优化代码也是类似

char*
strcpy(dest,src)
char*dest;
constchar*src;
{
registercharc;
char*__unboundeds=(char*__unbounded)CHECK_BOUNDS_LOW(src);
constptrdiff_toff=CHECK_BOUNDS_LOW(dest)-s-1;
size_tn;

do
{
c=*s++;
s[off]=c;
}
while(c!='\0');
n=s-src;
(void)CHECK_BOUNDS_HIGH(src+n);
(void)CHECK_BOUNDS_HIGH(dest+n);

returndest;
}


将之作为自定义函数使用后发现也没有问题。


继续发现strncpy和sprintf也会遇到同样的问题。

采用memcpy就没有问题了

memcpy(p+11,p+18,strlen(p+18)+1);


看了下源码,跟strcpy也没什么区别

void*
memcpy(void*dest,constvoid*src,size_tlen)
{
char*d=dest;
constchar*s=src;
while(len--)
*d++=*s++;
returndest;
}


暂时不明白为什么strcpy、strncpy、sprintf在gcc4.4.7下,自我移动会导致问题。

以前曾经在网上看见过strcpy的优化函数,在64位系统里,采用八字节长整形来进行复制,但是未在库中见过,只是作为优化的自定义代码推荐。

在这里例子中,如果我们将p+15改成p+16,就一切正常,把字符串总长度缩小到p+32(即*(p+32)=0),那么也一切正常。错误字段长度8字节,跟8都有关系,怀疑系统在什么地方做了优化,但是实在搞不清是谁在优化,优化后的代码是什么样子的。


所以建议如果要进行字符串自我移动,不要使用str,使用mem函数。


--------------------

同事提供了一个帖子,说的是内存重叠的问题

http://www.jb51.cc/article/p-smdmucpb-xt.html


但是这个例子的作者其实没有分析到点子上

charstr[]="123456789";
strcpy(str+2,str);

本身在代码逻辑上就是错的,从源码就能看出来,从前往后复制,会导致后面的内存覆盖。和我们这次遇到的不是一个情况。


按照源码应该结果是1212121212121212。。。。。。。。。。。一直到越界崩溃

但是实际结果是121234565678


在几个机器上试了下

在gcc4.1.1上,是12121212121。。。。。。 崩溃

Gcc4.4.7 显示121234565678

gcc4.8.5 显示12123456789


应该是在4.4.7上确实有优化,但是4.8.5应该是解决了,而且连这种逻辑异常的也一起支持了。

在网上找到了gcc4.7上strcpy的汇编bug,为什么是不是也有关系。

-----------------


网上查了一下,发现被误导了,这里应该研究libc.so的代码,而不是看gcc的代码


看了下libc的源码,define了不少实现,在不同设备上使用了不同优化的汇编码,应该是使用8字节复制代替单个字符串复制,在libc2.12有bug,libc2.17上应该是解决了。


查看他们的strcpy代码

libc2.12.1上

/*copySRCtoDEST.*/
char*
strcpy(dest,src)
char*dest;
constchar*src;
{
reg_charc;
char*__unboundeds=(char*__unbounded)CHECK_BOUNDS_LOW(src);
constptrdiff_toff=CHECK_BOUNDS_LOW(dest)-s-1;
size_tn;
do
{
c=*s++;
s[off]=c;
}
while(c!='\0');
n=s-src;
(void)CHECK_BOUNDS_HIGH(src+n);
(void)CHECK_BOUNDS_HIGH(dest+n);
returndest;
}


libc2.17上

/*copySRCtoDEST.*/
char*
strcpy(dest,src)
char*dest;
constchar*src;
{
charc;
char*__unboundeds=(char*__unbounded)CHECK_BOUNDS_LOW(src);
constptrdiff_toff=CHECK_BOUNDS_LOW(dest)-s-1;
size_tn;
do
{
c=*s++;
s[off]=c;
}
while(c!='\0');
n=s-src;
(void)CHECK_BOUNDS_HIGH(src+n);
(void)CHECK_BOUNDS_HIGH(dest+n);
returndest;
}

发现2.17相比2.12没什么改动,就是取消了寄存器(reg_char变成了char),在这个博客里面说过寄存器的重要性,可以提高copy速度,不明白为什么2.17取消了寄存器。

http://blog.csdn.net/astrotycoon/article/details/8114786


继续测试

发现在libc2.12上

(gdb)bt
#00x00000036a7532664in__strcpy_ssse3()from/lib64/libc.so.6
#10x0000000000400671inmain()attest.c:32

真正使用的是ssse3指令集下的strcpy.S实现


在glib2.17下

(gdb)bt
#0__strcpy_sse2_unaligned()at../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:232
#10x0000000000400655inmain()attest.c:9

直接进入.s汇编码,连libc.so都没有进入,不过这个汇编函数strcpy-sse2-unaligned也是glib里面的


对汇编实在无力,完全无从下手。

不过看来所谓的c源码对分析没有什么太大的帮助还容易引起误解,因为底层的库根本就不用c程序的源码啊。

strcpy在centos6.x,gcc4.4.7版本上会有bug,自我移动导致覆盖错误overlap的更多相关文章

  1. HTML实现代码雨源码及效果示例

    这篇文章主要介绍了HTML实现代码雨源码及效果示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. 为什么这个OpenGL ES 2.0着色器不能在iOS上使用我的VBO?

    如果有人能够了解这里出了什么问题,也许是对gl命令或其他一些不兼容的命令序列的错误排序,我将非常感谢你的帮助.尽管谷歌在“OpenGLES2.0编程指南”中进行了大量研究和研究,但我一直试图让这段代码整天都没有成功.我正在尝试在iPhone上的OpenGLES2.0中使用顶点缓冲区对象和自定义着色器.我试图交错来自以下类型的一系列自定义结构的顶点数据:位置,半径和颜色字节分别考虑顶点位置,点大小和

  3. ios – 将两个字符串转换为一组布尔值的快速方法是什么?

    我有一个长字符串,我想转换为一个布尔值数组.而且它需要很多次,很快.我天真的尝试是这样的:但这比我想要的要慢很多.我的剖析告诉我,地图是减速的地方,但我不知道我能做多么简单.我觉得如果没有Swift’s/ObjC的开销,这样做会很快.在C中,我认为这是一个简单的循环,其中一个字节的内存与一个常量进行比较,但我不知道我应该看的是什么函数或语法.有更好的办法吗?

  4. 在iOS上默认是char签名还是未签名?

    默认情况下,iOS上是否签名或未签名?(我认为这将是一个很好的回答问题,但奇怪的是谷歌没有任何用处!

  5. ios – 如何创建一个本机显示浮动窗口的ANE

    如何在Xcode中创建本机窗口并将其与MobileFlex应用程序集成.本机窗口应该与StageWebView组件类似,其中本机内容浮动在Flex应用程序的其余部分的矩形区域中.解决方法作为一名灵活的程序员,这是一个繁琐的过程,花了我几个星期才弄明白.希望这将有助于其他一些Xcode新手.首先,您必须对Objective-C和Xcode有基本的了解.您应该能够创建一个简单的HelloWorldXc

  6. 源码推荐:简化Swift编写的iOS动画,iOS Material Design库

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  7. Swift社交应用文本输入优化汇总

    本文将汇总一下Swift社交应用文本输入优化技巧。

  8. swift皮筋弹动发射飞机ios源码

    这是一个款采用swift实现的皮筋弹动发射飞机游戏源码,游戏源码比较详细,大家可以研究学习一下吧。

  9. Swift基础-0003

  10. swift 写的app 源码,保存一下下

    http://www.topthink.com/topic/3345.htmlhttp://www.csdn.net/article/2015-01-09/2823502-swift-open-source-libs

随机推荐

  1. 在airgapped(离线)CentOS 6系统上安装yum软件包

    我有一个CentOS6系统,出于安全考虑,它已经被空气泄漏.它可能从未连接到互联网,如果有,它很长时间没有更新.我想将所有.rpm软件包放在一个驱动器上,这样它们就可以脱机安装而无需查询互联网.但是,我在测试VM上遇到的问题是,即使指定了本地路径,yum仍然会挂起并尝试从在线存储库进行更新.另外,有没有办法使用yum-utils/yumdownloader轻松获取该包的所有依赖项和所有依赖项?目前

  2. centos – 命名在日志旋转后停止记录到rsyslog

    CentOS6.2,绑定9.7.3,rsyslog4.6.2我最近设置了一个服务器,我注意到在日志轮换后,named已停止记录到/var/log/messages.我认为这很奇怪,因为所有日志记录都是通过rsyslog进行的,并且named不会直接写入日志文件.这更奇怪,因为我在更新区域文件后命名了HUPed,但它仍然没有记录.在我停止并重新启动命名后,记录恢复.这里发生了什么?

  3. centos – 显示错误的磁盘大小

    对于其中一个磁盘,Df-h在我的服务器上显示错误的空白区域:Cpanel表明它只有34GB免费,但还有更多.几分钟前,我删除了超过80GB的日志文件.所以,我确信它完全错了.fdisk-l/dev/sda2也显示错误:如果没有格式化,我该怎么做才能解决这个问题?并且打开文件描述符就是它需要使用才能做到这一点.所以…使用“lsof”并查找已删除的文件.重新启动写入日志文件的服务,你很可能会看到空间可用.

  4. 如何在centos 6.9上安装docker-ce 17?

    我目前正在尝试在centOS6.9服务器上安装docker-ce17,但是,当运行yuminstalldocker-ce时,我收到以下错误:如果我用跳过的标志运行它我仍然得到相同的消息,有没有人知道这方面的方法?

  5. centos – 闲置工作站的异常负载平均值

    我有一个新的工作站,具有不寻常的高负载平均值.机器规格是:>至强cpu>256GB的RAM>4x512GBSSD连接到LSI2108RAID控制器我从livecd安装了CentOS6.564位,配置了分区,网络,用户/组,并安装了一些软件,如开发工具和MATLAB.在启动几分钟后,工作站负载平均值的值介于0.5到0.9之间.但它没有做任何事情.因此我无法理解为什么负载平均值如此之高.你能帮我诊断一下这个问题吗?

  6. centos – Cryptsetup luks – 检查内核是否支持aes-xts-plain64密码

    我在CentOS5上使用cryptsetupluks加密加密了一堆硬盘.一切都很好,直到我将系统升级到CentOS6.现在我再也无法安装磁盘了.使用我的关键短语装载:我收到此错误:在/var/log/messages中:有关如何装载的任何想法?找到解决方案问题是驱动器使用大约512个字符长的交互式关键短语加密.出于某种原因,CentOS6中的新内核模块在由旧版本创建时无法正确读取512个字符的加密密钥.似乎只会影响内核或cryptsetup的不同版本,因为在同一系统上创建和打开时,512字符的密钥将起作用

  7. centos – 大量ssh登录尝试

    22个我今天登录CentOS盒找到以下内容这是过去3天内的11次登录尝试.WTF?请注意,这是我从我的提供商处获得的全新IP,该盒子是全新的.我还没有发布任何关于此框的内容.为什么我会进行如此大量的登录尝试?是某种IP/端口扫描?基本上有4名匪徒,其中2名来自中国,1名来自香港,1名来自Verizon.这只发生在SSH上.HTTP上没有问题.我应该将罪魁祸首子网路由吗?你们有什么建议?

  8. centos – kswap使用100%的CPU,即使有100GB的RAM也可用

    >Linux内核是否应该足够智能,只需从内存中清除旧缓存页而不是启动kswap?

  9. centos – Azure将VM从A2 / 3调整为DS2 v2

    我正在尝试调整前一段时间创建的几个AzureVM,从基本的A3和标准A3到标准的DS2v2.我似乎没有能力调整到这个大小的VM.必须从头开始重建服务器会有点痛苦.如果它有所不同我在VM中运行CentOS,每个都有一个带有应用程序和操作系统的磁盘.任何人都可以告诉我是否可以在不删除磁盘的情况下删除VM,创建新VM然后将磁盘附加到新VM?

  10. centos – 广泛使用RAM时服务器计算速度减慢

    我在非常具体的情况下遇到服务器速度下降的问题.事实是:>1)我使用计算应用WRF>2)我使用双XeonE5-2620v3和128GBRAM(NUMA架构–可能与问题有关!

返回
顶部