返回的strdup地址出界 [英] Strdup returning address out of bounds

查看:178
本文介绍了返回的strdup地址出界的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想我会花更多的时间在这之前询问。 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() returns int. This results in undefined behavior. In particular, if int is 32 bits and char* 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 and man 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 or std=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 name strdup() 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 make strdup() 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 with str 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 use strdup() itself.

这篇关于返回的strdup地址出界的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