3

我试图了解在 HP-UX 11.11 中运行导致 SIGSEGV(11,分段错误)的程序出了什么问题:

(gdb) bt
#0  0x737390e8 in _sigfillset+0x618 () from /usr/lib/libc.2
#1  0x73736a8c in _sscanf+0x55c () from /usr/lib/libc.2
#2  0x7373c23c in malloc+0x18c () from /usr/lib/libc.2
#3  0x7379e3f8 in _findbuf+0x138 () from /usr/lib/libc.2
#4  0x7379c9f4 in _filbuf+0x34 () from /usr/lib/libc.2
#5  0x7379c604 in __fgets_unlocked+0x84 () from /usr/lib/libc.2
#6  0x7379c7fc in fgets+0xbc () from /usr/lib/libc.2
#7  0x7378ecec in __nsw_getoneconfig+0xf4 () from /usr/lib/libc.2
#8  0x7378f8b8 in __nsw_getconfig+0x150 () from /usr/lib/libc.2
#9  0x737903a8 in __thread_cond_init_default+0x100 () from /usr/lib/libc.2
#10 0x737909a0 in nss_search+0x80 () from /usr/lib/libc.2
#11 0x736e7320 in __gethostbyname_r+0x140 () from /usr/lib/libc.2
#12 0x736e74bc in gethostbyname+0x94 () from /usr/lib/libc.2
#13 0x11780 in dnetResolveName (name=0x400080d8 "smtp.org.com", hent=0x737f3334) at src/dnet.c:64
..

问题似乎发生在 libc 内部的某个地方!系统调用跟踪结束于:

Connecting to server smtp.org.com on port 25
write(1, "C o n n e c t i n g   t o   s e ".., 51) .......................... = 51
open("/etc/nsswitch.conf", O_RDONLY, 0666) ............................... [entry]
open("/etc/nsswitch.conf", O_RDONLY, 0666) ................................... = 5
  Received signal 11, SIGSEGV, in user mode, [SIG_DFL], partial siginfo
    Siginfo: si_code: I_NONEXIST, faulting address: 0x400118fc, si_errno: 0
    PC: 0xc01980eb, instruction: 0x0d3f1280
exit(11) [implicit] ............................ WIFSIGNALED(SIGSEGV)|WCOREDUMP

程序的最后一条指令:

struct hostent *him;
him = gethostbyname(name); // name == "smtp.org.com" as shown by gdb

这是系统的问题,还是我遗漏了什么?任何深入挖掘的指导将不胜感激。

谢谢。

4

4 回答 4

2

长话短说:vsnprintf 在 HP-UX 11.11 下损坏了我的堆。vsnprintf 是在 C99 (ISO/IEC 9899:1999) 中引入的,“等效于 snprintf,带有可变参数列表”(§7.19.6.12.2)、snprintf (§7.19.6.5.2):“如果 n 为零,什么都没有写”。嗯,HP UX 11.11 不符合这个规范。当第二个参数 == 0 时,参数写在第一个参数的末尾。当然,这会破坏堆(当 maxsize==0 时,我不分配空间,因为不应该写入任何内容)。

HP手册页不清楚(“用户有责任确保有足够的存储空间可用。”),关于 maxsize==0 的情况没有任何说明。不错的陷阱.. 至少,手册页的 WARNINGS 部分应该警告符合标准的用户..

这是一个鸡蛋/鸡肉 pb:vnsprintf 是可变参数,因此对于“用户的责任”,以确保有足够的存储可用”,“用户的责任”必须首先知道需要多少空间。做到这一点的最好方法是调用vnsprintf with 2nd arg == 0: 然后它应该返回所需的空间量并且 sprintfs 什么都没有.. 好吧,除了 HP !在这种 std 冲突下使用 vnsprintf 来确定所需空间的一种解决方案:malloc 1 字节到你的缓冲区(第一个arg) 并调用 vnsprintf(buf+buf.length,1,..)。这只会将 \0 放入您分配的新字节中。愚蠢但有效。如果您处于 wchar 条件下,malloc(sizeof..) .

无论如何,解决方法很简单:永远不要在 HP-UX 下使用 maxsize==0 调用 v/snprintf!我现在有一个快乐的稳定程序!

感谢所有贡献者。


在 HP-UX B11.11 下通过 vsnprintf 导致堆损坏 该程序在 Linux/Cygwin/.. 下打印“@@”。它在 HP-UX B11.11 下打印“@fooo@”:

#include <stdarg.h>
#include <stdio.h>

const int S=2;

void f (const char *fmt, ...) {
        va_list ap;
        int actualLen=0;
        char buf[S];

        bzero(buf, S);

        va_start(ap, fmt);
        actualLen = vsnprintf(buf, 0, fmt, ap);
        va_end(ap);

        printf("@%s@\n", buf);
}

int main () {
        f("%s", "fooo");
        return 0;
}
于 2009-03-10T11:35:14.947 回答
1

每当这种情况发生在我身上(系统库中出现意外的段错误)时,通常是因为我在其他地方做了一些愚蠢的事情,即缓冲区溢出、指针上的双重删除等。

在我的错误不明显的情况下,我使用 valgrind。像下面这样的东西通常就足够了:

valgrind -v --leak-check=yes --show-reachable=yes ./myprog

我假设 valgrind 可以在 HP-UX 中使用...

于 2009-03-06T16:43:48.030 回答
1

您的堆栈跟踪malloc几乎肯定意味着您在某处损坏了malloc's 的数据结构之一。正如先前的回答所说,您可能有缓冲区溢出或不足,并损坏了从堆中分配的项目之一。

另一种解释是,您尝试对free不是来自堆的东西执行 a 操作,但这不太可能——那可能会在free.

于 2009-03-06T22:18:58.240 回答
0

阅读(OS X)手册页说gethostbyname()返回一个指针,但据我所知,可能不会为该指针分配内存。你需要malloc()先吗?尝试这个:

struct hostent *him = malloc(sizeof(struct hostent));
him = gethostbyname(name);
...
free(him);

这样做效果更好吗?

编辑:我对此进行了测试,这可能是错误的。当然,我使用了裸字符串“stmp.org.com”而不是变量,但是两个版本(有和没有malloc()ing)都可以在 OS X 上运行。也许 HP-UX 是不同的。

于 2009-03-06T16:47:49.423 回答