【问题标题】:Adding an std::string definition causes Access Violation添加 std::string 定义会导致访问冲突
【发布时间】:2011-12-19 10:09:06
【问题描述】:

编辑: 亲爱的未来读者,std::string 与问题无关。这是一个未终止的数组。

简而言之,问题在于向仅包含 C 的程序添加单个 std::string 的声明会导致错误“访问冲突读取位置 0xffffffffffffffffe。”

在下面的代码中,如果声明 std::string 的行被注释掉,程序运行完成而没有错误。但是,如果该行留在程序中(未注释),则程序会因上述访问冲突错误而崩溃。当我在 VS2010 调试器中打开正在运行的程序时,调用 ldap_search_sA() 时发生了访问冲突。

请注意,声明的 std::string 从未使用过。不必使用它来导致访问冲突。简单地声明它会导致访问冲突。

我怀疑它与 LDAP 代码无关,但我可能是错的。

int main() 
{
    try {
        // Uncommenting the next line causes an Access Violation 
        // at the call to ldap_search_sA().
        // std::string s;
        LDAP* pLdapConnection = ldap_initA("eu.scor.local", LDAP_PORT);
        ULONG version = LDAP_VERSION3;
        ldap_set_option(pLdapConnection, LDAP_OPT_PROTOCOL_VERSION, (void*) &version);         
        ldap_connect(pLdapConnection, NULL);
        ldap_bind_sA(pLdapConnection, NULL, NULL, LDAP_AUTH_NTLM);
        LDAPMessage* pSearchResult;
        PCHAR pMyAttributes[2];
        pMyAttributes[0] = "cn";
        pMyAttributes[1] = "description";
        ldap_search_sA(pLdapConnection, "dc=eu,dc=scor,dc=local", LDAP_SCOPE_SUBTREE,  "objectClass=computer)", pMyAttributes, 0, &pSearchResult);    
    } catch (...) {
        printf("exception\n");
    }
    return 0;
}

【问题讨论】:

  • 我不知道这个 LDAP 的东西,但我怀疑你在某处调用 Undefined Behavior 并且该字符串的定义(!) 只是使它表现为一个 AV。
  • 好的,所以您认为这实际上是对 LDAP 的不当使用,我应该深入了解一下吗? (如果是“是”,则无需回答。)
  • 是的,我相信这一点,同时班塔尔也发现了问题所在。

标签: c++ visual-studio-2010 access-violation


【解决方案1】:
    PCHAR pMyAttributes[2];
    pMyAttributes[0] = "cn";
    pMyAttributes[1] = "description";

属性数组应该以NULL结尾:

    PCHAR pMyAttributes[3];
    pMyAttributes[0] = "cn";
    pMyAttributes[1] = "description";
    pMyAttributes[2] = NULL;

【讨论】:

  • 耶!!!抱歉浪费了大家宝贵的时间!我应该把支票寄到哪里? :)
  • 为什么要指定长度,然后使用赋值?初始化将允许编译器自己计算长度。
  • 复制/粘贴/修改我的代码可能比以您描述的样式编写新声明要快。只是猜测......
【解决方案2】:

我不知道ldap_search_sA 是什么,但是ldap_search 中的函数 OpenLDAP 采用指向以空指针结尾的char* 数组的指针。 您传递的数组未正确终止,因此任何事情都可能 发生。一般来说,我建议为此使用std::vector<char*>, 并将调用包装在一个系统地后缀的 C++ 函数中 终结者,所以你不会忘记。虽然在这种简单的情况下:

char* attributes[] = { "cn", "description", NULL };

会成功的。它可能会引起警告;它真的应该 是:

char const* attributes[] = { ... };

但是 OpenLDAP 接口是旧版 C,它忽略了 const,所以你会 在呼叫站点需要const_cast。 (包装的另一个论据 函数。)

最后,我强烈建议你放弃混淆 typedefs 喜欢PCHAR;他们只是让代码不那么清晰。

【讨论】:

  • FWIW:我通常声明这种事情 static 和 const (但 const 稍后需要 const_cast)。那是static char const* const attributes[] = {...};。关于您的代码,我可能会添加:C 样式数组的一个优点是您不必指定数组的大小。编译器根据初始化值自行计算。
【解决方案3】:

根据我的经验,当在 C++ 中观察到这样的奇怪事情时,实际上发生的是某处的某些代码损坏了内存,而这种损坏可能以各种奇怪的方式表现出来,包括它可能根本不表现出来。这些表现形式因事物在内存中的位置而异,因此引入新变量可能会导致事物在内存中的移动刚好足以引起损坏的表现,否则将不会表现出来。所以,如果我站在你的立场上,我会完全忘记字符串本身,我会专注于代码的其余部分,试图弄清楚你在那里做了什么会破坏内存。

我注意到你调用了几个函数而不检查它们的返回值,即使这些函数的规范中没有抛出异常。因此,如果这些函数中的任何一个失败(从 ldap_initA 开始)并且您继续假设它没有失败,那么您可能会遇到内存损坏。你检查过这个吗?

【讨论】:

  • 谢谢迈克,你是对的。我的未终止阵列是罪魁祸首。我最初确实检查了所有返回值,但将它们取出以使发布的代码更紧凑。有趣的是,没有 std::string DEFINITION (不是声明),未终止的数组没有问题。你真的必须精通 C/C++ 才能使用它。不适合像我这样的轻量级...
  • 是的,当然,@Banthar 值得称赞,因为只需查看代码即可准确了解问题所在。 (我不知道,因为我不熟悉 LDAP。)
猜你喜欢
  • 2012-05-22
  • 2016-06-15
  • 2023-03-08
  • 2023-03-15
  • 2016-07-18
  • 1970-01-01
  • 2010-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多