涉及来自 openldap 库的 ldap_url_parse 函数的令人困惑的分段错误

confusing segmentation fault involving ldap_url_parse function from openldap library

在 CentOS 6.6 服务器上,以下代码编译(使用 gcc 版本 4.4.7 或使用 clang 版本 3.4.2)没有发生意外,但在 运行 时导致分段错误:

#include <ldap.h>

int main( int argc, char **argv )
{
    LDAPURLDesc **ludpp;
    int parse_status = ldap_url_parse("ldap://ldap.example.com", ludpp);
    char * str;
}

但是,如果我修改它以删除字符串声明,如下所示:

#include <ldap.h>

int main( int argc, char **argv )
{
    LDAPURLDesc **ludpp;
    int parse_status = ldap_url_parse("ldap://ldap.example.com", ludpp);
}

然后它 运行 也没有发生任何事故。在我的 Mac OS X 10.10.3 (Yosemite) 两个版本(有和没有字符串声明)编译和 运行.

我的三个问题是:

  1. 为什么 CentOS 服务器上的第一个示例会出现段错误?
  2. 为什么第二个例子在 CentOS 服务器上没有出现段错误?
  3. 具体来说,我的 Mac 笔记本电脑和 Linux 服务器之间的区别是什么导致了两者之间的这种差异?

您打算像这样使用函数:

#include <ldap.h>

int main( int argc, char **argv )
{
    LDAPURLDesc *ludp;
    int parse_status = ldap_url_parse("ldap://ldap.example.com", &ludp);
}

这允许函数设置您随后将在变量 ludp 中看到的值(指向动态分配的解析结果的指针)。请注意,在这种情况下,第二个函数参数是一个有效的指针。

然而,在您的原始代码中,您传递了一个未初始化指针的值。这绝对是无用的,因为函数可能对该值执行的任何操作都没有定义的行为。可能导致的一种更可能的行为是分段错误,但决不能保证这样的结果(c.f。"undefined")。

此外,您的代码负责在不再需要时释放以这种方式提供的对象,这应该通过 ldap_free_urldesc() 来实现。这在测试程序中无关紧要,因为它无论如何都会立即退出,但如果在真正的程序中你只是继续然后就会发生内存泄漏——尤其是如果你丢失了 ldap_url_parse() 提供的指针,通过覆盖它或让它超出范围。