Can we implement c++ thunk in linux? - c++

I want to use class member functions as callbacks, I don't use libsigc, because it's slow.
In ATL, we can use member function for C-style callback(http://www.codeproject.com/KB/cpp/SoloGenericCallBack.aspx), so can we implement c++ thunk in linux?
The code below will crash:
#include <assert.h>
#include <stdio.h>
#include <sys/mman.h>
typedef char BYTE;
typedef int DWORD;
typedef int* DWORD_PTR;
typedef int* INT_PTR;
typedef bool BOOL;
typedef unsigned long ULONG;
typedef unsigned long* ULONG_PTR;
#define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) )
#define __stdcall __attribute__((__stdcall__))
//#pragma pack( push, 1 )
struct MemFunToStdCallThunk
{
BYTE m_mov;
DWORD m_this;
BYTE m_pushEax;
BYTE m_jmp;
DWORD m_relproc;
void Init( DWORD_PTR proc, void* pThis )
{
printf("proc=%x\n", proc);
m_mov = 0xB8; // mov eax
m_this = PtrToUlong(pThis);
m_pushEax = 0xc3;// push eax
m_jmp = 0xe9; //jmp
m_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(MemFunToStdCallThunk)));
printf("m_relproc = %x\n", m_relproc);
mprotect(this, sizeof(MemFunToStdCallThunk), PROT_READ|PROT_WRITE|PROT_EXEC);
}
void* GetCodeAddress()
{
return this;
}
}__attribute__ ((packed));
//#pragma pack( pop )
template< typename TDst, typename TSrc >
TDst UnionCastType( TSrc src )
{
union
{
struct
{
int* pfn; //function,index
long delta; // offset,
}funcPtr;
TSrc uSrc;
}uMedia;
uMedia.uSrc = src;
return uMedia.funcPtr.pfn;
}
typedef int ( __stdcall *StdCallFun)(int, int);
class CTestClass
{
public:
int m_nBase;
MemFunToStdCallThunk m_thunk;
int memFun( int m, int n )
{
int nSun = m_nBase + m + n;
printf("m=%d,n=%d,nSun=%d\n", m, n, nSun);
return 1234;
}
public:
CTestClass()
{
m_nBase = 10;
}
void Test()
{
printf("%x\n", &CTestClass::memFun);
m_thunk.Init(UnionCastType<DWORD_PTR>(&CTestClass::memFun), this );
StdCallFun fun = (StdCallFun)m_thunk.GetCodeAddress();
assert( fun != NULL );
int ret = fun( 9, 3 );
printf("ret = %x\n", ret);
}
};
int main()
{
CTestClass test;
test.Test();
return 0;
}
EDIT:
Thanks to user786653, I get the right answer:
#include <assert.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
typedef char BYTE;
typedef int DWORD;
typedef int* DWORD_PTR;
typedef int* INT_PTR;
typedef bool BOOL;
typedef unsigned long ULONG;
typedef unsigned long* ULONG_PTR;
#define PtrToUlong(p) ((ULONG)(ULONG_PTR) (p) )
#define __stdcall __attribute__((__stdcall__))
struct MemFunToStdCallThunk
{
BYTE m_repairStack[10];
DWORD m_mov;
DWORD m_this;
BYTE m_jmp;
DWORD m_relproc;
void Init( DWORD_PTR proc, void* pThis )
{
printf("proc=%p\n", proc);
m_repairStack[0] = 0x83; //sub esp, 0x4
m_repairStack[1] = 0xec;
m_repairStack[2] = 0x04;
m_repairStack[3] = 0x8b; //mov eax,[esp + 0x4]
m_repairStack[4] = 0x44;
m_repairStack[5] = 0x24;
m_repairStack[6] = 0x04;
m_repairStack[7] = 0x89;//mov [esp], eax
m_repairStack[8] = 0x04;
m_repairStack[9] = 0x24;
m_mov = 0x042444C7; // mov dword ptr [esp+0x4],
m_this = PtrToUlong(pThis);
m_jmp = 0xe9; //jmp
m_relproc = (DWORD)proc - ((DWORD)this+sizeof(MemFunToStdCallThunk));
printf("m_relproc = %d\n", m_relproc);
//long page_size = sysconf(_SC_PAGE_SIZE);
//mprotect((void*)(PtrToUlong(this) & -page_size), 2*page_size, PROT_READ|PROT_WRITE|PROT_EXEC);
}
void* GetCodeAddress()
{
return this;
}
}__attribute__ ((packed));
template< typename TDst, typename TSrc >
TDst UnionCastType( TSrc src )
{
union
{
struct
{
int* pfn; //function or index
long delta; // offset
}funcPtr;
TSrc uSrc;
}uMedia;
uMedia.uSrc = src;
return uMedia.funcPtr.pfn;
}
typedef int ( __stdcall *StdCallFun)(int, int);
class CTestClass
{
public:
int m_nBase;
MemFunToStdCallThunk m_thunk;
int memFun( int m, int n )
{
printf("this=%p\n", this);
int nSun = m_nBase + m + n;
printf("m=%d,n=%d,nSun=%d\n", m, n, nSun);
return nSun;
}
public:
CTestClass()
{
m_nBase = 10;
}
void Test()
{
int (CTestClass::*abc)(int, int);
printf("sizeof(MemFunToStdCallThunk)=%d,sizeof(abc)=%d\n", sizeof(MemFunToStdCallThunk), sizeof(abc));
printf("memFun=%p\n", &CTestClass::memFun);
m_thunk.Init(UnionCastType<DWORD_PTR>(&CTestClass::memFun), this );
StdCallFun fun = (StdCallFun)m_thunk.GetCodeAddress();
assert( fun != NULL );
int ret = memFun(2, 3);
printf("ret 1= %d\n", ret);
ret = fun( 9, 3 );
printf("ret 2= %d\n", ret);
}
};
int main()
{
CTestClass test;
test.Test();
return 0;
}

