Sometimes cannot get stack range from /proc/self/maps - c++

I have one problem. I am trying to get stack offset range from /proc/self/maps pseudofile. But I have sometime weird things.
Here is my code
fp = fopen("/proc/self/maps", "r");
if (fp == NULL) {
perror("Error opening file");
return NULL;
}
while (fgets(line, 2048, fp) != NULL) {
if (strstr(line, "stack") != NULL) {
printf("%s", line);
}
}
If you start the programm with one or multiple thread you can view this pseudo file and get something like this
7f20423a6000-7f2042ba6000 rw-p 00000000 00:00 0 [stack:3936]
7fffbe95e000-7fffbe97f000 rw-p 00000000 00:00 0 [stack]
the first line here is stack of thread , the second line is the stack of the process.
But the problem is that sometimes I cannot get stack of thread. It can be from the first time or appear on some next execution so it is not determined. On some distos it doesn't show stack of thread at all, I don't think the problem is in different implementation of pseudo file in distros but in something other.
Please help to solve this problem
EDIT
I actually call this function inside thread , so I create thread through pthread_create(&tid, NULL, proc_stack, NULL);I have been also thinking about this. Maybe it needs some time to update this pseudofile after thread start, this is only one reason I see here.
EDIT2
I've tried to call sleep forcely , but this didn't help, but the most weird is that on one distro it shows thread stack, on another doesn't.

On my system Your program also dosn't show second stack segment, but it seems 5 segments are allocated above [heap] and one of them is used for thread stack (local variables of proc_stack() are stored in this segment).
Code I used to check for it (test.c):
#include <stdio.h>
#include <string.h>
#include <pthread.h>
void* proc_stack(void* p){
FILE *fp;
char line[2048];
fp = fopen("/proc/self/maps", "r");
if (fp == NULL) {
perror("Error opening file");
return NULL;
}
while (fgets(line, 2048, fp) != NULL) {
// if (strstr(line, "stack") != NULL) {
printf("%s", line);
// }
}
printf("addr = %p %p\n", &fp, &line);
return NULL;
}
int main(){
pthread_t tid;
void *rv;
proc_stack( NULL );
puts("main");
pthread_create( &tid, NULL, proc_stack, NULL );
pthread_join( tid, &rv );
return 0;
}
Compiled with gcc -Wall test.c -pthread. Results (some lines removed):
...
01933000-01954000 rw-p 00000000 00:00 0 [heap]
...
7fff75be3000-7fff75c04000 rw-p 00000000 00:00 0 [stack]
7fff75d97000-7fff75d98000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
addr = 0x7fff75c00e68 0x7fff75c00e70
main
...
01933000-01954000 rw-p 00000000 00:00 0 [heap]
7f3be0000000-7f3be0021000 rw-p 00000000 00:00 0
7f3be0021000-7f3be4000000 ---p 00000000 00:00 0
7f3be6b79000-7f3be6b7a000 rw-p 00000000 00:00 0
7f3be6b7a000-7f3be6b7b000 ---p 00000000 00:00 0
7f3be6b7b000-7f3be737b000 rw-p 00000000 00:00 0
...
7fff75be3000-7fff75c04000 rw-p 00000000 00:00 0 [stack]
7fff75d97000-7fff75d98000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
addr = 0x7f3be73796c8 0x7f3be73796d0

Related

ptrace fails when injecting code into old ELF binary (2005)

