I'm attempting to debug a stack overwrite (no pun intended) corruption problem with some c/c++ code in Visual Studio 2008.
When I compile the solution in win32 debug mode, I'm able to run the debugger and see a class get instantiated.
In the constructor call, we initialize some fixed length char[] member variables using memset.
If I use printf to print the memory location of the member variable, I get a value that is exactly 14 bytes past what the VS2008 watch/local var window reports as the memory location.
How does VS calculate what it thinks the memory address is of a variable?
Edit: I have compiled with Run Time Check options, and what I see is "Run-time Check Failure #2 - stack around variable 'varName' was corrupted.
Edit 3: Here is the abbreviated source
Header file:
//////////////////////////////////////////////////////////////////////
#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];
};
and the source code with constructor...
#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);
}
Output of printf:
m_szServer mem location: 01427308
Visual Studio 2008 Locals window
m`_szServer 0x014272fa "" char [128]`
It's off by 14... and when the code actually runs the very first memset, it does so starting with address 7308, not 72fa. It basically tramples contiguous memory regions (and thus, variables)
The debugger inserts extra space. This space is set to a pre-defined value, and if it's changed, the debugger knows that something has gone wrong. It's normal for compilers and debuggers to insert space that serves no apparent purpose.
If you have used a fixed-size char[], that immediately signals to me as a problem, since there's no explicit encapsulation. You could use a custom array type (such as boost::array) to write your own buffer overrun detection code. If you throw at this time, you will get a stack trace.
This is (probably) not going to fix your bug, but I would try to avoid C-style arrays if you can.
Unless you have some compelling reason to use the fixed-length arrays, replace them with std::vector which will be filled with 0x00 by default.
so instead of
const size_t MYCLASS::BUFLEN(16);
class myClass {
public:
myClass()
{
memset(buffer, 0, BUFLEN);
}
private:
static const size_t BUFLEN;
char buffer[BUFLEN];
};
you have
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;
};
Related
I created 50 threads to read the same file at the same time and then, in each thread, tried to write its content to new file that create with different name.
The code was supposed to generate 50 different files.
But I got unexpected results that it just generate 3~5 files.
When all the read the same file, there is no race-condition, and each thread is aimed to write its content to different file.
Can somebody help me? Thank you!
My code is listed below and it is a modification from Reference
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <thread>
void copy(const char *src_path, const char *dst_path);
int main(int argc, char **argv)
{
std::vector<std::thread> vth;
char *tmp = "Copy.deb";
for (int i = 0; i < 50; ++i)
{
char src[40];
memset(src, '\0', sizeof(src));
sprintf(src, "%d", i);
strcat(src, tmp);
vth.emplace_back(std::bind(copy, "Original.deb", strdup(src)));
}
for (int i = 0; i < 50; ++i)
{
vth[i].join();
}
return 0;
}
void copy(const char *src_path, const char *dst_path)
{
FILE *src, *dst;
int buffer_size = 8 * 1024;
char buffer[buffer_size];
size_t length;
src = fopen(src_path, "rb");
dst = fopen(dst_path, "wb");
while (!feof(src))
{
length = fread(buffer, 1, buffer_size, src);
fwrite(buffer, 1, length, dst);
}
fclose(src);
fclose(dst);
}
I believe your problem is that you are passing src (which is a pointer to a local variable on your main thread's stack) to your thread's entry function, but since your copy() function runs asynchronously in a separate thread, the char src[40] array that you are passing a pointer to has already been been popped off of the main thread's stack (and likely overwritten by other data) before the copy() function gets a chance to read its contents.
The easy fix would be to make a copy of the string on the heap, so that you can guarantee the string will remain valid until the the copy() function executes and reads it:
vth.emplace_back(std::bind(copy, "Original.deb", strdup(src)));
... and be sure to have your copy() function free the heap-allocation when it's done using it:
void copy(const char *src_path, const char *dst_path)
{
FILE *src, *dst;
int buffer_size = 8 * 1024;
char buffer[buffer_size];
size_t length;
src = fopen(src_path, "rb");
dst = fopen(dst_path, "wb");
free(dst_path); // free the string previously allocated by strdup()
[...]
Note that you don't currently have the same problem with the "Original.deb" argument since "Original.deb" is a string-literal and therefore stored statically in the executable, which means it remains valid for as long as the program is running -- but if/when you change your code to not use a string-literal for that argument, you'd likely need to do something similar for it as well.
This is my code. I want to get 5 strings from the user and espeak reads each of them when user interred it. But I get segmentation fault(core dumped) message.
#include <string.h>
#include <malloc.h>
#include <espeak/speak_lib.h>
int test()
{
espeak_POSITION_TYPE position_type;
espeak_AUDIO_OUTPUT output;
char *path=NULL;
int Buflength = 500, Options=0;
void* user_data;
t_espeak_callback *SynthCallback;
espeak_PARAMETER Parm;
char Voice[] = {"English"};
int i=0;
char text[1000];
unsigned int Size,position=0, end_position=0, flags=espeakCHARS_AUTO, *unique_identifier;
output = AUDIO_OUTPUT_PLAYBACK;
espeak_Initialize(output, Buflength, path, Options );
espeak_SetVoiceByName(Voice);
const char *langNativeString = "en_US";
espeak_VOICE voice={0};
voice.languages = langNativeString;
voice.name = "US";
voice.variant = 2;
voice.gender = 1;
Size = strlen(text)+1;
for (i=0; i<5; i++)
{
scanf("%s ", &text);
printf("%s", text);
espeak_Synth( text, Size, position, position_type, end_position, flags,
unique_identifier, user_data );
espeak_Synchronize( );
fflush(stdout);
}
return 0;
}
int main(int argc, char* argv[] )
{
test();
return 0;
}
I tried some modification but none of them worked. I want the program works like this:
User input: hi
espeak says: hi
user input: one
espeak says: one
(for 5
inputs)
But when I try to interring more than 4 characters as input,it gives segmentation fault error!
The two main issues are:
you use strlen on an uninitialized array of chars;
the unique_identifier argument of espeak_Synth must be NULL or point to an unsigned int (see the source code) while now it is an unsigned pointer to random memory.
Move strlen after scanf, use NULL instead of unique_identifier and your code will suddenly work (kind of).
There are many other issues though: useless variables, uninitialized variables, no input sanitization and more. IMO a better approach would be to throw away the test function and rewrite it from scratch properly.
Addendum
This is how I'd rewrite the above code. It is still suboptimal (no input sanitization, no error checking) but IMO it is much cleaner.
#include <stdio.h>
#include <string.h>
#include <espeak/speak_lib.h>
static void say(const char *text)
{
static int initialized = 0;
if (! initialized) {
espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, NULL, 0);
espeak_SetVoiceByName("en");
initialized = 1;
}
espeak_Synth(text, strlen(text)+1,
0, POS_CHARACTER, 0,
espeakCHARS_UTF8, NULL, NULL);
espeak_Synchronize();
}
int main()
{
char text[1000];
int i;
for (i = 0; i < 5; ++i) {
scanf("%s", text);
say(text);
}
return 0;
}
I use Visual Studio Micro C++ to program Arduino Mega1280 AVR.
I keep all my mixed types config parameters in a struct that is persisted in the 4096 Bytes EEPROM (in addition to other information saved in the EEPROM).
For every new program upload, I wish to check the new config against the EEPROM saved config, which I do byte by byte, updating only EEPROM bytes that differ.
My problem is that while the code compiles OK, (no errors/warnings) I do not get what I expect, and when reading the struct by bytes, I only get part of the expected info. I need help to make it work properly. Thanks.
Here is my simplified code:
#include <avr\eeprom.h>
#include <EEPROM.h>
#include <Arduino.h>
char configVersion[5] = "VS41";
unsigned int deviceID = 0xF0F0;
char deviceRev[5] = "ABCD";
char revDate[11] = "09-08-2014";
unsigned int dataArraySize = 150;
struct defineConfigs {
char configVersion[5];
unsigned int deviceID;
char deviceRev[5];
char revDate[11];
unsigned int dataArraySize;
byte mode;
byte refpage;
byte tolerance;
byte externalTrigger;
byte laserEnable;
}
configData=
{
{configVersion[5]},
deviceID,
{deviceRev[5]},
{revDate[11]},
dataArraySize,
1,
2,
0,
0,
0
};
unsigned int configBaseAddress=3840; //0x0F00
void Setup()
{
loadConfig(configBaseAddress);
}
void loadConfig(int configAddress) //EA
{
int s;
for ( s=0; s<sizeof(configData); s++) {
// Serial.println(*((char*)(&configData) + s),HEX); //Serial.print(","); //for testing
if (*((char*)(&configData) + s) == EEPROM.read(configAddress + s)) {
} else {
EEPROM.write(configAddress + s, *((byte*)(&configData) + s));
Serial.println(EEPROM.read(configAddress + s),HEX);
//read back for testing
}
}
}
Initialization of configData use uninitialized data
{configVersion[5]}
point on the first character after the array configVersion[0 ... 4]. This is not as you expect the litteral string "VS41".
You could check this printing configData.configVersion :
printf("%s\n", configData.configVersion);
Try to modify configData initialization like this :
struct defineConfigs {
char configVersion[5];
unsigned int deviceID;
char deviceRev[5];
char revDate[11];
unsigned int dataArraySize;
byte mode;
byte refpage;
byte tolerance;
byte externalTrigger;
byte laserEnable;
} configData = {
"VS41",
deviceID,
"ABCD",
"09-08-2014",
dataArraySize,
1,
2,
0,
0,
0
};
I've been at this for some time now. I need a basic IRC Ping Pong function to return the the proper response when the IRC server pings. I changed the name of the function get() to something else and I'm still getting the error. I thought perhaps the function name get() was already defined in one of the includes or something else.
#include "stdafx.h"
#include "Ping_Pong.h"
#include <iostream>
#include <ws2tcpip.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CWinApp theApp;
#define MT4_EXPFUNC __declspec(dllexport)
#pragma comment(lib, "Ws2_32.lib")
class MT4_EXPFUNC IRC {
private:
char buf[513];
char rbuf[513];
char sbuf[513];
char *tok;
int recv_bytes;
int irc_socket;
struct addrinfo hints;
struct addrinfo *results;
public:
char *nick, *user, *host, *chan, *type, *mesg;
int irc_connect(const char *host, const char *port, const char *nick);
void socket_err(const char* err_string);
//int join(const char *channel);
This is the name of the function in question
int __stdcall get();
char *check(const char* test_str);
char *pop_arg(char **save_ptr);
int init_comarg();
int say(const char *channel, const char *message);
int sayf(const char *channel, const char *message, ...);
int mode(const char *channel, const char *mode, char *target);
//void die();
};
And this is the function I'm having a problem with.
MT4_EXPFUNC int __stdcall IRC::get()
{
memset(rbuf, 0, 513);
recv_bytes = recv(irc_socket, rbuf, sizeof(rbuf), 0);
if (recv_bytes <= 0) {
return -1;
}
std::cout << rbuf;
// Auto-Respond to PING messages.
if (rbuf[0] == 'P' && rbuf[1] == 'I') {
tok = strtok(rbuf, "PING :");
sprintf(buf, "PONG %s", tok-1 );
send(irc_socket, buf, strlen(buf), 0);
std::cout << buf;
memset(buf, 0, 513);
}
if ( strstr(rbuf, "PRIVMSG")) {
memcpy(sbuf, rbuf, 513);
nick = strtok(sbuf, "!") + 1;
user = strtok(NULL, "#");
host = strtok(NULL, " ");
type = strtok(NULL, " ") - 1;
chan = strtok(NULL, " ");
mesg = strtok(NULL, ":");
}
return 1;
}
In the tutorial linked below, a .def file was suggested with the following code:
Library "Ping_Pong"
Export get
I removed the .def and it worked.
http://www.xpworx.com/metatrader-mql-articles/mql4-articles/create-your-own-metatrader-extension-dll.php
I've this C++ function,
bool MyClass::my_function(int num, TCHAR** filepath)
I've expose the function as
extern "C"
{
__declspec(dllexport) bool MyFunction(int num, char* filepath[])
{
OutputDebugStringA("--MyFunction--");
TCHAR **w_filepath = (TCHAR **)calloc(num, 2* sizeof(TCHAR **));
for(int i = 0; i < num; i++)
{
OutputDebugStringA(filepath[i]);
int len = strlen(filepath[i]) + 1;
w_filepath[i] = (TCHAR *)calloc (1, len);
ctow(w_filepath[i], filepath[i]); // converts char to WCHAR
}
bool ret = MyClass.my_function(num, w_filepath);
OutputDebugStringA("End -- MyFunction --");
free(w_filepath);
return ret;
}
}
I've C# wrapper as
[DllImport("MyDll.dll")]
public static extern bool MyFunction(int num, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPTStr)] string[] filepath);
In C#, i call Myfunction as
string [] filepath = { "D:\\samplefile\\abc.txt", "D:\\samplefile\\def.txt"}
MyFunction(2, filepath)
In C++ function, it gets only first character of filepath.
For example, from above call if i print in C++ code using
OutputDebugStringA
it prints only D for both first and second.
If i remove
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPTStr)]
from c# wrapper
I'll get Access violation error in
w_filepath[i] = (TCHAR *)calloc (1, len)
for second file.
Please help me.
1) w_filepath[i] = (TCHAR *)calloc (1, len); - calloc requires size in bytes, so it should be w_filepath[i] = (wchar_t *)calloc (1, len*sizeof(wchar_t));
2) data from c# comes as wchar_t*, so you don't need converting routines at all , and should change function declaration to
__declspec(dllexport) bool MyFunction(int num, wchar_t* filepath[])