I have a file pointer exported from a dll, which is initialized(fopen) by the application and then used(fprintf) inside the dll.
The problem is fprintf will throw an exception.
DLLFile.c
#define BUILD_FOO
#include "API.H"
File *pFile;
void exportedFunction()
{
fprintf(pFile,"This will result in an exception\n");//<-This print will crash
}
API.H
#ifdef BUILD_FOO
# define FOOAPI __declspec(dllexport)
#else
# define FOOAPI __declspec(dllimport)
#endif
FOOAPI extern File *pFile;
FOOAPI void exportedFunction();
APLICATION.C
#undef BUILD_FOO
#include "API.H"
void main()
{
pFile = fopen("path_to_folder","wt");
fprintf(pFile , "This print will work"); // <- This will be printed ok
exportedFunction();
}
1 From the debugging I've done, this is what I saw:
Inside the application, fopen() assigns for pFile an element from _iob[].
In the DLL when fprintf is called, it is checked that pFile is part of the _iob[], but the _iob[] from the application seems not to be the same with the one in the DLL(they have different addresses).
2 I have the same use case(with the same application) and another somewhat similar DLL, and everything works ok there(the _iob[] is at the same place in the application and DLL).
This is likely being caused by your application and your DLL disagreeing on which version of the C runtime they're using. Unless they're both compiled against the exact same version of the C runtime, all bets are off, and you can't call CRT functions from one using the data from another or vice-versa.
The safest way to avoid this problem is not to pass FILE* pointers across DLL boundaries. That way, any interaction with a FILE* will always happen using the same version of the CRT, and there's no danger of any mismatches. So your DLL should not expose a FILE* variable; instead it should be some opaque type, and all operations on the variable need to happen in the same module.
For example:
// API.h
FOOAPI void set_file(void *file);
FOOAPI void set_fprintf_callback(int (*my_fprintf)(void *, const char *, ...));
FOOAPI void exportedFunction();
// DLLFile.c
void *pFile; // Not exported
int (*fprintf_callback)(void *, const char *, ...); // Not exported
FOOAPI set_file(void *file)
{
pFile = file;
}
FOOAPI set_fprintf_callback(int (*my_fprintf)(void *, const char *, ...))
{
fprintf_callback = my_fprintf;
}
FOOAPI exportedFunction()
{
// Call back into the application to do the actual fprintf
fprintf_callback(pFile, "This should not crash");
}
// Application.c
int mydll_fprintf(void *pFile, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int result = vfprintf((FILE *)pFile, fmt, ap);
va_end(ap);
return result;
}
int main()
{
FILE *pFile = fopen(...);
set_file(pFile);
set_fprintf_callback(&mydll_fprintf);
exportedFunction();
return 0;
}
Have the application pass to the DLL a callback, and in that callback, have the application write to the file.
Related
I have function in library lib.so which I'm linking to my application dynamically using dlopen()
lib.h
void DebugPrint( unsigned char logLevel,
const char *programName,
const char *format,
... );
#define DBG_PRINT(logLvl, format, ...) \
DebugPrint(logLvl,TL_MODULE_NAME, format, ## __VA_ARGS__)
myapp.c
void (*DBG_PRINT_ptr)( unsigned char logLevel,
const char *programName,
const char *format,
... );
void *handle = NULL;
bool ret = RESULT_SUCCESS;
/* Open Shared Lib into the same Process */
/* LDRA_INSPECTED 496 S */
handle = dlopen(lib.so, RTLD_NOW);
if (NULL == handle)
{
/* fail to load the library */
LLOG_error(" dlopen Error to open handle: %s\n", dlerror());
ret = RESULT_FAILURE;
}
if(RESULT_SUCCESS == ret)
{
DBG_PRINT_ptr = dlsym(handle, "DebugPrint");
if( DBG_PRINT_ptr == NULL)
{
LLOG_error("Failed in DBG_PRINT dlsym(): Err:%s", dlerror());
dlclose(handle);
ret = RESULT_FAILURE;
}
}
(void)DBG_PRINT_ptr ("loglevel1","dd","printval");
but I'm getting error while runtime
Failed in DBG_PRINT dlsym(): Err:Symbol not found
what is the correct way to define function pointer for the following requirement.
There is no way to point to a macro with a function pointer. Only functions can be pointed by a function pointer.
You can have a pointer to the function that the macro calls however. Like this:
auto fptr = &DebugPrint;
Symbol not found
This means that there is no symbol by that name in the dynamic library.
One typical mistake is to attempt to load a function which has C++ language linkage. The symbol of such function will be mangled and won't match the name of the function.
Functions can be declared to have C linkage with a language linkage declaration:
extern "C"
So the problem is the following. The project needs to intercept all file IO
operations, like open() and close(). I am trying to add printf() before calling the corresponding open() or close(). I am not supposed to rewrite the source code by changing open() or close() to myOpen() or myClose() for example. I have been trying to use LD_PRELOAD environment variable. But the indefinite loop problem came up. My problem is like this one.
int open(char * path,int flags,int mode)
{
// print file name
printf("open :%s\n",path);
return __open(path,flags,mode);
}
Yes, you want LD_PRELOAD.
You need to create a shared library (.so) that has code for all functions that you want to intercept. And, you want to set LD_PRELOAD to use that shared library
Here is some sample code for the open function. You'll need to do something similar for each function you want to intercept:
#define _GNU_SOURCE
#include <dlfcn.h>
int
open(const char *file,int flags,int mode)
{
static int (*real_open)(const char *file,int flags,int mode) = NULL;
int fd;
if (real_open == NULL)
real_open = dlsym(RTLD_NEXT,"open");
// do whatever special stuff ...
fd = real_open(file,flags,mode);
// do whatever special stuff ...
return fd;
}
I believe RTLD_NEXT is easiest and may be sufficient. Otherwise, you could add a constructor that does dlopen once on libc
UPDATE:
I am not familiar with C and I got the following problems with gcc. "error: 'NULL' undeclared (first use in this function)",
This is defined by several #include files, so try #include <stdio.h>. You'll need that if you want to call printf.
"error: 'RTLD_NEXT' undeclared (first use in this function)",
That is defined by doing #include <dlfcn.h> [as shown in my example]
and "symbol lookup error: ./hack_stackoverflow.so: undefined symbol: dlsym".
From man dlsym, it says: Link with -ldl So, add -ldl to the line that builds your .so.
Also, you have to be careful to prevent infinite recursion if the "special stuff" does something that loops back on your intercept function.
Notably, you want to call printf. If you intercept the write syscall, bad things may happen.
So, you need to keep track of when you're already in one of your intercept functions and not do anything special if already there. See the in_self variable.
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
ssize_t
write(int fd,const void *buf,size_t len)
{
static ssize_t (*real_write)(int fd,const void *buf,size_t len) = NULL;
static int in_self = 0;
ssize_t err;
if (real_write == NULL)
real_write = dlsym(RTLD_NEXT,"write");
++in_self;
if (in_self == 1)
printf("mywrite: fd=%d buf=%p len=%ld\n",fd,buf,len);
err = real_write(fd,buf,len);
if (in_self == 1)
printf("mywrite: fd=%d buf=%p err=%ld\n",fd,buf,err);
--in_self;
return err;
}
The above works okay for single threaded programs/environments, but if you're intercepting an arbitrary one, it could be multithreaded.
So, we'd have to initialize all the real_* pointers in a constructor. This is a function with a special attribute that tells the dynamic loader to call the function ASAP automatically.
And, we have to put in_self into thread local storage. We do this by adding the __thread attribute.
You may need to link with -lpthread as well as -ldl for the multithreaded version.
Edit: We also have to preserve the correct errno value
Putting it all together:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <errno.h>
static int (*real_open)(const char *file,int flags,int mode) = NULL;
static ssize_t (*real_write)(int fd,const void *buf,size_t len) = NULL;
__attribute__((constructor))
void
my_lib_init(void)
{
real_open = dlsym(RTLD_NEXT,"open");
real_write = dlsym(RTLD_NEXT,"write");
}
int
open(const char *file,int flags,int mode)
{
int fd;
// do whatever special stuff ...
fd = real_open(file,flags,mode);
// do whatever special stuff ...
return fd;
}
ssize_t
write(int fd,const void *buf,size_t len)
{
static int __thread in_self = 0;
int sverr;
ssize_t ret;
++in_self;
if (in_self == 1)
printf("mywrite: fd=%d buf=%p len=%ld\n",fd,buf,len);
ret = real_write(fd,buf,len);
// preserve errno value for actual syscall -- otherwise, errno may
// be set by the following printf and _caller_ will get the _wrong_
// errno value
sverr = errno;
if (in_self == 1)
printf("mywrite: fd=%d buf=%p ret=%ld\n",fd,buf,ret);
--in_self;
// restore correct errno value for write syscall
errno = sverr;
return ret;
}
I recently started programming in C and something I can't seem to get my head around is the way stdout prints to screen.
When I added all my statements in the main() function and used the printf() function everything worked well, all the printf() statements were able to print to stdout.
From Main.c
...
#include "HeaderFile.h"
int main(int argc, char * argv[]){
...
printf("%c\n", testChar);
return 0;/*End of execution. Returns 0 value and ends gracefully*/
}
...
But when I started to modularize my code in different functions, I realised that I have to insert the fflush(stdout) function at the end of each printf() function in order for the print function to print out to stdout:
From ReadFile.c
...
#include "HeaderFile.h"
void readFileFunction(char* file){
...
printf("%c\n", testChar);
fflush(stdout);
...
}
...
Header file:
/*This is the header file used by the Linked list program.*/
/*This is the header file used by the Linked list program.*/
#ifndef HEADERFILE_H /* Include guard */
#define HEADERFILE_H
#include <stdio.h> /*including the stdio file inside the Main.c file. stdio.h is a header file, where this and other similar functions are defined.*/
#include <string.h>/*including the string file inside the Main.c file. string.h is a header file, where this and other similar functions are defined.*/
#include <time.h>/*including the time file inside the Main.c file. time.h is a header file, where this and other similar functions are defined.*/
#include <stdint.h>/*including the stdint file inside the Main.c file. stdint.h is a header file, where this and other similar functions are defined.*/
#include <stdlib.h>/*including the stdlib file inside the Main.c file. stdlib.h is a header file, where this and other similar functions are defined.*/
#include <errno.h> /*including the errno file inside the Main.c file. errno.h is a header file, where this and other similar functions are defined.*/
#include <regex.h>
extern const char errorString[]; /*A string of characters. Indicates an error message when the program in-counters a problem during execution.*/
/*String constants used to match user input with a specific function.*/
extern const char *string1;
extern const char *string2;
extern const char *string3;
extern const char *string4;
extern const char *string5;
extern const char *string6;
extern const char *string7;
extern const char *string8;
extern const char *string9;
/*Node structure with character value and the next node.*/
typedef struct node {
char value;
char type;
struct node * next;
} nodeStruct;
/*function prototypes for every function being used in the code.*/
int removeChar(nodeStruct ** head, char value);
void readFileInit(char* file);
void readFileFunction(char *file);
void printList(nodeStruct * head) ;
void push(nodeStruct ** head, char value) ;
char tail(nodeStruct * head) ;
char head(nodeStruct * head) ;
int length(nodeStruct * head) ;
int pop(nodeStruct ** head) ;
int regularExpr (const char *patt, char *str) ;
void append(nodeStruct ** head, char value) ;
int insertAfter(nodeStruct ** head, char value, char value2) ;
int insertBefore(nodeStruct ** head, char value, char value2) ;
#endif // HEADERFILE_H
Would you please explain in details why this sudden difference?
The function prototype for fflush is this:
int fflush ( FILE * stream );
It flushes the file pointer to the stream ensuring its written.
Depending on the environment where the code is executing on, the stdout in this case could well be buffered, implying that it does not get written straight away. fflush alleviates that and ensures it is flushed out.
Another thing, the kernel could be under a load at the point of execution thus delaying the printing to the console or terminal in this case, in which case, ending up judiciously sprinkling fflush all over the place.
It might help to enclose a SCCE example as looking at the OP's question, it is not easy to discriminate as to why, more of rather what is happening.
Edit:
The code can specify that the output is automatically written without buffering by including this snippet
setbuf(stdout, NULL);
It would be good practice, to save the state of buffer control at the start, switch off the buffering, and at end of code execution restore the buffer control.
I have my program, which exec's another process (not mine, consider it a blackbox). Is there a way to detect operations, like open() and close(), for this child process?
Especially I'm interested in finding all newly created files, or existing files, that are opened with intention to be created (O_CREAT flag for open()).
The working approach is to redefine the open() within my own shared library and preload it inside exec()'ed process via LD_PRELOAD environment variable. Thanks to #alk for the approach.
The code for redefined open() looks like:
#include <fcntl.h>
#include <dlfcn.h>
#include <stdarg.h>
#include <sys/types.h>
extern "C" {
int open(const char *pathname, int flags, ...) {
bool has_mode = false;
mode_t mode = 0;
if (flags & O_CREAT) {
va_list ap;
va_start(ap, flags);
mode = va_arg(ap, mode_t);
has_mode = true;
va_end(ap);
}
using Fn = int (*)(const char * pathname, int flags, ...);
Fn new_open = reinterpret_cast<Fn>(dlsym(RTLD_NEXT, "open"));
// Do something useful.
if (has_mode) {
return new_open(pathname, flags, mode);
} else {
return new_open(pathname, flags);
}
}
} // extern "C"
The only problem is with fcntl.h - it may have some geeky declaration for the function open(). You need this file to get definition of the O_CREAT. Another way is to include the file with definition directly: in my case it's the file asm-generic/fcntl.h.
I'm working on a program that generates an FDF file for filling in an Adobe PDF form. Currently, I have various procedures that are called, as before each one terminates, it opens the FDF file, writes its particular data, and closes the file.
I'm trying to put the code for writing the data to the FDF file in a separate procedure, and then have the other procedures call it. This would allow for a greater separation of the code by task, and if I had to change it in the future, I could do so easily.
I'm having some problems though, as I need to pass varying amounts of variables to fprintf. That is, I used to have a line like this:
fprintf(fp,"<</T(f1_44(0))/V(%d)>>\n",wages);
I wrote the below function, but I can't get it to work:
void writeToFDF(FILE *fp, char *filename, char *data, char *arg)
{
/* independent method for writing to FDF file */
/* open file */
fp=fopen(filename,"a");
fprintf(fp,data,arg);
/* close file */
fclose(fp);
}
So in theory, I would then in the parent function call:
writeToFDF(fp,"1040.fdf","<</T(f1_44(0))/V(%d)>>\n",wages);
I'm getting errors right now, and I believe it has to do with the last part of the function's arguments. Also, how can I get it to work if I have multiple arguments?
Thank you.
You need vfprintf. It will accept a variable list of arguments.
Like this:
void writeToFDF(FILE *fp, char *filename, char *data, ...)
{
va_list pl;
/* independent method for writing to FDF file */
/* open file */
fp=fopen(filename,"a");
va_start (pl, data);
vfprintf(fp,data,pl);
/* close file */
fclose(fp);
va_end(pl);
}
EDIT: while I tried to stay as close to your original code, ephemient's solution that omits the FILE *fp argument is in fact better: fp has only local significance (it's opened and closed in this function) so it should not be passed around.
This is what vfprintf is for.
#include <stdarg.h>
#include <stdio.h>
void writeToFDF(const char *filename, const char *format, ...) {
va_list ap;
FILE *fp = fopen(filename, "a");
va_begin(ap, format);
vfprintf(fp, format, ap);
va_end(ap);
fclose(fp);
}
You will need to use a Variadic function. See Forward an invocation of a variadic function in C
#include <stdio.h>
#include <stdarg.h>
void foo(FILE *file, char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(file, fmt, ap);
va_end(ap);
}