I have a very old gameserver file for a video-game that became obsolete years ago (more than a decade and a half has passed since then). A lot of clones and reverse-engineered copycats of this engine exist, but nothing will ever be like the real thing, or at least without tons and tons of work (it's a MMORPG server). It's so old that it uses LinuxThreads instead of NPTL, and uses it for its thread-per-connection architecture (up to 1100 simmultaneos connections interacting with a huge 2D tilebased game world).
I was trying to rewrite it from scratch, since it has ancient GCC debug info available, but had to drop it since the amount of work to do was insane. Now I'm trying to inject new functionality into it, but couldn't proggress any further since I don't really understand how I'm supposed to inject into it.
I've tried coding a very simple injector using ptrace, but the server dies because of a segmentation fault (SIGSEGV) and since I can't attach GDB, I don't really know where the crash is happening.
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#define EMPTY_ADDR 0x80EF000UL
const char *SHELLCODE = "\x90\x90\x90\x90\x90\x90\x90\x90";
pid_t GamePID;
void GetGamePID() {
FILE *fp = fopen("/home/bob/lock.pid", "rb");
if (!fp) {
printf(":: [Error] Game not running.\n");
return;
}
fscanf(fp, "%d", &GamePID);
}
int main() {
GetGamePID();
if (!GamePID)
return 0;
if (ptrace(PTRACE_ATTACH, GamePID, NULL, NULL)) {
printf(":: [Error] Cannot attach.\n");
printf(":: # Fail %d: %s.\n", errno, strerror(errno));
return 0;
}
siginfo_t info;
waitid(P_PID, GamePID, &info, WSTOPPED);
printf(":: [Info] Attach on PID %d.\n", GamePID);
struct user_regs_struct oldregs, regs;
if (ptrace(PTRACE_GETREGS, GamePID, NULL, &oldregs)) {
printf(":: [Error] Cannot save registers (Fail %d).\n", errno);
ptrace(PTRACE_DETACH, GamePID, NULL, NULL);
return 1;
}
unsigned long save[2];
save[0] = ptrace(PTRACE_PEEKTEXT, GamePID, (void *)(EMPTY_ADDR), NULL);
save[1] = ptrace(PTRACE_PEEKTEXT, GamePID, (void *)(EMPTY_ADDR + 8UL), NULL);
size_t payload_size = strlen(SHELLCODE);
uint64_t *payload = (uint64_t *)SHELLCODE;
printf("[*] Injecting payload at address 0x%lx.\n", EMPTY_ADDR);
for (size_t i = 0; i < payload_size; i += 8, payload++) {
if (ptrace(PTRACE_POKETEXT, GamePID, EMPTY_ADDR + i, *payload) < 0) {
printf(":: [Error] Failed to PTRACE_POKETEXT: %s\n", strerror(errno));
return 1;
}
}
regs = oldregs;
regs.rip = EMPTY_ADDR;
if (ptrace(PTRACE_SETREGS, GamePID, NULL, &regs)) {
printf(":: [Error] Cannot modify registers.\n");
ptrace(PTRACE_DETACH, GamePID, NULL, NULL);
return 1;
}
if (ptrace(PTRACE_CONT, GamePID, NULL, NULL)) {
printf(":: [Error] Cannot run shellcode.\n");
ptrace(PTRACE_DETACH, GamePID, NULL, NULL);
return 1;
}
waitid(P_PID, GamePID, &info, WSTOPPED);
// I used blank r-xp space but just in case...
if (ptrace(PTRACE_POKETEXT, GamePID, (void *)(EMPTY_ADDR), (void *)save[0]) ||
ptrace(PTRACE_POKETEXT, GamePID, (void *)(EMPTY_ADDR + 8UL), (void *)save[1])) {
printf(":: [Error] Cannot restore origcode.\n");
ptrace(PTRACE_DETACH, GamePID, NULL, NULL);
return 1;
}
if (ptrace(PTRACE_SETREGS, GamePID, NULL, &oldregs)) {
printf(":: [Error] Cannot restore registers.\n");
ptrace(PTRACE_DETACH, GamePID, NULL, NULL);
return 1;
}
if (ptrace(PTRACE_DETACH, GamePID, NULL, NULL)) {
printf(":: [Error] Cannot detach from process.\n");
return 1;
}
puts("[+] Done.");
}
That's how my injector looks like. Strings and whatnot is hardcoded because this is dummy code. Here is /proc/pid/maps output:
08047000-08048000 rwxp 00000000 08:01 549662 /home/bob/bin/game.orig
08048000-08125000 r-xp 00001000 08:01 549662 /home/bob/bin/game.orig
08125000-08129000 rwxp 000dd000 08:01 549662 /home/bob/bin/game.orig
08129000-0eb45000 rwxp 00000000 00:00 0
0f3e2000-14f10000 rwxp 00000000 00:00 0 [heap]
c573f000-f7b69000 rwxp 00000000 00:00 0
f7b6a000-f7b71000 rwxs 00000000 00:01 32821 /SYSV0000271b (deleted)
f7b71000-f7b72000 rwxp 00000000 00:00 0
f7bb5000-f7beb000 rwxp 00000000 00:00 0
f7bec000-f7d3e000 rwxp 00000000 00:00 0
f7d3e000-f7e57000 r-xp 00000000 08:01 1041510 /home/bob/lib/libc.so.6
f7e57000-f7e59000 r-xp 00119000 08:01 1041510 /home/bob/lib/libc.so.6
f7e59000-f7e5b000 rwxp 0011b000 08:01 1041510 /home/bob/lib/libc.so.6
f7e5b000-f7e5d000 rwxp 00000000 00:00 0
f7e5d000-f7e66000 r-xp 00000000 08:01 1041511 /home/bob/lib/libgcc_s.so.1
f7e66000-f7e67000 rwxp 00009000 08:01 1041511 /home/bob/lib/libgcc_s.so.1
f7e67000-f7e68000 rwxp 00000000 00:00 0
f7e68000-f7e8c000 r-xp 00000000 08:01 1041512 /home/bob/lib/libm.so.6
f7e8c000-f7e8d000 r-xp 00023000 08:01 1041512 /home/bob/lib/libm.so.6
f7e8d000-f7e8e000 rwxp 00024000 08:01 1041512 /home/bob/lib/libm.so.6
f7e8e000-f7f3d000 r-xp 00000000 08:01 1041514 /home/bob/lib/libstdc++.so.5
f7f3d000-f7f42000 rwxp 000ae000 08:01 1041514 /home/bob/lib/libstdc++.so.5
f7f42000-f7f47000 rwxp 00000000 00:00 0
f7f47000-f7f56000 r-xp 00000000 08:01 1041513 /home/bob/lib/libpthread.so.0
f7f56000-f7f57000 r-xp 0000e000 08:01 1041513 /home/bob/lib/libpthread.so.0
f7f57000-f7f58000 rwxp 0000f000 08:01 1041513 /home/bob/lib/libpthread.so.0
f7f58000-f7f9b000 rwxp 00000000 00:00 0
f7f9b000-f7f9e000 r--p 00000000 00:00 0 [vvar]
f7f9e000-f7f9f000 r-xp 00000000 00:00 0 [vdso]
f7f9f000-f7fb8000 r-xp 00000000 08:01 1041509 /home/bob/lib/ld-linux.so.2
f7fb8000-f7fb9000 r-xp 00018000 08:01 1041509 /home/bob/lib/ld-linux.so.2
f7fb9000-f7fba000 rwxp 00019000 08:01 1041509 /home/bob/lib/ld-linux.so.2
ff000000-ff001000 ---p 00000000 00:00 0
ff001000-ff200000 rwxp 00000000 00:00 0
ff200000-ff201000 ---p 00000000 00:00 0
ff201000-ff400000 rwxp 00000000 00:00 0
ff400000-ff401000 ---p 00000000 00:00 0
ff401000-ff600000 rwxp 00000000 00:00 0
ff600000-ff601000 ---p 00000000 00:00 0
ff601000-ff800000 rwxp 00000000 00:00 0
fff4b000-fffa2000 rwxp 00000000 00:00 0 [stack]
My server spawns each thread as an independent process, and as you can see I had to use my libraries (/home/bob/lib) copied from and ancient RedHat version which was compatible with the threading model (getpid() returns a different value for each thread).
I would really like to hear some suggestions on how I can inject new code. Is it just as hacky as writing directly to /proc/pid/mem? How would I override a game function (say, HandlePlayerMove) with /proc/pid/mem? Is it possible to inject a shared object using LD_PRELOAD given that it was compiled against a newer version of libc, libm, etc? Is there a way of knowing what's triggering SIGSEGV without ptrace failing?
edit: dummy code typo

mmap error : segmentation fault/invalid pointer error

I am new to mmap and still learning it . Based on my understanding i have created class for mmap which will be used to map a file in memory . The entire class is working fine but problem is coming when destructor is called ..the problem is segmentation fault or invalid pointer error is coming at the end of main function ...I have posted code of my class and main function which is using that class ...
Map.h
class MapData
{
public :
MapData();
~MapData();
MapData(char []);
bool OPEN();
void fnClose();
long fnGetSize();
char * fnGetFileRef();
char * ReadNextData(int );
private :
char * ptrRecord;
char ptrFileNm[250+1];
int fd;
struct stat sbuf;
bool bSuccess;
long sTotalSize;
char acData[2000+1];
long lCurrRead;
};
MapData.cpp
MapData::MapData()
{
}
MapData::~MapData()
{
printf("Inside MADATA Destructor \n ");
}
MapData::MapData(char acInput[])
{
strcpy(ptrFileNm,acInput);
sTotalSize=0;
lCurrRead=0;
bSuccess=false;
}
bool MapData::OPEN()
{
// if failed return false flg
if ((fd = open(ptrFileNm, O_RDONLY)) == -1) {
return bSuccess;
}
if (stat(ptrFileNm, &sbuf) == -1) {
return bSuccess;
}
// copy in local variable
sTotalSize = sbuf.st_size;
ptrRecord = (char * )mmap( (caddr_t)0, sTotalSize, PROT_READ, MAP_SHARED, fd, 0) ;
if (ptrRecord == (char *)(caddr_t)(-1) ) {
perror("Fail to Map Data ");
return bSuccess;
}
else
{
printf("Successfully Map Data***[%ld] \n",sTotalSize);
bSuccess=true;
}
return bSuccess;
}
char * MapData::fnGetFileRef()
{
return ptrRecord;
}
char * MapData::ReadNextData(int iX)
{
if((lCurrRead+iX)<sTotalSize)
{
memset(acData,0x00,sizeof(acData));
strncpy(acData,ptrRecord+lCurrRead,iX);
acData[iX+1]='\0';
lCurrRead+=iX;
}else{
strcpy(acData,"ZZZ");
}
return acData;
}
long MapData::fnGetSize()
{
return sTotalSize;
}
void MapData::fnClose()
{
// Don't forget to free the mmapped memory
if(munmap(ptrRecord, sTotalSize) == -1)
{
close(fd);
perror("Error un-mmapping the file");
exit(EXIT_FAILURE);
}
// Un-mmaping doesn't close the file, so we still need to do that.
close(fd);
printf("CLOSED SUCCESSFULLY \n ");
}
Main.cpp
int main()
{
char acFileNm[500+1];
MEMSET(acFileNm); // clean the variable
// file name to be read
strcpy(acFileNm,"ABDFILE.txt");
long lProcCnt=0; // no of byte read by program
char acLine[MAX_LINE_LENGTH+1]; // hold current read line
bool bFlag=true; // main flag
DEBUG_PRINT("File to be processed:%s \n",acFileNm);
// create object of mmap
MapData * pt1 = NULL;
pt1 = new MapData(acFileNm);
if(!pt1)
{
cout<<"Error creating object so quit ..."<<endl;
return 0 ;
}
auto_ptr<MapData> ptrMap( pt1 ); // pass ownership to auto deletor to delete memory
DEBUG_PRINT("STEP1:%s \n","OBJECT CREATION FOR FILE MAPPED IN MEMORY");
// try to open the file
if(ptrMap->OPEN())
{
// on success..get pointer to first char of file
char * ptrData = ptrMap->fnGetFileRef();
long lCompSize=ptrMap->fnGetSize(); // total no of bytes = fiexed line size * no of row + (no of row * EOL)
short int iEOL=0;
// logic to identify file generated on ewhich OS
if( (*(ptrData+MAX_LINE_LENGTH) == '\r') && (*(ptrData+MAX_LINE_LENGTH+1) == '\n'))
{
// DOS format CRLF
iEOL = 2;
}else if(*(ptrData+MAX_LINE_LENGTH) == '\n'){
// Unix format LF
iEOL = 1;
}
DEBUG_PRINT("STEP2: SIZEOFFILE%ld FILESYSTEM FORMAT:%d \n",lCompSize,iEOL);
// here read till it reaches maximum limit of file
while(lProcCnt<lCompSize)
{
//DEBUG_PRINT("PROC COUNTER[%ld] MAX_COUNTER[%ld] \n",lProcCnt,lCompSize);
lProcCnt+=MAX_LINE_LENGTH+iEOL; // increement no of bytes read at initial
MEMSET(acLine);
strncpy(acLine,ptrData+lProcCnt,MAX_LINE_LENGTH); // read line
acLine[MAX_LINE_LENGTH+1]='\0';
// process the line :function is called here to process the line
}
}else{
DEBUG_PRINT("MAP DATA FAILED OF FILE[%s] \n",acFileNm);
bFlag=false;
}
// at the end check if all the controls are matched
if(bFlag)
DEBUG_PRINT("END OF FILE PROCESSING SUCCESS \n");
else
DEBUG_PRINT("END OF FILE PROCESSING FAILED \n");
// close the memory map
ptrMap->fnClose();
MapData * ptr5 = ptrMap.release(); // release the ownership
delete ptr5; **// segmentation fault comes here ...**
}
Please suggest me where i am going wrong since gdb is also not helping ...detailed explanation will be good for me to understand ...
Stacktrace generated by gdb:
*** glibc detected *** DemoMap: free(): invalid pointer: 0x0804c000 ***
======= Backtrace: =========
/lib/libc.so.6[0x9bbc81]
/lib/libc.so.6[0x9be562]
/usr/lib/libstdc++.so.6(_ZdlPv+0x22)[0x544552]
DemoMap[0x80491e6]
/lib/libc.so.6(__libc_start_main+0xe6)[0x961d36]
DemoMap[0x8048d91]
======= Memory map: ========
00110000-00111000 r-xp 00000000 00:00 0 [vdso]
0044c000-00469000 r-xp 00000000 08:03 1237 /lib/libgcc_s-4.4.7-20120601.so.1
00469000-0046a000 rw-p 0001d000 08:03 1237 /lib/libgcc_s-4.4.7-20120601.so.1
00495000-00576000 r-xp 00000000 08:02 132841 /usr/lib/libstdc++.so.6.0.13
00576000-0057a000 r--p 000e0000 08:02 132841 /usr/lib/libstdc++.so.6.0.13
0057a000-0057c000 rw-p 000e4000 08:02 132841 /usr/lib/libstdc++.so.6.0.13
0057c000-00582000 rw-p 00000000 00:00 0
00929000-00947000 r-xp 00000000 08:03 1065 /lib/ld-2.12.so
00947000-00948000 r--p 0001d000 08:03 1065 /lib/ld-2.12.so
00948000-00949000 rw-p 0001e000 08:03 1065 /lib/ld-2.12.so
0094b000-00adb000 r-xp 00000000 08:03 1067 /lib/libc-2.12.so
00adb000-00adc000 ---p 00190000 08:03 1067 /lib/libc-2.12.so
00adc000-00ade000 r--p 00190000 08:03 1067 /lib/libc-2.12.so
00ade000-00adf000 rw-p 00192000 08:03 1067 /lib/libc-2.12.so
00adf000-00ae2000 rw-p 00000000 00:00 0
00b29000-00b51000 r-xp 00000000 08:03 1211 /lib/libm-2.12.so
00b51000-00b52000 r--p 00027000 08:03 1211 /lib/libm-2.12.so
00b52000-00b53000 rw-p 00028000 08:03 1211 /lib/libm-2.12.so
08048000-0804b000 r-xp 00000000 08:08 2883976 DemoMap
0804b000-0804c000 rw-p 00002000 08:08 2883976 DemoMap
0804c000-0806d000 rw-p 00000000 00:00 0 [heap]
b7e00000-b7e21000 rw-p 00000000 00:00 0
b7e21000-b7f00000 ---p 00000000 00:00 0
b7f9b000-b7fe5000 r--s 00000000 08:08 4326707 ABCDEF.TXT
b7fe5000-b7fe8000 rw-p 00000000 00:00 0
b7ffd000-b8000000 rw-p 00000000 00:00 0
bffeb000-c0000000 rw-p 00000000 00:00 0 [stack]
may be here.
char ptrFileNm[250+1];
char acFileNm[500+1];
MapData::MapData(char acInput[])
{
strcpy(ptrFileNm,acInput);//segmentation fault
sTotalSize=0;
lCurrRead=0;
bSuccess=false;
}

Glibc Error: double free or corruption

I have been looking around at the meaning of this error and it seems to mean that I am freeing the same object more than once. I can't seem to figure out how to prevent this. Any help or suggestions would be much appreciated.
File(randname)
File(a.out)
~File(a.out)
~Directory(randname)
~File(null)
~File()
*** glibc detected *** a.out: double free or corruption (fasttop): 0x0804b048 ***
======= Backtrace: =========
/lib/libc.so.6(+0x6ff0b)[0xb74baf0b]
/usr/local/gcc/gcc-cilk/lib/libstdc++.so.6(_ZdlPv+0x1f)[0xb7671b4f]
/usr/local/gcc/gcc-cilk/lib/libstdc++.so.6(_ZdaPv+0x1b)[0xb7671b9b]
a.out[0x8048983]
a.out[0x8048b12]
a.out[0x80487d7]
/lib/libc.so.6(__libc_start_main+0xf3)[0xb7464003]
a.out[0x8048701]
======= Memory map: ========
08048000-08049000 r-xp 00000000 00:25 268562602 /home/user/test/a.out
08049000-0804a000 r--p 00000000 00:25 268562602 /home/user/test/a.out
0804a000-0804b000 rw-p 00001000 00:25 268562602 /home/user/test/a.out
0804b000-0806c000 rw-p 00000000 00:00 0 [heap]
b7448000-b744b000 rw-p 00000000 00:00 0
b744b000-b75b2000 r-xp 00000000 08:01 1365267 /lib/libc-2.14.1.so
b75b2000-b75b4000 r--p 00167000 08:01 1365267 /lib/libc-2.14.1.so
b75b4000-b75b5000 rw-p 00169000 08:01 1365267 /lib/libc-2.14.1.so
b75b5000-b75b8000 rw-p 00000000 00:00 0
b75b8000-b75d3000 r-xp 00000000 08:01 1179017 /usr/local/gcc/gcc-cilk/lib/libgcc_s.so.1
b75d3000-b75d4000 r--p 0001a000 08:01 1179017 /usr/local/gcc/gcc-cilk/lib/libgcc_s.so.1
b75d4000-b75d5000 rw-p 0001b000 08:01 1179017 /usr/local/gcc/gcc-cilk/lib/libgcc_s.so.1
b75d5000-b75fe000 r-xp 00000000 08:01 1365275 /lib/libm-2.14.1.so
b75fe000-b75ff000 r--p 00028000 08:01 1365275 /lib/libm-2.14.1.so
b75ff000-b7600000 rw-p 00029000 08:01 1365275 /lib/libm-2.14.1.so
b7622000-b7624000 rw-p 00000000 00:00 0
b7624000-b770b000 r-xp 00000000 08:01 1179021 /usr/local/gcc/gcc-cilk/lib/libstdc++.so.6.0.19
b770b000-b770f000 r--p 000e7000 08:01 1179021 /usr/local/gcc/gcc-cilk/lib/libstdc++.so.6.0.19
b770f000-b7710000 rw-p 000eb000 08:01 1179021 /usr/local/gcc/gcc-cilk/lib/libstdc++.so.6.0.19
b7710000-b7718000 rw-p 00000000 00:00 0
b7718000-b7737000 r-xp 00000000 08:01 1365260 /lib/ld-2.14.1.so
b7737000-b7738000 r--p 0001f000 08:01 1365260 /lib/ld-2.14.1.so
b7738000-b7739000 rw-p 00020000 08:01 1365260 /lib/ld-2.14.1.so
bfa18000-bfa39000 rw-p 00000000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
Aborted
And here is the code:
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
class File
{
protected:
unsigned char recordLen;
unsigned location;
unsigned fileSize;
unsigned char filenameLen;
char* filename;
public:
File(){filename = NULL;}
File(FILE* readFromHere, const char* name)
{
recordLen = 152;
location = 20003;
fileSize = 16348;
filenameLen = strlen(name);
filename = new char[filenameLen + 1];
strcpy(filename, name);
cout << "File(" << filename << ")\n";
}
File(const File& o)
{
if (o.filename == NULL)
filename = o.filename;
else
{
filename = new char[o.filenameLen + 1];
strcpy(filename, o.filename);
}
}
~File()
{
if (filename)
cout << "~File(" << filename << ")\n";
else
cout << "~File(null)\n";
if (filename != NULL)
delete[] filename;
}
};
class Directory : public File
{
protected:
int numContents;
File* contents;
public:
Directory(FILE* readFromHere, const char* name)
: File(readFromHere, name)
{
numContents = 2;
contents = new File[numContents];
contents[0] = File(readFromHere, "a.out");
//~ contents[1] = File(readFromHere, "otherfile.cpp");
}
~Directory()
{
if (filename)
cout << "~Directory(" << filename << ")\n";
else
cout << "~Directory(null)\n";
if (contents != NULL)
delete[] contents;
}
};
int main()
{
Directory d(NULL, "randname");
sleep(2);
return 0;
}
Your class doesn't follow the Rule of Three even though it owns resources. You have a copy constructor and a destructor, but not a copy assignment operator. Which means that this line:
contents[0] = File(readFromHere, "a.out");
invokes the default copy assignment operator, which happily copies pointers. There's your double-deletion problem.

Mixed-language program crash occurs when free() called

I have a program where code in C, C++ and Fortran has been compiled and linked together. The main function is written in C++ and is found in file testQ.cpp. The C++ code calls a Fortran subroutine in file getqpf.F. The subroutine in getqpf.F calls C functions in a number of other files.
Using gcc and gfortran on GNU/Linux I have successfully linked together the program:
g++ -c test-Q.cpp -I./boost/boost_1_52_0/ -g
gcc -c paul2.c -g
gcc -c paul2_L1.c -g
gcc -c paul6.c -g
gcc -c paul6_L1.c -g
gcc -c fit_slope.c -g
gfortran -c getqpf.F -g
g++ -o test-Q test-Q.o paul2.o paul2_L1.o paul6.o paul6_L1.o fit_slope.o getqpf.o -g -lgfortran
The program appears to run normally. However, it crashes before terminating when free() is called:
free(x1);
This is the last statement in the program, and the program will only crash when free() is called. Now x1 is created using the following malloc:
double *x1;
x1 = (double*)malloc(iXget);
The x1 pointer is passed in to the Fortran code, and the Fortran subroutine passes it into a C code function.
Here is the output of the crash. What could be going wrong here, and how might I debug this? I've recently installed valgrind. How can I use this to debug my program?
*** glibc detected *** ./test-Q: free(): invalid next size (normal): 0x0000000000f50aa0 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7ae16)[0x7feabf64de16]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x6c)[0x7feabf6520fc]
./test-Q[0x402520]
./test-Q[0x4026b2]
./test-Q[0x401dbd]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7feabf5f430d]
./test-Q[0x401cf9]
======= Memory map: ========
00400000-0040b000 r-xp 00000000 08:11 9714095 /media/RESEARCH/SAS2-version2/test-Q/test-Q
0060a000-0060b000 r--p 0000a000 08:11 9714095 /media/RESEARCH/SAS2-version2/test-Q/test-Q
0060b000-0060c000 rw-p 0000b000 08:11 9714095 /media/RESEARCH/SAS2-version2/test-Q/test-Q
00f39000-00f5a000 rw-p 00000000 00:00 0 [heap]
7feab8000000-7feab8021000 rw-p 00000000 00:00 0
7feab8021000-7feabc000000 ---p 00000000 00:00 0
7feabf39d000-7feabf3d2000 r-xp 00000000 08:01 18881806 /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0
7feabf3d2000-7feabf5d1000 ---p 00035000 08:01 18881806 /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0
7feabf5d1000-7feabf5d2000 r--p 00034000 08:01 18881806 /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0
7feabf5d2000-7feabf5d3000 rw-p 00035000 08:01 18881806 /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0
7feabf5d3000-7feabf76c000 r-xp 00000000 08:01 16515356 /lib/x86_64-linux-gnu/libc-2.13.so
7feabf76c000-7feabf96b000 ---p 00199000 08:01 16515356 /lib/x86_64-linux-gnu/libc-2.13.so
7feabf96b000-7feabf96f000 r--p 00198000 08:01 16515356 /lib/x86_64-linux-gnu/libc-2.13.so
7feabf96f000-7feabf970000 rw-p 0019c000 08:01 16515356 /lib/x86_64-linux-gnu/libc-2.13.so
7feabf970000-7feabf976000 rw-p 00000000 00:00 0
7feabf976000-7feabf98b000 r-xp 00000000 08:01 16518820 /lib/x86_64-linux-gnu/libgcc_s.so.1
7feabf98b000-7feabfb8a000 ---p 00015000 08:01 16518820 /lib/x86_64-linux-gnu/libgcc_s.so.1
7feabfb8a000-7feabfb8b000 r--p 00014000 08:01 16518820 /lib/x86_64-linux-gnu/libgcc_s.so.1
7feabfb8b000-7feabfb8c000 rw-p 00015000 08:01 16518820 /lib/x86_64-linux-gnu/libgcc_s.so.1
7feabfb8c000-7feabfc0f000 r-xp 00000000 08:01 16515346 /lib/x86_64-linux-gnu/libm-2.13.so
7feabfc0f000-7feabfe0e000 ---p 00083000 08:01 16515346 /lib/x86_64-linux-gnu/libm-2.13.so
7feabfe0e000-7feabfe0f000 r--p 00082000 08:01 16515346 /lib/x86_64-linux-gnu/libm-2.13.so
7feabfe0f000-7feabfe10000 rw-p 00083000 08:01 16515346 /lib/x86_64-linux-gnu/libm-2.13.so
7feabfe10000-7feabfef8000 r-xp 00000000 08:01 18881835 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16
7feabfef8000-7feac00f8000 ---p 000e8000 08:01 18881835 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16
7feac00f8000-7feac0100000 r--p 000e8000 08:01 18881835 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16
7feac0100000-7feac0102000 rw-p 000f0000 08:01 18881835 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16
7feac0102000-7feac0117000 rw-p 00000000 00:00 0
7feac0117000-7feac022b000 r-xp 00000000 08:01 18883022 /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0
7feac022b000-7feac042a000 ---p 00114000 08:01 18883022 /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0
7feac042a000-7feac042b000 r--p 00113000 08:01 18883022 /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0
7feac042b000-7feac042d000 rw-p 00114000 08:01 18883022 /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0
7feac042d000-7feac044e000 r-xp 00000000 08:01 16515354 /lib/x86_64-linux-gnu/ld-2.13.so
7feac0630000-7feac0636000 rw-p 00000000 00:00 0
7feac064a000-7feac064d000 rw-p 00000000 00:00 0
7feac064d000-7feac064e000 r--p 00020000 08:01 16515354 /lib/x86_64-linux-gnu/ld-2.13.so
7feac064e000-7feac0650000 rw-p 00021000 08:01 16515354 /lib/x86_64-linux-gnu/ld-2.13.so
7fff2940a000-7fff2942b000 rw-p 00000000 00:00 0 [stack]
7fff2952c000-7fff2952d000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted
UPDATE
After running valgrind --tool=memcheck --leak-check=full --log-file=memcheck.log ./test-Q, I get a rather curious-looking log file. Perhaps something isn't set up properly? Here it is:
==15621== Memcheck, a memory error detector
==15621== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==15621== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==15621== Command: ./test-Q
==15621== Parent PID: 14623
==15621==
==15621== Invalid write of size 4
==15621== at 0x401EE2: call_function(std::vector<double, std::allocator<double> >) (test-Q.cpp:183)
==15621== by 0x4026B1: run_experiment() (test-Q.cpp:346)
==15621== by 0x401DBC: main (test-Q.cpp:120)
==15621== Address 0x5ecba78 is 1,000 bytes inside a block of size 1,001 alloc'd
==15621== at 0x4C2A66F: malloc (vg_replace_malloc.c:270)
==15621== by 0x401E9A: call_function(std::vector<double, std::allocator<double> >) (test-Q.cpp:179)
==15621== by 0x4026B1: run_experiment() (test-Q.cpp:346)
==15621== by 0x401DBC: main (test-Q.cpp:120)
==15621==
--15621-- VALGRIND INTERNAL ERROR: Valgrind received a signal 11 (SIGSEGV) - exiting
--15621-- si_code=80; Faulting address: 0x0; sp: 0x4030e0df0
valgrind: the 'impossible' happened:
Killed by fatal signal
==15621== at 0x380624A6: vgPlain_arena_malloc (m_mallocfree.c:291)
==15621== by 0x380294E4: vgMemCheck_new_block (mc_malloc_wrappers.c:263)
==15621== by 0x3802967A: vgMemCheck_malloc (mc_malloc_wrappers.c:301)
==15621== by 0x3809D05D: vgPlain_scheduler (scheduler.c:1665)
==15621== by 0x380AC715: run_a_thread_NORETURN (syswrap-linux.c:103)
sched status:
running_tid=1
Thread 1: status = VgTs_Runnable
==15621== at 0x4C2A66F: malloc (vg_replace_malloc.c:270)
==15621== by 0x401FB9: call_function(std::vector<double, std::allocator<double> >) (test-Q.cpp:217)
==15621== by 0x4026B1: run_experiment() (test-Q.cpp:346)
==15621== by 0x401DBC: main (test-Q.cpp:120)
Note: see also the FAQ in the source distribution.
It contains workarounds to several common problems.
In particular, if Valgrind aborted or crashed after
identifying problems in your program, there's a good chance
that fixing those problems will prevent Valgrind aborting or
crashing, especially if it happened in m_mallocfree.c.
If that doesn't help, please report this bug to: www.valgrind.org
In the bug report, send all the above text, the valgrind
version, and what OS and version you are using. Thanks.
UPDATE
Here is the function in question with the array.
// main function
int main()
{
run_experiment();
}
void run_experiment()
{
const int MAX_VAL = 1001;
std::string line;
std::ifstream myfile ("s1.txt");
std::vector<double>data(MAX_VAL);
int cnt = 0;
double val;
if (myfile.is_open())
{
while ( myfile.good() && cnt < MAX_VAL)
{
std::getline (myfile,line);
val = boost::lexical_cast<double>(line);
data[cnt++] = val;
}
myfile.close();
// data vector seems to be OK here
// call the function to do the data processing
// this is the line 346 called into question by Valgrind
// run_experiment() (test-Q.cpp:346)
call_function(data);
}
else std::cout << "Unable to open file";
} // end
Here is the function declaration. The vector is being passed by value.
void call_function(std::vector<double> v);
UPDATE
As astutely suggested by mux in an answer below, it is indeed a problem with writing beyond the bounds of an array. Here is the version of the code that works, with the wrong code shown in the comments. I modified the vector to hold elements of type float, but the real issue was indeed writing beyond the bounds of an array.
The C-style array was created using malloc(), but the sizeof() function had to be used to create adequate space.
Changing this one line of code causes the error to go away.
// function to call code in the q analysis function
void call_function(std::vector<float> v)
{
// create all of the inputs
float *tri = NULL;
int nsamp;
int lwin;
int nfreqfit; // calculated below
float dt;
float null;
int L2;
float df; // calculated below
float *qq = NULL;
float *pf = NULL;
float *ampls;
double *work1;
double *work2;
double *work3;
double *work4;
int mem;
int morder;
int nfs; // calculated below
double *xReal = NULL;
double *xImag = NULL;
double *xAbs = NULL;
double *x1 = NULL;
int cen;
int top;
int bot;
float cut;
int nfst; // calculated below
int raw;
float fst; // low frequency to fit; replaces fpeak frequency
nsamp = v.size();
lwin = 101;
dt = 0.0042;
null = 100;
L2 = 1;
mem = 0; // keep this as is
morder = 5;
cen = 1;
top = 0;
bot = 0;
cut = 0.50;
raw = 1;
fst = 0.0; // lowest frequency to fit
// this is the line that was changed
tri = (float*)malloc(nsamp * sizeof(float));
// This is the line that needed changing
// tri = (float*)malloc(nsamp);
// copy the data into the vector
for (int i = 0; i < nsamp; i++)
tri[i] = v[i];
std::cout << "Done copying data to the vector" << std::endl;
// more code here...
} // end of function
void run_experiment()
{
const int MAX_VAL = 1001;
std::string line;
std::ifstream myfile ("s1.txt");
std::vector<float>data(MAX_VAL);
int cnt = 0;
float val;
if (myfile.is_open())
{
while ( myfile.good() && cnt < MAX_VAL)
{
std::getline (myfile,line);
val = boost::lexical_cast<double>(line);
data[cnt++] = val;
}
myfile.close();
/*
for (int i = 0; i < 1001; i++)
std::cout << data[i] << std::endl;
*/
// call the function to do the data processing
call_function(data);
}
else std::cout << "Unable to open file";
} // end
int main()
{
run_experiment();
}
It looks like you have a memory leak somewhere in your program, the output you provided isn't really helpful at all, you should run the program with valgrind to figure the problem. Try:
valgrind --tool=memcheck --leak-check=full --log-file=memcheck.log <binary>
If you fork any child processes you may want to add:
--trace-children=yes
Then post the memcheck.log and the relevant code if you still can't fix it.
Edit: it seems that you're writing beyond the bounds of some array here:
call_function(std::vector<double, std::allocator<double> >) (test-Q.cpp:183)
You should fix that first, it could be the problem.

