Visual Studio 2008 C++ 误报内存地址位置
Posted
技术标签:
【中文标题】Visual Studio 2008 C++ 误报内存地址位置【英文标题】:Visual Studio 2008 C++ misreporting memory address location 【发布时间】:2010-09-21 15:07:02 【问题描述】:我正在尝试调试 Visual Studio 2008 中某些 c/c++ 代码的堆栈覆盖(没有双关语)损坏问题。
当我在 win32 调试模式下编译解决方案时,我能够运行调试器并看到一个类被实例化。
在构造函数调用中,我们使用memset初始化了一些固定长度的char[]成员变量。
如果我使用 printf 打印成员变量的内存位置,我得到的值正好超过 VS2008 监视/本地 var 窗口报告的内存位置的 14 个字节。
VS 如何计算它认为变量的内存地址是什么?
编辑:我已使用运行时检查选项进行编译,我看到的是“运行时检查失败 #2 - 变量 'varName' 周围的堆栈已损坏。
编辑 3:这是缩写源
头文件:
//////////////////////////////////////////////////////////////////////
#include "commsock.h"
#include "buffer.h"
#include "BufferedReader.h"
#define AUTHTYPE_PASSKEY 1
#define AUTHTYPE_PAGER 2
#define AUTHTYPE_PASSWORD 3
#define AUTHTYPE_RADIUS 4
#define AUTHTYPE_INFOCARD_RO 5
#define AUTHTYPE_INFOCARD_CR 6
#define AUTHSTATE_NOT_LOGGED_IN 0
#define AUTHSTATE_IDENTIFIED 1
#define AUTHSTATE_AUTHENTICATED 2
#define AUTHSTATE_MAX_FAILS 32
#define AUTHSTATE_NO_LOG 65536
class PRClientSession
public:
PRClientSession();
virtual ~PRClientSession();
void Reset();
BOOL BeginAuth(LPCSTR szUserID, LPCSTR szClientIP, LPCSTR szOtherUserID="");
BOOL CompleteAuth(LPCSTR szResponse);
BOOL Logoff();
BOOL DetachAsync();
BOOL Detach();
BOOL Attach(const char *authstr=NULL);
BOOL Connected()return m_Socket.Connected();;
BOOL EncryptText(char *pPassword, char *pOut, char *pKey);
BOOL EncryptText(char *pPassword, char *pOut);
BOOL DecryptText(char *pPassword, char *pOut, char *pKey);
BOOL DecryptText(char *pPassword, char *pOut);
LPCSTR Error(LPCSTR szErr=NULL)if (szErr)strncpy_s(m_szError,szErr,sizeof(m_szError));return m_szError;;
LPCSTR Challenge(LPCSTR szChal=NULL)if (szChal)strncpy_s(m_szChallenge,szChal,sizeof(m_szChallenge));return m_szChallenge;;
LPCSTR UserID(LPCSTR szUID=NULL)if (szUID)strncpy_s(m_szUserID,szUID,sizeof(m_szUserID));return m_szUserID;;
LPCSTR SessionID(LPCSTR szSID=NULL)if (szSID)strncpy_s(m_szSessionID,szSID,sizeof(m_szSessionID));return m_szSessionID;;
LPCSTR SessionLogID(LPCSTR szSLID=NULL)if (szSLID)strncpy_s(m_szSessionLogID,szSLID,sizeof(m_szSessionLogID));return m_szSessionLogID;;
LPCSTR SessionStateID(LPCSTR szSSID=NULL)if (szSSID)strncpy_s(m_szSessionStateID,szSSID,sizeof(m_szSessionStateID));return m_szSessionStateID;;
int AuthType(int iType=-1)if (iType != -1)m_iAuthType = iType;return m_iAuthType;;
int SendRequest(LPCSTR szType, ...);
int Write(char *szBuf, int iLen=-1);
int Read(char *szBuf, int iLen, int iTimeout=-1);
BOOL ReadResponse(int iBlock=FALSE);
int ReadResponseTimeout(int iBlock) ;
BOOL GetField(LPCSTR szField, char *szBuf, int iLen, int total=-1);
BOOL GetField(LPCSTR szField, int &iBuf );
char *GetData()return m_pData;;
int GetDataSize()return m_iDataSize;
char *GetMessage()return m_pMessage;;
SOCKET getSocket()return m_Socket.getSocket();
private:
BOOL LoadConfig();
BOOL GetMsgField(LPCSTR szIn, LPCSTR szSrch, char *szBuf, int iLen, int total=-1);
int ReadMessage( char *buf, int len, const char *terminator = NULL );
public:
bool sendCommand(char* szCommand, char *szArglist);
LPCSTR ReplyMessage() return m_szReplyMessage;
int IsRadiusChallenge() return m_iIsRadiusChallenge;
static char PRIISMS_USER_TAG[];
static char DEST_USER_TAG[];
static char RADIUS_USER_TAG[];
static char RADIUS_PASSWORD_TAG[];
static char GENERATE_LOGIN[];
static char VALIDATE_LOGIN[];
static char PR_RADIUS_GENERATED[];
private:
BOOL doConnect();
// Response reader vars...
char *m_pMessage;
char *m_pData;
Buffer m_Buf;
BOOL m_bLoaded;
BufferedReader m_reader;
Buffer m_ReqBuf;
CCommSocket m_Socket;
char m_szServer[128];
int m_iServerPort;
char m_szError[128];
int m_iAuthState;
int m_iDataSize;
int m_iAuthType;
char m_szChallenge[1024];
char m_szUserID[64];
char m_szSessionID[64];
char m_szSessionLogID[64];
char m_szSessionStateID[64];
char m_szSessionSecret[16];
long m_RequestID;
int m_iIsRadiusChallenge;
char m_szReplyMessage[1024];
;
以及带有构造函数的源代码...
#include "stdafx.h"
#include "PRclntsn.h"
#include "iondes.h"
#include "prsystemparameters.h"
#include "prsessionlog.h"
#include "util.h"
#include "PRClntSn.h"
#include <string>
using namespace std;
#define LoadConfigFailedMsg "Unable to retrieve database configuration entries."
#ifndef AUTH_TYPE_RADIUS
#define AUTH_TYPE_RADIUS 4
#endif
//------------------------------------------------------------------------------------
// initialize static members
char PRClientSession::DEST_USER_TAG[] = "DEST_USER=";
char PRClientSession::PRIISMS_USER_TAG[] = "PRIISMS_USER=";
char PRClientSession::RADIUS_USER_TAG[] = "RADIUS_USER=";
char PRClientSession::RADIUS_PASSWORD_TAG[] = "RADIUS_PASSWORD=";
char PRClientSession::GENERATE_LOGIN[] = "GENERATE_LOGIN";
char PRClientSession::VALIDATE_LOGIN[] = "VALIDATE_LOGIN";
char PRClientSession::PR_RADIUS_GENERATED[] = "PR_RADIUS_GENERATED";
PRClientSession::PRClientSession()
Reset();
void PRClientSession::Reset()
//LOG4CXX_TRACE(mainlogger, CLASS_METHOD_TAG);
printf("m_szServer mem location: %p", (void *)&m_szServer);
memset(m_szServer, 0, sizeof(m_szServer));
m_iServerPort = 0;
memset(m_szError, 0, sizeof(m_szError));
m_iAuthState = 0;
m_iDataSize = 0;
m_iAuthType = 0;
memset(m_szChallenge, 0, sizeof(m_szChallenge));
memset(m_szUserID, 0, sizeof(m_szUserID));
memset(m_szSessionID, 0, sizeof(m_szSessionID));
memset(m_szSessionLogID, 0, sizeof(m_szSessionLogID));
memset(m_szSessionStateID, 0, sizeof(m_szSessionStateID));
memset(m_szSessionSecret, 0, sizeof(m_szSessionSecret) );
// memset(m_szReadBuf, 0, sizeof(m_szReadBuf));
m_RequestID = 0;
m_iIsRadiusChallenge = 0;
memset(m_szReplyMessage, 0, sizeof(m_szReplyMessage));
m_reader.setComm(&m_Socket);
printf 的输出:
m_szServer mem location: 01427308
Visual Studio 2008 局部变量窗口
m`_szServer 0x014272fa "" char [128]`
它在 14 点关闭...当代码实际运行第一个 memset 时,它从地址 7308 开始,而不是 72fa。它基本上践踏了连续的内存区域(因此,变量)
【问题讨论】:
堆栈溢出(线程中的堆栈空间不足),或堆栈覆盖(函数损坏堆栈)? 您能否发布一些输出,更详细地解释您的意思?据我了解,您所说的是在可视化调试器中显示的字符数组的地址与打印时的地址不同。这是正确的吗? 由于您使用的是 memset,您是否确认您没有在分配后立即覆盖内存?也是字符串的空终止字符。 Steve,最初我们在程序中看到的是后期,当从函数返回时,我们会得到堆栈损坏。当我深入研究并试图找出问题所在时,我注意到该类以某种方式错位了。我在源代码和标题中查找了编译指示包,但没有找到。 如果可以的话,我会发布相关函数的代码。使用代码图标 (101010) 获得良好的格式 【参考方案1】:调试器插入额外的空间。这个空间被设置为一个预定义的值,如果它被改变,调试器就知道出了问题。编译器和调试器插入没有明显用途的空间是正常的。
如果您使用了固定大小的 char[],这会立即向我表明存在问题,因为没有明确的封装。您可以使用自定义数组类型(例如 boost::array)来编写自己的缓冲区溢出检测代码。如果此时抛出,则会得到堆栈跟踪。
【讨论】:
它是 C/C++ 代码的混合体 - 该项目在 Visual Studio 6.0 中运行。我们已将代码移至 VS2008,但现在调试器无法正确显示。 @MattLear:首先要做的是更新你的编译器。 VS6.0 是臭名昭著的,而且不是很好。您很有可能刚刚发现了一个错误。其次,您确实必须开始发布有关代码的 C 部分的内容,但我猜您没有在该部分中实例化类,所以我的帖子仍然适用。编辑:等等,你的 OP 说你在 VS9 中。你到底在用什么编译器? @DeadMG - 听到听到。 VC6 运行“OK”的东西,然后新的编译器发现了简单的错误。我也见过这个。也用于 boost::array 或 scoped_array DeadMG:代码最初是使用 VS 6.0 C++ 开发的。我们已经将项目迁移到 VS2008 C++ 并且它编译没有错误(是的,很多警告,是的,我知道它们可能是一个问题)。我想我还在尝试了解 VS 内存工具如何误报内存位置? @MattLear:用于内部调试信息。调试器可能会包含该空间,而代码内运算符& 不会。 boost::array 仍然是你最好的选择。【参考方案2】:这(可能)不会修复您的错误,但如果可以的话,我会尽量避免使用 C 样式的数组。
除非你有一些令人信服的理由来使用固定长度的数组,否则用 std::vector 替换它们,默认情况下会用 0x00 填充。
所以而不是
const size_t MYCLASS::BUFLEN(16);
class myClass
public:
myClass()
memset(buffer, 0, BUFLEN);
private:
static const size_t BUFLEN;
char buffer[BUFLEN];
;
你有
const size_t MYCLASS::BUFLEN(16);
class myClass
public:
myClass() : buffer(BUFLEN)
memset(buffer, 0, BUFLEN);
private:
static const size_t BUFLEN;
std::vector<char> buffer;
;
【讨论】:
以上是关于Visual Studio 2008 C++ 误报内存地址位置的主要内容,如果未能解决你的问题,请参考以下文章
我可以在 Visual Studio 2008 中使用 Visual Studio 6 编译的 C++ 静态库吗?
如何在visual studio2008中创建,编译和运行C++程序,