Yes, but I wouldn't recommend it. It will (obviously) make your code a lot less portable and you're potentially opening a security hole if you're not careful.
You will need to make the code executable with mprotect(2). Something like mprotect(&thunk_struct, sizeof(struct _CallBackProcThunk), PROT_READ|PROT_WRITE|PROT_EXEC).
Also the normal GCC syntax for structure packing is struct S { /* ... */ } __attribute__ ((packed)) though newer versions might support the #pragma pack syntax.
You will probably also want to substitute DWORD with uint32_t from stdint.h and BYTE with uint8_t (or just stick a typedef in there).
EDIT:
From the man page on mprotect "[..]addr must be aligned to a page boundary". You should check the return value. Try doing something like this instead:
long page_size = sysconf(_SC_PAGE_SIZE);
uintptr_t addr = ((uintptr_t)this) & -page_size;
if (mprotect((void*)addr, 2*page_size, PROT_READ|PROT_WRITE|PROT_EXEC)) {
perror("mprotect");
/* handle error */
}
The following calculation is wrong:
DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(MemFunToStdCallThunk)))
It's doing its calculations on int*'s.
(DWORD)proc - ((DWORD)this+sizeof(MemFunToStdCallThunk)
should be sufficient here.
A very ugly (non-portable etc. etc.), but small and self-contained example follows:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>
struct thunk {
uint32_t mov;
uint32_t this_ptr;
uint8_t jmp;
uint32_t rel;
} __attribute__((packed));
class Test {
public:
virtual int foo(void) {
printf("foo! %p\n", (void*)this);
return 42;
}
};
int main()
{
Test test;
printf("%d\n", test.foo());
thunk t;
t.mov = 0x042444C7;
t.this_ptr = (uint32_t)&test;
t.jmp = 0xe9;
t.rel = ((uint32_t)(void*)&Test::foo) - ((uint32_t)&t + sizeof(thunk));
uint32_t addr = (uint32_t)&t;
long page_size = sysconf(_SC_PAGE_SIZE);
if (mprotect((void*)(addr & -page_size), 2*page_size, PROT_READ|PROT_WRITE|PROT_EXEC)) {
perror("mprotect");
return 1;
}
union {
void* p;
int (*foo)(int);
} u;
u.p = &t;
printf("%d\n", u.foo(0));
return 0;
}

A reasonable approach is something like this:
struct Foo {
void doit();
};
extern "C" {
void callback(void *handle) {
reinterpret_cast<Foo*>(handle)->doit();
}
}
The assembly of callback looks like this here (x64):
callback:
jmpq _ZN3Foo4doitEv

You can't pass pointer-to-member pointers to C callbacks directly, but there are portable tricks (i.e. not restricted to one target OS) that work very well.
The easiest way to do that is just to use a wrapper non-member function whose only purpose is to call your member function.
void wrapper()
{
object->callWhatever();
}
You can pass wrapper() as a function pointer.
See also for example Cast member function for create_pthread() call for how to handle cases where you get a void* parameter with the callback and want to use that to store (directly or not) a reference/pointer to the object you want to operate on.

I want to use class member functions as callbacks, I don't use libsigc, because it's slow. In ATL, we can use member function for C-style callback(http://www.codeproject.com/KB/cpp/SoloGenericCallBack.aspx), so can we implement c++ thunk in linux?
You probably can. However, there is no need to.
Most asynchronous APIs allow to pass a void* argument when registering for an asynchronous event. When the event gets reported this void* is reported as well and can be used to call a member function of an object. (Vague language because APIs like epoll_wait() don't actually call you back, where as pthread_create() does.).

Related

Reinterpret_cast sent data

The code below is just an example.
Function1 is a dllexport, how do I properly convert/read the value of data inside of Foo2?
When I print the value, it returns 000001DFA1C501F3.
Function1(PVOID InPassThruBuffer, ULONG InPassThruSize);
void Foo(std::wstring* data) {
Function1(&data, sizeof(wchar_t))
}
// ==============================================
typedef struct _REMOTE_ENTRY_INFO_
{
UCHAR* UserData;
ULONG UserDataSize;
}REMOTE_ENTRY_INFO;
void __stdcall Foo2(REMOTE_ENTRY_INFO* inRemoteInfo)
{
std::wstring wdata;
if (inRemoteInfo->UserDataSize == sizeof(wchar_t))
wdata = reinterpret_cast<wchar_t *>(inRemoteInfo->UserData);
}
Try something more like this instead:
void Foo(std::wstring* data)
{
Function1(const_cast<wchar_t*>(data->c_str()), data->size() * sizeof(wchar_t));
// or, in C++17 and later:
// Function1(data->data(), data->size() * sizeof(wchar_t));
}
void __stdcall Foo2(REMOTE_ENTRY_INFO* inRemoteInfo)
{
wchar_t *wdata = reinterpret_cast<wchar_t*>(inRemoteInfo->UserData);
int wdatalen = inRemoteInfo->UserDataSize / sizeof(wchar_t);
}
Or, if Foo2() in called in the context of Function1() before Foo() exits, then you can just pass the std::wstring* pointer itself instead:
void Foo(std::wstring* data)
{
Function1(&data, sizeof(data));
// or, if Function1() does not *copy* the data,
// merely passes around the provided pointer as-is:
//
// Function1(data, sizeof(*data));
}
void __stdcall Foo2(REMOTE_ENTRY_INFO* inRemoteInfo)
{
std::wstring *wdata = *reinterpret_cast<std::wstring**>(inRemoteInfo->UserData);
// or:
// std::wstring *wdata = reinterpret_cast<std::wstring*>(inRemoteInfo->UserData);
}

self-modifying under windows issue overwrite

I am writting a self-mutation code , and its original value before overwrite is 1,but after the overwrite should be 42. I think I am missing some aspecs because I got 1 on both original and mutation overwrite. my complete code looks like this gist link , but the original source was written under *unix https://shanetully.com/2013/12/writing-a-self-mutating-x86_64-c-program/
#include <windows.h>
#include <iostream>
using namespace std;
int getpagesize();
void foo(void);
int change_page_permissions_of_address(void *addr);
int getpagesize() {
SYSTEM_INFO si;
GetSystemInfo(&si);
return unsigned(si.dwPageSize);
}
void foo(void) {
int i = 0;
i++;
printf("i: %d\n", i);
}
int change_page_permissions_of_address(void *addr) {
// Get total function size
int page_size = getpagesize();
DWORD dwOldProtect;
// Obtain the addresses for the functions so we can calculate size.
uintptr_t tmp = (uintptr_t)addr-(uintptr_t)addr%page_size;
addr = (void*)tmp;
// We need to give ourselves access to modifify data at the given address
if (VirtualProtect(addr, page_size, PAGE_EXECUTE_READWRITE, &dwOldProtect) == -1) {
return -1;
}
return 0;
}
int main() {
void *foo_addr = (void*)foo;
if (change_page_permissions_of_address(foo_addr) == -1) {
printf("Error while changing page permissions of foo(): %s\n");
return 1;
}
// Call the unmodified foo()
puts("Calling foo...");
foo();
// Change the immediate value in the addl instruction in foo() to 42
unsigned char *instruction = (unsigned char*)foo_addr + 18;
*instruction = 0x2A;
puts("Calling foo..., but I am the self-modifying");
foo();
cin.get();
return 0;
}
Check of VirtualProtect is incorrect as it returns FALSE, not -1 in case of an error. Also I suspect that you will need to obtain a pointer to a starting page of the region of pages that foo belongs to and it is not clear where did you get offset 18 from.

Fail to Read Through Shared Memory

I am trying to publish some random things over shared memory; and for some weird reason, the reader doesn't pick up what the sender has written
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <cstdio>
class SHM {
volatile char* _ptr;
public:
SHM() {
const auto handle = shm_open("myTest", O_RDWR|O_CREAT, 0666);
const auto size = 4 * 1024 * 1024;
if (-1 == ftruncate(handle, size)) {
throw;
}
_ptr = (volatile char*)mmap(0,size , PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0);
if(_ptr == MAP_FAILED){
throw;
}
int rc = fchmod(handle, 0666);
if (rc == -1) {
throw;
}
}
bool read(uint64_t& magic, uint64_t& time) {
const uint64_t newVal = *(uint64_t*)_ptr;
if (newVal != magic) {
magic = newVal;
printf("value changed!!!\n");
time = *(uint64_t*)(_ptr + sizeof(magic));
return true;
}
//printf("old value: %lu\n", newVal);
return false;
}
void publish(const uint64_t time) {
__sync_fetch_and_add((uint64_t*)_ptr, time);
__sync_synchronize();
*(uint64_t*)(_ptr + sizeof(uint64_t)) = time;
}
};
Here is the sender:
#include <ctime>
#include <unistd.h>
#include <cstdlib>
#include <cstdint>
#include "shm.h"
int main() {
SHM shm;
timespec t;
for (auto i = 0; i < 10000; i++) {
if (0 == clock_gettime(CLOCK_REALTIME, &t)) {
const uint64_t v = t.tv_sec * 1000 * 1000 * 1000 + t.tv_nsec;
shm.publish(v);
printf("published %lu\n", v);
usleep(100);
}
}
}
Here is the reader:
#include <iostream>
#include "shm.h"
int main() {
SHM shm;
uint64_t magic = 0;
uint64_t t = 0;
while (true) {
if (shm.read(magic, t)) {
printf("%lu, %lu\n", magic, t);
}
}
}
If I restart the reader, the reader is indeed able to read the last value that the sender has written.
However, if I start the reader first, and then the sender, all the values the sender writes aren't picked up by the reader.
To make this even weirder, if I uncomment the printf statement in SHM::read(), then the reader is able to pick up sometimes.
Any idea?
GCC version:
g++ (GCC) 7.2.1 20170829 (Red Hat 7.2.1-1)
I spotted a couple of issues, however, I am unsure if they would fix your problem.
name for shm_open should start with / for portable use.
In read and publish the casts must not discard volatile. E.g.: const uint64_t newVal = *(uint64_t volatile*)_ptr;. Even better, drop volatile and use std::atomic.
Although there are different processes involved, this is still the case of same objects being accessed by more than one thread of execution and at least one of these threads modifies the shared objects.
I made the above changes. Using std::atomic fixed it:
class SHM {
void* _ptr;
public:
SHM() {
const auto handle = shm_open("/myTest", O_RDWR|O_CREAT, 0666);
const auto size = 4 * 1024 * 1024;
if (-1 == ftruncate(handle, size))
throw;
_ptr = mmap(0,size , PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0);
if(_ptr == MAP_FAILED)
throw;
}
bool read(uint64_t& magic, uint64_t& time) {
auto p = static_cast<std::atomic<uint64_t>*>(_ptr);
const uint64_t newVal = p[0];
if (newVal != magic) {
magic = newVal;
printf("value changed!!!\n");
time = p[1];
return true;
}
return false;
}
void publish(const uint64_t time) {
auto p = static_cast<std::atomic<uint64_t>*>(_ptr);
p[0] += time;
p[1] = time;
}
};
void sender() {
SHM shm;
timespec t;
for (auto i = 0; i < 10000; i++) {
if (0 == clock_gettime(CLOCK_REALTIME, &t)) {
const uint64_t v = t.tv_sec * 1000 * 1000 * 1000 + t.tv_nsec;
shm.publish(v);
printf("published %lu\n", v);
usleep(100);
}
}
}
void reader() {
SHM shm;
uint64_t magic = 0;
uint64_t t = 0;
while (true) {
if (shm.read(magic, t)) {
printf("%lu, %lu\n", magic, t);
}
}
}
int main(int ac, char**) {
if(ac > 1)
reader();
else
sender();
}
With std::atomic you can have more control. E.g.:
struct Data {
std::atomic<uint64_t> time;
std::atomic<uint64_t> generation;
};
// ...
bool read(uint64_t& generation, uint64_t& time) {
auto data = static_cast<Data*>(_ptr);
auto new_generation = data->generation.load(std::memory_order_acquire); // 1. Syncronizes with (2).
if(generation == new_generation)
return false;
generation = new_generation;
time = data->time.load(std::memory_order_relaxed);
printf("value changed!!!\n");
return true;
}
void publish(const uint64_t time) {
auto data = static_cast<Data*>(_ptr);
data->time.store(time, std::memory_order_relaxed);
data->generation.fetch_add(time, std::memory_order_release); // 2. (1) Synchronises with this store.
}

multiple LD_REPLOAD sharing variables

My purpose is quite simple: when I start the mongoose server, the server will initialize a variable which is defined by me. To do this, I hooked __libc_start_main. Then when the server receives a request, it will print out that initialized variable. To do this, I hooked recv. Below is my code.
#include <string>
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include "common-structure.h"
# define dprintf(fmt...)
data datainfo; //defined in common-structure.h
typedef int (*main_type)(int, char**, char**);
struct arg_type
{
char **argv;
int (*main_func) (int, char **, char **);
};
main_type saved_init_func = NULL;
void tern_init_func(int argc, char **argv, char **env){
dprintf("%04d: __tern_init_func() called.\n", (int) pthread_self());
if(saved_init_func)
saved_init_func(argc, argv, env);
datainfo.age = 10;
}
typedef void (*fini_type)(void*);
fini_type saved_fini_func = NULL;
extern "C" int my_main(int argc, char **pt, char **aa)
{
int ret;
arg_type *args = (arg_type*)pt;
dprintf("%04d: __libc_start_main() called.\n", (int) pthread_self());
ret = args->main_func(argc, args->argv, aa);
return ret;
}
extern "C" int __libc_start_main(
void *func_ptr,
int argc,
char* argv[],
void (*init_func)(void),
void (*fini_func)(void),
void (*rtld_fini_func)(void),
void *stack_end)
{
typedef void (*fnptr_type)(void);
typedef int (*orig_func_type)(void *, int, char *[], fnptr_type,
fnptr_type, fnptr_type, void*);
orig_func_type orig_func;
arg_type args;
void * handle;
int ret;
// Get lib path.
Dl_info dli;
dladdr((void *)dlsym, &dli);
std::string libPath = dli.dli_fname;
libPath = dli.dli_fname;
size_t lastSlash = libPath.find_last_of("/");
libPath = libPath.substr(0, lastSlash);
libPath += "/libc.so.6";
libPath = "/lib/x86_64-linux-gnu/libc.so.6";
if(!(handle=dlopen(libPath.c_str(), RTLD_LAZY))) {
puts("dlopen error");
abort();
}
orig_func = (orig_func_type) dlsym(handle, "__libc_start_main");
if(dlerror()) {
puts("dlerror");
abort();
}
dlclose(handle);
dprintf("%04d: __libc_start_main is hooked.\n", (int) pthread_self());
args.argv = argv;
args.main_func = (main_type)func_ptr;
saved_init_func = (main_type)init_func;
saved_fini_func = (fini_type)rtld_fini_func;
ret = orig_func((void*)my_main, argc, (char**)(&args),
(fnptr_type)tern_init_func, (fnptr_type)fini_func,
rtld_fini_func, stack_end);
return ret;
}
//hook recv
extern "C" ssize_t recv(int sockfd, void *buf, size_t len, int flags)
{
ssize_t (*orig_recv)(int sockfd, void *buf, size_t len, int flags);
orig_recv = dlsym(RTLD_NEXT, "recv");
orig_recv(sockfd, buf, len, flags);
printf("age is %d\n", datainfo.age);
}
However, when I makefile, I get the error: invalid conversion from ‘void*’ to ‘ssize_t (*)(int, void*, size_t, int) coming from dlsym(RTLD_NEXT, "recv");. My another question is can I achieve my goal in this way? If not, what is the correct way?
C++ is much more strongly typed than C, you need to explicitly cast void * to the correct type.
For example:
extern "C" ssize_t recv(int sockfd, void *buf, size_t len, int flags)
{
using orig_recv_t = ssize_t (*)(int, void *, size_t, int);
// Or for pre C++11 compilers: typedef ssize_t (*orig_recv_t)(int, void *, size_t, int);
orig_recv_t orig_recv;
orig_recv = reinterpret_cast<orig_recv_t>(dlsym(RTLD_NEXT, "recv"));
orig_recv(sockfd, buf, len, flags);
printf("age is %d\n", datainfo.age);
}

overloading new and delete in c++

HI All,
I was trying to overload new and delete to fix a memory leak problem in my project. But got stuck with some compilation error.
Currently this code is bit shabby
Here is my hdr file
#include <cstddef>
#include <iostream>
#include <list>
#include <stdarg.h>
#include <stdio.h>
using namespace std;
typedef unsigned int DWORD;
void AddTrack(DWORD addr, DWORD asize, const char *fname, DWORD lnum);
char *OutputDebugString (const char *fmt, ...);
void RemoveTrack(DWORD addr);
void DumpUnfreed();
#ifdef _DEBUG
#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW
void * operator new (unsigned int size, const char *file, int line)
{
void *ptr = (void *)malloc(size);
AddTrack((DWORD)ptr, size, file, line);
return(ptr);
}
/*inline void * operator new(unsigned int size)
{
void *ptr = (void *)malloc(size);
AddTrack((DWORD)ptr, size, _FILE_,_LINE_);
return(ptr);
}*/
void operator delete(void *p)
{
RemoveTrack((DWORD)p);
free(p);
}
#endif
char *OutputDebugString (const char *fmt, ...)
{
char *p = NULL;
size_t size = 1024;
int n = 0;
va_list ap;
if((p = (char*) malloc(size)) == NULL)
return NULL;
while(1) {
va_start(ap, fmt);
n = vsnprintf(p, size, fmt, ap);
va_end(ap);
if(n > -1 && n < size)
return p;
/* failed: have to try again, alloc more mem. */
if(n > -1) /* glibc 2.1 */
size = n + 1;
else /* glibc 2.0 */
size *= 2; /* twice the old size */
if((p = (char *)realloc (p, size)) == NULL)
return NULL;
}
}
typedef struct information {
DWORD address;
DWORD size;
char file[64];
DWORD line;
} ALLOC_INFO;
typedef list < ALLOC_INFO* > AllocList;
AllocList *allocList;
void AddTrack(DWORD addr, DWORD asize, const char *fname, DWORD lnum)
{
ALLOC_INFO *info;
if(!allocList) {
//allocList = new AllocList;
allocList = (AllocList*)malloc (sizeof (AllocList));
}
//info = new(ALLOC_INFO);
info = (ALLOC_INFO*) malloc (sizeof (ALLOC_INFO));
info->address = addr;
strncpy(info->file, fname, 63);
info->line = lnum;
info->size = asize;
allocList->insert(allocList->begin(), info);
}
void RemoveTrack(DWORD addr)
{
AllocList::iterator i;
if(!allocList)
if(!allocList)
return;
for(i = allocList->begin(); i != allocList->end(); i++)
{
if((*i)->address == addr)
{
allocList->remove((*i));
break;
}
}
}
void DumpUnfreed()
{
AllocList::iterator i;
DWORD totalSize = 0;
char buf[1024];
if(!allocList)
return;
for(i = allocList->begin(); i != allocList->end(); i++) {
sprintf(buf, "%-50s:\t\tLINE %d,\t\tADDRESS %d\t%d unfreed\n",
(*i)->file, (*i)->line, (*i)->address, (*i)->size);
OutputDebugString("%s",buf);
totalSize += (*i)->size;
}
sprintf(buf, "-----------------------------------------------------------\n");
OutputDebugString("%s",buf);
sprintf(buf, "Total Unfreed: %d bytes\n", totalSize);
OutputDebugString("%s",buf);
}
And my main.cpp is
#include "mynew.h"
int main()
{
char *ptr = new char;
DumpUnfreed();
return 0;
}
When i try to compile i get the following error
[root#dhcppc0 new]# !g
g++ main.cpp -D_DEBUG
mynew.h:25: error: declaration of ‘operator new’ as non-function
main.cpp: In function ‘int main()’:
main.cpp:9: error: no matching function for call to ‘operator new(unsigned int, const char [9], int)’
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/new:84: note: candidates are: void* operator new(size_t)
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/new:88: note: void* operator new(size_t, const std::nothrow_t&)
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/new:94: note: void* operator new(size_t, void*)
I know there is some thing wrong with my #defines, but I am not sure what is wrong.
Can any one please bale me out of this
You've defined your new macro before your functions. Your code ends up looking like:
void *
operator new(__FILE__, __LINE__)(unsigned int size, const char *file, int line)
Which is obviously wrong. Your should move the macro definitions underneath the functions (or better is to keep those functions in a .cpp file you link with.) For what it's worth, new is a keyword and cannot be an identifier, so your program is, strictly speaking, ill-formed.
I recently posted my global memory operators framework. It might help you a bit.
the signature don't match it sould be void* operator new (size_t size).
overriding single object new signature is
static void * operator new(site_t size),
roni