Stack Smashing Using Message Queues

i have the following main code:
#include "ComHandler.h"
#include "socketMessage.h"
#define THIS_IP "localhost"
#define C_PORT 32456
#define S_PORT 25465
#define S_PORT_UDP 22548
int main(int argc, char* argv[]) {
conOptions opts;
strncpy(opts.password, "PASS", sizeof("PASS"));
opts.retryQty = 5;
opts.timeout = 300;
char dir[INET6_ADDRSTRLEN];
strncpy(dir, THIS_IP, sizeof(THIS_IP));
if (argv[1][0] == 'C') {
opts.connType = CLIENT_HANDLER;
opts.thisID = 2;
ComHandler comH(opts);
char buffer[10];
strncpy(buffer, "Testing", 10);
int rtnValue = comH.sendMsg(buffer, 10, 1, TCP_C);
std::cout << "Returned Value: " << rtnValue << std::endl;
} else {
opts.connType = SERVER_HANDLER;
opts.thisID = 1;
ComHandler comH(opts);
comH.addConnectionData(2, dir, C_PORT);
comH.addConnectionData(comH.getID(), dir, S_PORT);
char rcvdTxt[MINIDATA_DATA_SIZE];
comH.receiveMsg(rcvdTxt, MINIDATA_DATA_SIZE, 2, TCP_C);
std::cout << "Received: " << rcvdTxt << std::endl;
comH.closeCommunications();
}
}
The code is for testing my communication platform. The platform works well, but the problem appears when the messages are received by the Handler (ComHandler). When i call the method "receiveMsg" from ComHandler, i get a "stack smashing detected" in the "return" of the method.
This is the "ComHandler" class:
#ifndef COMHANDLER_H_
#define COMHANDLER_H_
#include "Constants.h"
#include "ComConstants.h"
#include "DataLogger.h"
#include <list>
#include <math.h>
#define CLIENT_HANDLER 1
#define SERVER_HANDLER 2
#define COMMENT_LINE '#'
#define TXT_SEPARATOR ';'
#define MINIDATA_DATA_SIZE (COMDATA_MAX_SIZE - 4* sizeof(int))
enum CON_TYPE {
TCP_C, UDP_C
};
#pragma pack(push)
#pragma pack(1)
typedef struct {
int totalPackets;
int sequenceNumber;
int sequenceID;
int dataSize;
char data[MINIDATA_DATA_SIZE];
} miniData;
#pragma pack(pop)
typedef struct connectionOptions {
unsigned int timeout;
unsigned int retryQty;
id_t thisID;
char password[PASSWORD_MAX_SIZE];
int connType;
connectionOptions() :
timeout(CON_TIMEOUT), retryQty(SOCKET_RETRIES), connType(
SERVER_HANDLER) {
memset(password, 0, PASSWORD_MAX_SIZE);
}
connectionOptions(connectionOptions& opt) {
timeout = opt.timeout;
retryQty = opt.retryQty;
thisID = opt.thisID;
connType = opt.connType;
memcpy(password, opt.password, PASSWORD_MAX_SIZE);
}
} conOptions;
class ComHandler {
private:
int dataForwarder_ReceiverMsgQueue;
int dataForwarder_SenderMsgQueue;
conOptions opts;
int sequenceID;
Semaphore ch_mux;
SharedMemory<comHandlerGlOp> ch_shm;
void cpyMiniData(miniData* to, miniData* from);
void createIPCs();
public:
ComHandler();
ComHandler(conOptions options);
ComHandler(id_t thisID);
virtual ~ComHandler();
int receiveMsg(char* buffer, int bufferSize, id_t originID,
CON_TYPE type = TCP_C);
int sendMsg(char* buffer, std::size_t bufferSize, id_t destinationID,
CON_TYPE type = TCP_C);
void configListenersData(char addr[INET6_ADDRSTRLEN], int port,
CON_TYPE type);
void addConnectionData(id_t id, char addr[INET6_ADDRSTRLEN], int port);
void addConnectionData(const char* file);
void modifyConnectionData(id_t id, char addr[INET6_ADDRSTRLEN], int port);
void removeConnectionData(id_t id);
int getID();
void closeCommunications();
};
#endif /* COMHANDLER_H_ */
The comData structure:
typedef struct {
long type;
int requestType;
char destination[INET6_ADDRSTRLEN];
char origin[INET6_ADDRSTRLEN];
id_t originID;
id_t destinationID;
int port;
pid_t senderPid;
pid_t originPid;
char data[COMDATA_MAX_SIZE];
} comData;
And the method with the problem:
int ComHandler::receiveMsg(char* buffer, int bufferSize, id_t originID,
CON_TYPE type) {
comData aux;
aux.type = DATA_RECEIVE;
int qtyReceived = 0;
if (originID != ANY_MSG_ORIGIN) {
if (type == TCP_C)
aux.requestType = RECEIVE_DATA_FROM_DESTINATION_TCP;
else
aux.requestType = RECEIVE_DATA_FROM_DESTINATION_UDP;
} else {
if (type == TCP_C)
aux.requestType = RECEIVE_ANY_DATA_TCP;
else
aux.requestType = RECEIVE_ANY_DATA_UDP;
}
aux.originID = originID;
aux.senderPid = getpid();
aux.originPid = getpid();
msgsnd(dataForwarder_ReceiverMsgQueue, &aux, sizeof(comData), 0);
msgrcv(dataForwarder_ReceiverMsgQueue, &aux, sizeof(comData), getpid(), 0);
/* More Code */
return qtyReceived;
}
The stack smashing error appears after "return qtyReceived;" is called. And the /* More Code */ in the middle is the non important code, because if a delete that part, the stack smashing stills appears.
After much debugging i found that the smashing appears if i call:
`msgrcv(dataForwarder_ReceiverMsgQueue, &aux, sizeof(comData), getpid(), 0);`
if i comment that line, i don't get the error.
Also with the debugger, i was able to see that the messages from the queue arrive with good format and size, exactly as they should.
The console output is:
*** stack smashing detected ***: /media/blackhole/workspace/Final/bin/ComTest terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb7df88d5]
/lib/i386-linux-gnu/libc.so.6(+0xe7887)[0xb7df8887]
/media/blackhole/workspace/Final/bin/ComTest[0x804dc6b]
/media/blackhole/workspace/Final/bin/ComTest[0x804a002]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb7d2a113]
/media/blackhole/workspace/Final/bin/ComTest[0x8049d11]
======= Memory map: ========
08048000-08054000 r-xp 00000000 08:05 256373 /media/blackhole/workspace/Final/bin/ComTest
08054000-08055000 r--p 0000b000 08:05 256373 /media/blackhole/workspace/Final/bin/ComTest
08055000-08056000 rw-p 0000c000 08:05 256373 /media/blackhole/workspace/Final/bin/ComTest
08056000-08077000 rw-p 00000000 00:00 0 [heap]
b7d0f000-b7d11000 rw-p 00000000 00:00 0
b7d11000-b7e87000 r-xp 00000000 08:06 525221 /lib/i386-linux-gnu/libc-2.13.so
b7e87000-b7e89000 r--p 00176000 08:06 525221 /lib/i386-linux-gnu/libc-2.13.so
b7e89000-b7e8a000 rw-p 00178000 08:06 525221 /lib/i386-linux-gnu/libc-2.13.so
b7e8a000-b7e8d000 rw-p 00000000 00:00 0
b7e8d000-b7ea9000 r-xp 00000000 08:06 525242 /lib/i386-linux-gnu/libgcc_s.so.1
b7ea9000-b7eaa000 r--p 0001b000 08:06 525242 /lib/i386-linux-gnu/libgcc_s.so.1
b7eaa000-b7eab000 rw-p 0001c000 08:06 525242 /lib/i386-linux-gnu/libgcc_s.so.1
b7eab000-b7eac000 rw-p 00000000 00:00 0
b7eac000-b7ed4000 r-xp 00000000 08:06 525251 /lib/i386-linux-gnu/libm-2.13.so
b7ed4000-b7ed5000 r--p 00028000 08:06 525251 /lib/i386-linux-gnu/libm-2.13.so
b7ed5000-b7ed6000 rw-p 00029000 08:06 525251 /lib/i386-linux-gnu/libm-2.13.so
b7ed6000-b7fb4000 r-xp 00000000 08:06 5514 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b7fb4000-b7fb5000 ---p 000de000 08:06 5514 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b7fb5000-b7fb9000 r--p 000de000 08:06 5514 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b7fb9000-b7fba000 rw-p 000e2000 08:06 5514 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b7fba000-b7fc1000 rw-p 00000000 00:00 0
b7fdc000-b7fdd000 rw-s 00000000 00:04 163119127 /SYSV02056f32 (deleted)
b7fdd000-b7fdf000 rw-p 00000000 00:00 0
b7fdf000-b7fe0000 r-xp 00000000 00:00 0 [vdso]
b7fe0000-b7ffe000 r-xp 00000000 08:06 525208 /lib/i386-linux-gnu/ld-2.13.so
b7ffe000-b7fff000 r--p 0001d000 08:06 525208 /lib/i386-linux-gnu/ld-2.13.so
b7fff000-b8000000 rw-p 0001e000 08:06 525208 /lib/i386-linux-gnu/ld-2.13.so
bffdf000-c0000000 rw-p 00000000 00:00 0 [stack]
So, any ideas? If you need something about the code, just ask me.
According to this, the msgsz parameter of msgrcv() should be the size of the mtext member of the mymsg struct:
struct mymsg {
long int mtype; /* message type */
char mtext[1]; /* message text */
}
The problem is that you include the size of the mtype member (4 bytes) so msgrcv() writes four bytes past the end of your struct which trashes the stack.