tags:

views:

576

answers:

3

I have an application where I need to write a new getpid function to replace the original one of the OS. The implementation would be similar to:

pid_t getpid(void)
{
    if (gi_PID != -1)
    {
     return gi_PID;
    }
    else
    {
     // OS level getpid() function
    }
}

How can I call the original getpid() implementation of the OS through this function?

EDIT: I tried:

pid_t getpid(void)
{
    if (gi_PID != -1)
    {
     return gi_PID;
    }
    else
    {
     return _getpid();
    }
}

as Jonathan has suggested. This gave me the following errors when compiling with g++:

In function pid_t getpid()': SerendibPlugin.cpp:882: error: _getpid' undeclared (first use this function) SerendibPlugin.cpp:882: error: (Each undeclared identifier is reported only once for each function it appears in.)

EDIT 2: I've managed to get this to work by using a function pointer and setting it to the next second symbol with the id "getpid", using dlsym(RTLD_NEXT, "getpid").

Here's my sample code:

vi xx.c
"xx.c" 23 lines, 425 characters 
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <dlfcn.h>

using namespace std;
pid_t(*___getpid)();

pid_t getpid(void)
{
    cout << "My getpid" << endl;
    cout << "PID :" << (*___getpid)() << endl;
    return (*___getpid)();
}

int main(void)
{
    ___getpid = (pid_t(*)())dlsym(RTLD_NEXT, "getpid");
    pid_t p1 = getpid();
    printf("%d \n", (int)p1);
    return(0);
}

g++ xx.c -o xout

My getpid
PID :7802
7802
+2  A: 

On many systems, you will find that getpid() is a 'weak symbol' for _getpid(), which can be called in lieu of getpid().


The first version of the answer mentioned __getpid(); the mention was removed swiftly since it was erroneous.

This code works for me on Solaris 10 (SPARC) - with a C++ compiler:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

extern "C" pid_t _getpid();

pid_t getpid(void)
{
    return(-1);
}

int main(void)
{
    pid_t p1 = getpid();
    pid_t p2 = _getpid();
    printf("%d vs %d\n", (int)p1, (int)p2);
    return(0);
}

This code works for me on Solaris 10 (SPARC) - with a C compiler:

Black JL: cat xx.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

pid_t getpid(void)
{
    return(-1);
}

int main(void)
{
    pid_t p1 = getpid();
    pid_t p2 = _getpid();
    printf("%d vs %d\n", (int)p1, (int)p2);
    return(0);
}
Black JL: make xx && ./xx
cc     xx.c   -o xx
"xx.c", line 13: warning: implicit function declaration: _getpid
-1 vs 29808
Black JL:
Jonathan Leffler
I'm using solaris 5.10. I tried _getpid and __getpid but both returned errors. I might be missing a header file. I'll keep trying.
Gayan
The sample you've given compiles and works fine with cc and gcc but fails to compile when using g++. Any pointers on how to get over this?
Gayan
Interesting - which version of g++? I tested using g++ 4.3.4 (4.4.0 still pending build; a pre-req library is playing tricks on me), built to use the system assembler and loader. What was the error you got?
Jonathan Leffler
A: 

You're using the terminology a bit incorrectly. It's not possible to override getpid() because it's not a virtual function. All you can do is attempt to replace getpid with a different function by various evil means.

But I must ask, why are you doing this? Replacing getpid means that any component which was depending on the return of getpid will now be receiving you're presumably modified result. This change has a very high risk of changing some other component.

What you're offering is a new functionality and hence should be a different function.

That being said if you truly want to take this approach the best way is to dynamic loading of the function. The original DLL will still contain the getpid function and you can access that via a combination of LoadLibrary/GetProcAddress on Windows or dlopen/dlsym on Linux. If you're using a different OS please specify.

EDIT Responding to comments that getpid needs to be testable

If testing is the concern then why not instead have a custom getpid method for you're application. For example, applicationGetPid(). For normal execution this could be forwarded off to the system getpid function. But during Unit Testing it could be used to produce more predictable values.

pid_t applicationGetPid() { 
#if UNIT_TEST
return SomeCodeForUnitTests;
#else
return getpid();
#endif
}
JaredPar
This sort of ovnerriding is necessary when unit tests (in a large system) do something like generate log messages with the current PID in them. Thus, you want the unit test output (the log files) to be easily diffable, so you want to override getpid(). That said, I agree with the premise of just making a new function and switching all the calling code. That would be the most straightforward in this case.
slacy
I agree with you. I'll correct the question.We're writing a test tool which could simulate the functionality of the other processes in the system. Some of our libraries use getpid to make sure whether a process is valid. The precise mechanics are a bit complex but I can assure you that we've taken this decision after a lot of consideration.
Gayan
@slacy, in that case then, wouldn't you be better served by creating a new function, which in normal code simply forwards to getpid. But during unit-test it's compiled out to a more predictable and testable function? This is a more reliable approach than replacing system calls.
JaredPar
@Jared Par - For unit testing, writing a function which could work in either situation is fine. But what we're doing is black box testing and there's no control over the code of the libraries or the actual applications being tested
Gayan
+1  A: 

You can use a macro:

in a .h, included in every file where you want to replace the getpid function

#define getpid mygetpid

Then, put your own implementation in a .cpp Be aware to not include the previous .h!

pid_t mygetpid() {
    // do what you want
    return getpid();
}
Jérôme
Wouldn't this call the mygetpid function recursively, since getpid is replaced with the defined value at compile time?
Gayan
Hum, I didn't thought in this point. The .h should be included in all the files where you want over writing getpid, and not include in the .cpp where you define mygetpid. The linker should find by himself the implementation of mygetpid.
Jérôme