When programming debug functions I am left with 2 options, either put them all within preprocessor blocks so that they don’t exist at release runtime, or put them within an if block with a constant variable (potentially determined at launch) to control their execution. I wanted to write an improved method where in release mode the end user doesn’t have access to the functions, but with a special DLL they can use them.
I want to know two things:
- Is this more efficient than using a semi-constant (determined at program launch) variable to control there execution. (e.g. will control flow prediction simply ignore all the calls to these debug functions)
- Is this is a good practice. To be precise, would this be frowned upon by developers or horrible for some other reason (like security).
The DLL contains an essentially empty DllMain, here are the important definitions:
#include <iostream> extern "C" void __cdecl println(const char* str) { #ifdef GEN_DEBUG_FUNCS std::cout << str << std::endl; #endif } extern "C" int __cdecl test() { #ifdef GEN_DEBUG_FUNCS return 1; #else return 0; #endif }
And on the primary program side of things we have:
The header to hold the function ptrs:
typedef void(__cdecl *f_println)(const char*); typedef int(__cdecl *f_test)(); #ifdef FPTR_INIT #define EXTERN #else #define EXTERN extern #endif EXTERN f_println println; EXTERN f_test test; /* Used for testing the functions in a CPP file other than main */ void testFuncs();
The CPP file to test the function pointers:
#include "FunctionPtrs.h" #include <iostream> void testFuncs() { println("Hello World"); std::cout << "funci() returned " << test() << std::endl; }
And finally the Main CPP file which contains the entry-point and function pointer loading:
#include <windows.h> #include <iostream> #define FPTR_INIT #include "FunctionPtrs.h" int importDeclarations(const bool debug); int main(int argc, char* argv[]) { bool debug = false; for(int i = 0; i < argc; ++i) { if(strcmp(argv[i], "--debug") == 0) { debug = true; } } const int status = importDeclarations(debug); if(status) { return status; } testFuncs(); system("pause"); return EXIT_SUCCESS; } int importDeclarations(const bool debug) { const char* path = debug ? "%PATH_TO_DLL%\debug\DebugDLL.dll" : "%PATH_TO_DLL%\release\DebugDLL.dll"; const HINSTANCE hGetProcIDDLL = LoadLibrary(path); if(!hGetProcIDDLL) { std::cout << "Could not load the dynamic library." << std::endl; return EXIT_FAILURE; } println = (f_println)GetProcAddress(hGetProcIDDLL, "println"); test = (f_test)GetProcAddress(hGetProcIDDLL, "test"); if(!println || !test) { std::cout << "Could not locate function." << std::endl; return EXIT_FAILURE; } return 0; }