返回的strdup地址出界 [英] Strdup returning address out of bounds
问题描述
我想我会花更多的时间在这之前询问。 Valgrind的不报什么,其实它不与Valgrind的崩溃。
的char * A =HI;
字符* B =的strdup(一);
(GDB)打印B =>
$ 8 = 0xffffffffe8003680<地址0xffffffffe8003680出界的制造>
这只是发生在我的动态加载共享库(加载使用dlopen)。我不知道什么可能导致此。我剥去只是一切出库,只有在它这两条线。你可以帮我调试这个?
如果我试图访问 B
现在
计划接收信号SIGSEGV,分割过错。
从/lib64/libc.so.6 0x00007ffff76b3d0a在strchrnul()
怎么可能是错的怎么回事?
的回溯:的
计划接收信号SIGSEGV,分割过错。
从/lib64/libc.so.6 0x00007ffff76b3d0a在strchrnul()
(GDB)BT
从/lib64/libc.so.6#0 0x00007ffff76b3d0a在strchrnul()
从/lib64/libc.so.6#1 0x00007ffff767088a在vfprintf()
#2 0x00007ffff767af79中的printf()从/lib64/libc.so.6
#3 0x00007ffff722678c在_mkp_stage_30(插件= 0x61f420,CS = 0x7fffe8002040,
SR = 0x7fffe8003070)在hello.c中:68
#4 0x000000000040f93a在mk_plugin_stage_run(勾= 16,插座= 18,CONX =为0x0,
CS = 0x7fffe8002040,SR = 0x7fffe8003070)在mk_plugin.c:558
#5 0x000000000040c501在mk_http_init(CS = 0x7fffe8002040,SR = 0x7fffe8003070)
在mk_http.c:255
#6 0x0000000000404870在mk_request_process(CS = 0x7fffe8002040,
SR = 0x7fffe8003070)在mk_request.c:510
#7 0x0000000000404d75在mk_handler_write(插座= 18,CS = 0x7fffe8002040)
在mk_request.c:630
#8 0x000000000040b446在mk_conn_write在mk_connection.c(插座= 18):130
#9 0x0000000000409352在mk_epoll_init(EFD = 12,处理器= 0x7fffe8001690,
在mk_epoll.c max_events = 202):102
在mk_sched_launch_worker_loop#10 0x0000000000409b4e(thread_conf = 0x61a5a0)
在mk_scheduler.c:196
从/lib64/libpthread.so.0#11 0x00007ffff79c2f05在start_thread()
#12 0x00007ffff770553d在克隆()从/lib64/libc.so.6
块引用>解决方案您需要添加
的#include<&string.h中GT;
获得
的strdup的声明()
。或者,如果你已经有了这一点,你需要调用你的编译器的方式,使
的strdup()
可见(详见下文)。的strdup()
被定义为在POSIX,而不是由ISO C。GCC默认启用适当的宏(S),但使用
-ansi
或-std = C99
将禁用它们。您还可以添加适当的的#define
到源文件的顶部。在没有明显的声明,编译器假定(下C90规则)
的strdup()
收益INT
。这将导致不确定的行为。特别是,如果INT
是32位和的char *
为64位,坏的事情会发生。 (在C99规则,要求没有可见的声明中的函数是一个约束冲突。)您也应该杀青你的编译器的警告级别和的注意警告的。像这样的问题应该体现在编译时;你不应该有诊断运行时的行为。
更新:
以下是基于文档和实验我自己的Ubuntu 11.04系统上。它可能适用于使用glibc的任何系统;它的一些可能适用于非glibc的系统。
的strdup人
和男人feature_test_macros
了解更多信息。要使用
的strdup()
,您的必须的有无的#include<文件string.h>
来作出声明可见。 (如果你省略这个编译器不一定会抱怨,但你需要也无妨。)此外,你需要有下列之一(或同等学历)的前的的
的#include<文件string.h>
:的#define _SVID_SOURCE
的#define _BSD_SOURCE
的#define _XOPEN_SOURCE 500 / *或以上* /
的#define _XOPEN_SOURCE
#定义_XOPEN_SOURCE_EXTENDED的#define _POSIX_C_SOURCE 200809L / *或更大* /
要做到这一点,最简单的方法就是的不的使用
-ansi
或-std = ...
gcc的选项(或者类似的叮当声); GCC使一些宏默认情况下。如果你想与
-ansi
或STD = C99
,那么你可以明确设置的一个编译上述宏(或两个,如果您使用第四替代),无论是与一个明确的的#define
源(可能是最好的解决方案),或使用,例如,的gcc -std = C99 -D_XOPEN_SOURCE = 500
。的和的,正如我前面提到的,你应该杀青你的编译器的警告级别。对于GCC,我通常使用:
的gcc -std = C99 -pedantic -Wall -Wextra -O3
的
-O3
使优化;一个副作用是,它使需要执行这些优化分析,其可以检测了若干并不明显在较低的优化级别的问题。原因这一切繁琐程序是
的strdup()
不是由ANSI / ISO C标准(该委员会决定不将其列入)的定义,但它是通过POSIX定义 - 其声明中<&string.h中GT;
,ISO C标准头之一。在严格的ISO C遵循模式,名称的strdup()
可能不会在可见<文件string.h>
。你必须把这些额外的步骤来告诉编译器使其可见无妨。 (GCC是默认情况下不完全符合C编译器,这就是为什么它能够使的strdup()
默认可见。)由于
的strdup()
就是这样一个简单的功能,则可以考虑只是写在标准的ISO C自己的实现,并使用该来代替。例如(注意开头STR
是保留名称):的char * dupstr(为const char * S){
char * const的结果=的malloc(strlen的(S)+ 1);
如果(结果!= NULL){
的strcpy(结果,S);
}
返回结果;
}(我只是最低限度测试这一点。)如果
的strdup()
是您正在使用,滚动您自己可能是最好的解决方案的唯一POSIX的特定功能。如果您使用其他特定POSIX标准的功能,那么你总得去面对这一切东西,你还不如用的strdup()
本身。I thought I'd ask before spending more hours on this. Valgrind doesn't report anything, in fact it doesn't crash with Valgrind.
char* a = "HI"; char* b = strdup(a);
(gdb) print b =>
$8 = 0xffffffffe8003680 <Address 0xffffffffe8003680 out of bounds>
This only happens in my dynamically loaded shared library, (loaded with dlopen). I have no idea what could possibly cause this. I stripped just about everything out of that library, there are only these two lines in it. Can you help me debug this?
If I try to access
b
now:Program received signal SIGSEGV, Segmentation fault. 0x00007ffff76b3d0a in strchrnul () from /lib64/libc.so.6
What could possibly be going wrong here?
Backtrace:
Program received signal SIGSEGV, Segmentation fault. 0x00007ffff76b3d0a in strchrnul () from /lib64/libc.so.6 (gdb) bt #0 0x00007ffff76b3d0a in strchrnul () from /lib64/libc.so.6 #1 0x00007ffff767088a in vfprintf () from /lib64/libc.so.6 #2 0x00007ffff767af79 in printf () from /lib64/libc.so.6 #3 0x00007ffff722678c in _mkp_stage_30 (plugin=0x61f420, cs=0x7fffe8002040, sr=0x7fffe8003070) at hello.c:68 #4 0x000000000040f93a in mk_plugin_stage_run (hook=16, socket=18, conx=0x0, cs=0x7fffe8002040, sr=0x7fffe8003070) at mk_plugin.c:558 #5 0x000000000040c501 in mk_http_init (cs=0x7fffe8002040, sr=0x7fffe8003070) at mk_http.c:255 #6 0x0000000000404870 in mk_request_process (cs=0x7fffe8002040, sr=0x7fffe8003070) at mk_request.c:510 #7 0x0000000000404d75 in mk_handler_write (socket=18, cs=0x7fffe8002040) at mk_request.c:630 #8 0x000000000040b446 in mk_conn_write (socket=18) at mk_connection.c:130 #9 0x0000000000409352 in mk_epoll_init (efd=12, handler=0x7fffe8001690, max_events=202) at mk_epoll.c:102 #10 0x0000000000409b4e in mk_sched_launch_worker_loop (thread_conf=0x61a5a0) at mk_scheduler.c:196 #11 0x00007ffff79c2f05 in start_thread () from /lib64/libpthread.so.0 #12 0x00007ffff770553d in clone () from /lib64/libc.so.6
解决方案You need to add
#include <string.h>
to get the declaration of
strdup()
.Or, if you already have that, you need to invoke your compiler in a way that makes
strdup()
visible (see below for details).strdup()
is defined by POSIX, not by ISO C.gcc enables the appropriate macro(s) by default, but using
-ansi
or-std=c99
will disable them. You can also add an appropriate#define
to the top of your source file.In the absence of a visible declaration, the compiler assumes (under C90 rules) that
strdup()
returnsint
. This results in undefined behavior. In particular, ifint
is 32 bits andchar*
is 64 bits, Bad Things Will Happen. (Under C99 rules, calling a function with no visible declaration is a constraint violation.)You should also crank up your compiler's warning levels and pay attention to the warnings. A problem like this should manifest at compile time; you shouldn't have to diagnose the run-time behavior.
UPDATE :
The following is based on documentation and experiments on my own Ubuntu 11.04 system. It's likely to apply to any system using glibc; some of it might apply to non-glibc systems.
man strdup
andman feature_test_macros
for more information.To use
strdup()
, you must have#include <string.h>
to make the declaration visible. (The compiler won't necessarily complain if you omit this, but you need it anyway.)In addition, you need to have one of the following (or equivalent) before the
#include <string.h>
:#define _SVID_SOURCE
#define _BSD_SOURCE
#define _XOPEN_SOURCE 500 /* or greater */
#define _XOPEN_SOURCE #define _XOPEN_SOURCE_EXTENDED
#define _POSIX_C_SOURCE 200809L /* or greater */
The simplest way to do this is just not to use the
-ansi
or-std=...
option for gcc (or the equivalent for clang); gcc enables some of these macros by default.If you want to compile with
-ansi
orstd=c99
, then you can explicitly set one of the above macros (or two if you use the 4th alternative), either with an explicit#define
in the source (probably the best solution), or by using, for example,gcc -std=c99 -D_XOPEN_SOURCE=500
.And, as I mentioned before, you should crank up the warning levels on your compiler. For gcc, I typically use:
gcc -std=c99 -pedantic -Wall -Wextra -O3
The
-O3
enables optimizations; a side effect is that it enables the analysis necessary to perform those optimizations, which can detect a number of problems that aren't apparent at lower optimization levels.The reason for all this rigmarole is that
strdup()
is not defined by the ANSI/ISO C standard (the committee chose not to include it), but it is defined by POSIX -- and its declaration is in<string.h>
, one of the ISO C standard headers. In strict ISO C conforming mode, the namestrdup()
may not be made visible in<string.h>
. You have to take these extra steps to tell the compiler to make it visible anyway. (gcc is not a fully conforming C compiler by default, which is why it's able to makestrdup()
visible by default.)Since
strdup()
is such a simple function, you might consider just writing your own implementation in standard ISO C and using that instead. For example (note that names starting withstr
are reserved):char *dupstr(const char *s) { char *const result = malloc(strlen(s) + 1); if (result != NULL) { strcpy(result, s); } return result; }
(I have only minimally tested this.) If
strdup()
is the only POSIX-specific function you're using, rolling your own might be the best solution. If you're using other POSIX-specific functions, then you'll have to deal with all this stuff anyway, and you might as well usestrdup()
itself.这篇关于返回的strdup地址出界的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!