我正在使用 Visual Studio 2013 Community Edition 编写命令行 C++ 程序。它通过 LDAP 连接到 Active Directory 服务器,并检索几个属性(例如:办公地点、部门)中的唯一值列表。
程序编译正常,但在运行时遇到内存访问问题:
LdapSearchResultTest1.exe 中 0x74EDC6B1 (Wldap32.dll) 处的未处理异常:0xC0000005:访问冲突读取位置 0xCCCCCCCC。
这是我第一次将 C++ 与外部库一起使用,所以我什至不确定如何调试它(通常我为 Android 编写 Java)。我花了一天的大部分时间环顾 SO 并根据对类似问题的答案尝试想法,但我仍然无法弄清楚。
确切的问题在于此函数调用中的最后一个参数:
// Do the search
int searchReturnCode = ldap_search_s(
ldapSession,
&searchBase[0],
LDAP_SCOPE_SUBTREE,
filter,
pAttributes,
0,
&pSearchResults); // Error is here
我的代码基于 MSDN 网站上的示例,我在我的代码之后复制了该示例。这是一个 SSCCE证明了这个问题:
#include<iostream>
#include<Windows.h>
#include<Winldap.h>
#include<WinBer.h>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
// Function headers
vector<string> get_unique_departments(LDAP*, char*, string);
vector<string> get_unique_office_locations(LDAP*, char*, string);
vector<string> get_unique_values_by_property(LDAP*, char*, string, string);
void print_list(string, vector<string>);
// Main function
int main(int argc, char* argv[]) {
/**
* Take AD connection arguments from Windows command line:
* - Server address
* - Server port
* - Username
* - Password
* - Search base(s) (space separated if there are multiple)
*
* Example call from Windows command line:
* > program.exe ad-test.example.com 389 joe@ad-test.example.com L3tM31n "OU=Development Team,DC=ad-test,DC=example,DC=com" "OU=Management Team,DC=ad-test,DC=example,DC=com"
*/
string serverAddress = argv[1];
int serverPort = atoi(argv[2]);
string username = argv[3];
string password = argv[4];
vector<string> searchBases;
for (int i = 0; i < argc; i++) {
searchBases.push_back(argv[i]);
}
// If debug build, print received parameters
#ifdef _DEBUG
cout << "Server address: " << serverAddress << endl
<< "Server port: " << serverPort << endl
<< "Username: " << username << endl
<< "Password: " << password << endl;
for (size_t i = 5; i < searchBases.size(); i++) {
cout << "Search base: " << searchBases.at(i) << endl;
}
cout << endl;
#endif
// Initiate LDAP connection to Active Directory
int ldapVersion = LDAP_VERSION3;
LDAP* ldapSession = ldap_init(&serverAddress[0], serverPort);
ldap_set_option(ldapSession, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion);
ULONG ldapConnection = ldap_connect(ldapSession, nullptr);
// Bind user
int ldapBindResult = ldap_simple_bind_s(ldapSession, &username[0], &password[0]);
if (ldapBindResult != LDAP_SUCCESS) {
ldap_unbind(ldapSession);
#ifdef _DEBUG
cout << "Unable to connect to LDAP directory" << endl << endl;
#endif
}
else {
#ifdef _DEBUG
cout << "Connected to LDAP!" << endl << endl;
#endif
}
// The LDAP object filter
char* filter = "(&(objectCategory=person)(objectClass=user))";
// Get lists of departments and offices
vector<string> departments, offices;
for (int i = 0; i < searchBases.size(); i++) {
vector<string> tempDepts = get_unique_departments(ldapSession, filter, searchBases.at(i));
vector<string> tempOffices = get_unique_office_locations(ldapSession, filter, searchBases.at(i));
for (int j = 0; j < tempDepts.size(); j++) {
departments.push_back(tempDepts.at(j));
}
for (int j = 0; j < tempOffices.size(); j++) {
offices.push_back(tempOffices.at(j));
}
}
// Print the lists
print_list("Departments", departments);
print_list("Offices", offices);
// Return
return 0;
}
// Retrieve a list of unique departments
vector<string> get_unique_departments(LDAP* session, char* filter, string searchBase) {
return get_unique_values_by_property(session, filter, searchBase, "department");
}
// Retrieve a list of unique office locations
vector<string> get_unique_office_locations(LDAP* session, char* filter, string searchBase) {
return get_unique_values_by_property(session, filter, searchBase, "office");
}
// Get a list of an attribute's unique values
vector<string> get_unique_values_by_property(LDAP* ldapSession, char* filter, string searchBase, string property) {
// Initialize some variables
vector<string> results;
char* pAttributes[1];
pAttributes[0] = &property[0];
LDAPMessage* pSearchResults = NULL;
int numResults = 0;
// Do the search
int searchReturnCode = ldap_search_s(
ldapSession,
&searchBase[0],
LDAP_SCOPE_SUBTREE,
filter,
pAttributes,
0,
&pSearchResults); // Error is here
// Process results
if (searchReturnCode == LDAP_SUCCESS) {
// Initialize some variables
LDAPMessage* pEntry = NULL;
char* pEntryDN = NULL;
char* sMsg;
BerElement* pBer = NULL;
char* pAttribute = NULL;
char** ppValue = NULL;
ULONG iValue = 0;
// Count the results
numResults = ldap_count_entries(ldapSession, pSearchResults);
// Loop over results
for (ULONG i = 0; i < numResults; i++) {
// Get the first/next entry
if (!i) {
pEntry = ldap_first_entry(ldapSession, pSearchResults);
}
else {
pEntry = ldap_next_entry(ldapSession, pEntry);
}
// Fail if unable to get entry
if (pEntry == NULL) {
results.clear();
return results;
}
// Loop over the attributes
pAttribute = ldap_first_attribute(ldapSession, pEntry, &pBer);
while (pAttribute != NULL) {
// Get and handle the values
ppValue = ldap_get_values(ldapSession, pEntry, pAttribute);
if (ppValue != NULL) {
iValue = ldap_count_values(ppValue);
if (find(results.begin(), results.end(), *ppValue) == results.end()) {
results.push_back(*ppValue);
}
// Memory management
ldap_value_free(ppValue);
ppValue = NULL;
ldap_memfree(pAttribute);
// Get the next attribute
pAttribute = ldap_next_attribute(ldapSession, pEntry, pBer);
}
}
// Memory management
if (pBer != NULL) {
ber_free(pBer, 0);
}
pBer = NULL;
}
}
// Free search result memory
if (pSearchResults != NULL) {
ldap_msgfree(pSearchResults);
}
// Return
return results;
}
// Print a vector-based list w/ header
void print_list(string header, vector<string> items) {
if (items.size() > 0) {
cout << header << ":" << endl;
for (int i = 0; i < items.size(); i++) {
cout << items.at(i) << endl;
}
cout << endl;
}
}
来自 https://msdn.microsoft.com/en-us/library/aa367016%28v=vs.85%29.aspx
//----------------------------------------------
// Performing an LDAP Synchronous Search.
//
// Be aware that you must set the command prompt screen buffer
// height to 350 and the width to 90.
//-------------------------------------------------------------
#include <windows.h>
#include <winldap.h>
#include <winber.h>
#include <rpc.h>
#include <rpcdce.h>
#include <stdio.h>
//-----------------------------------------------------------
// This subroutine must have validated credentials (name and
// password) passed to it.
//-----------------------------------------------------------
int MyLDAPSearch(PCHAR pUserName, PCHAR pPassword)
{
//---------------------------------------------------------
// Initialize a session. LDAP_PORT is the default port, 389.
//---------------------------------------------------------
PCHAR hostName = "fabrikam.com";
LDAP* pLdapConnection = NULL;
pLdapConnection = ldap_init(hostName, LDAP_PORT);
if (pLdapConnection == NULL)
{
printf("ldap_init failed with 0x%x.\n",LdapGetLastError());
ldap_unbind(pLdapConnection);
return -1;
}
else
printf("ldap_init succeeded \n");
//-------------------------------------------------------
// Set session options.
//-------------------------------------------------------
ULONG version = LDAP_VERSION3;
ULONG numReturns = 10;
ULONG lRtn = 0;
// Set the version to 3.0 (default is 2.0).
lRtn = ldap_set_option(
pLdapConnection, // Session handle
LDAP_OPT_PROTOCOL_VERSION, // Option
(void*) &version); // Option value
if(lRtn == LDAP_SUCCESS)
printf("ldap version set to 3.0 \n");
else
{
printf("SetOption Error:%0lX\n", lRtn);
ldap_unbind(pLdapConnection);
return -1;
}
// Set the limit on the number of entries returned to 10.
lRtn = ldap_set_option(
pLdapConnection, // Session handle
LDAP_OPT_SIZELIMIT, // Option
(void*) &numReturns); // Option value
if(lRtn == LDAP_SUCCESS)
printf("Max return entries set to 10 \n");
else
{
printf("SetOption Error:%0lX\n", lRtn);
ldap_unbind(pLdapConnection);
return -1;
}
//--------------------------------------------------------
// Connect to the server.
//--------------------------------------------------------
lRtn = ldap_connect(pLdapConnection, NULL);
if(lRtn == LDAP_SUCCESS)
printf("ldap_connect succeeded \n");
else
{
printf("ldap_connect failed with 0x%lx.\n",lRtn);
ldap_unbind(pLdapConnection);
return -1;
}
//--------------------------------------------------------
// Bind with credentials.
//--------------------------------------------------------
PCHAR pMyDN = "DC=fabrikam,DC=com";
SEC_WINNT_AUTH_IDENTITY secIdent;
secIdent.User = (unsigned char*)pUserName;
secIdent.UserLength = strlen(pUserName);
secIdent.Password = (unsigned char*)pPassword;
secIdent.PasswordLength = strlen(pPassword);
secIdent.Domain = (unsigned char*)hostName;
secIdent.DomainLength = strlen(hostName);
secIdent.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
lRtn = ldap_bind_s(
pLdapConnection, // Session Handle
pMyDN, // Domain DN
(PCHAR)&secIdent, // Credential structure
LDAP_AUTH_NEGOTIATE); // Auth mode
if(lRtn == LDAP_SUCCESS)
{
printf("ldap_bind_s succeeded \n");
secIdent.Password = NULL; // Remove password pointer
pPassword = NULL; // Remove password pointer
}
else
{
printf("ldap_bind_s failed with 0x%lx.\n",lRtn);
ldap_unbind(pLdapConnection);
return -1;
}
//----------------------------------------------------------
// Perform a synchronous search of fabrikam.com for
// all user objects that have a "person" category.
//----------------------------------------------------------
ULONG errorCode = LDAP_SUCCESS;
LDAPMessage* pSearchResult;
PCHAR pMyFilter = "(&(objectCategory=person)(objectClass=user))";
PCHAR pMyAttributes[6];
pMyAttributes[0] = "cn";
pMyAttributes[1] = "company";
pMyAttributes[2] = "department";
pMyAttributes[3] = "telephoneNumber";
pMyAttributes[4] = "memberOf";
pMyAttributes[5] = NULL;
errorCode = ldap_search_s(
pLdapConnection, // Session handle
pMyDN, // DN to start search
LDAP_SCOPE_SUBTREE, // Scope
pMyFilter, // Filter
pMyAttributes, // Retrieve list of attributes
0, // Get both attributes and values
&pSearchResult); // [out] Search results
if (errorCode != LDAP_SUCCESS)
{
printf("ldap_search_s failed with 0x%0lx \n",errorCode);
ldap_unbind_s(pLdapConnection);
if(pSearchResult != NULL)
ldap_msgfree(pSearchResult);
return -1;
}
else
printf("ldap_search succeeded \n");
//----------------------------------------------------------
// Get the number of entries returned.
//----------------------------------------------------------
ULONG numberOfEntries;
numberOfEntries = ldap_count_entries(
pLdapConnection, // Session handle
pSearchResult); // Search result
if(numberOfEntries == NULL)
{
printf("ldap_count_entries failed with 0x%0lx \n",errorCode);
ldap_unbind_s(pLdapConnection);
if(pSearchResult != NULL)
ldap_msgfree(pSearchResult);
return -1;
}
else
printf("ldap_count_entries succeeded \n");
printf("The number of entries is: %d \n", numberOfEntries);
//----------------------------------------------------------
// Loop through the search entries, get, and output the
// requested list of attributes and values.
//----------------------------------------------------------
LDAPMessage* pEntry = NULL;
PCHAR pEntryDN = NULL;
ULONG iCnt = 0;
char* sMsg;
BerElement* pBer = NULL;
PCHAR pAttribute = NULL;
PCHAR* ppValue = NULL;
ULONG iValue = 0;
for( iCnt=0; iCnt < numberOfEntries; iCnt++ )
{
// Get the first/next entry.
if( !iCnt )
pEntry = ldap_first_entry(pLdapConnection, pSearchResult);
else
pEntry = ldap_next_entry(pLdapConnection, pEntry);
// Output a status message.
sMsg = (!iCnt ? "ldap_first_entry" : "ldap_next_entry");
if( pEntry == NULL )
{
printf("%s failed with 0x%0lx \n", sMsg, LdapGetLastError());
ldap_unbind_s(pLdapConnection);
ldap_msgfree(pSearchResult);
return -1;
}
else
printf("%s succeeded\n",sMsg);
// Output the entry number.
printf("ENTRY NUMBER %i \n", iCnt);
// Get the first attribute name.
pAttribute = ldap_first_attribute(
pLdapConnection, // Session handle
pEntry, // Current entry
&pBer); // [out] Current BerElement
// Output the attribute names for the current object
// and output values.
while(pAttribute != NULL)
{
// Output the attribute name.
printf(" ATTR: %s",pAttribute);
// Get the string values.
ppValue = ldap_get_values(
pLdapConnection, // Session Handle
pEntry, // Current entry
pAttribute); // Current attribute
// Print status if no values are returned (NULL ptr)
if(ppValue == NULL)
{
printf(": [NO ATTRIBUTE VALUE RETURNED]");
}
// Output the attribute values
else
{
iValue = ldap_count_values(ppValue);
if(!iValue)
{
printf(": [BAD VALUE LIST]");
}
else
{
// Output the first attribute value
printf(": %s", *ppValue);
// Output more values if available
ULONG z;
for(z=1; z<iValue; z++)
{
printf(", %s", ppValue[z]);
}
}
}
// Free memory.
if(ppValue != NULL)
ldap_value_free(ppValue);
ppValue = NULL;
ldap_memfree(pAttribute);
// Get next attribute name.
pAttribute = ldap_next_attribute(
pLdapConnection, // Session Handle
pEntry, // Current entry
pBer); // Current BerElement
printf("\n");
}
if( pBer != NULL )
ber_free(pBer,0);
pBer = NULL;
}
//----------------------------------------------------------
// Normal cleanup and exit.
//----------------------------------------------------------
ldap_unbind(pLdapConnection);
ldap_msgfree(pSearchResult);
ldap_value_free(ppValue);
return 0;
}
最佳答案
阅读 ldap_search_s 的文档,我看到:
base [in]
Pointer to a null-terminated string that contains the distinguished name of the entry at which to start the search.
但是,&searchBase[0] 只会为您提供一个指向存储空间的指针,std::string 使用 - 不需要以 null 终止。您应该改用 searchBase.c_str(),因为这可以保证为您提供一个空终止的 c 字符串。
关于c++ - 读取内存时访问冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30337642/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以
ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是: