Does gcc wrap option takes effects on function printf ? - c

I wrote a wrap function to replace the printf of stdio.h. I found that the wrap option worked on functions in stdlib.h, like malloc or exit. But it did not work on printf or fprintf.
Does the option wrap takes effects on functions in stdio.h ? And how can I wrap an arbitrary function ? I cannot get useful guide from the ld document.
Here is the code :
//gcc wrap.c -g -Wl,--wrap,fprintf
int __real_fprintf(FILE *stream, const char *format, ...);
int main(){
fprintf(stderr, "MAIN!\n");
return 0;
}
int __wrap_fprintf(FILE *stream, const char *format, ...){
__real_fprintf(stderr, "WRAP!\n");
return 0;
}

If you want this to work properly for fprintf, you need to also add the flag -fno-builtin-fprintf to the command line. Othwise, gcc will optimize the call to fprintf to instead call fwrite, and the linker will not see a call to fprintf to wrap.
In general, to properly wrap any function, you may need the corresponding -fno-builtin- option as well.

fprintf without arguments (other than the format string) is optimized to fwrite. Change your call of fprintf to fprintf(stderr, "%s\n", "MAIN!"); and the wrapping will take effect.
int __real_fprintf(FILE *stream, const char *format, ...);
int main(){
fprintf(stderr, "%s\n", "MAIN!");
return 0;
}
int __wrap_fprintf(FILE *stream, const char *format, ...){
__real_fprintf(stderr, "WRAP!\n");
return 0;
}

Related

Conflicting types compiling a LD_PRELOAD wrapper

I tried to use LD_PRELOAD to hook sprintf function , so I will print to file the result of buffer:
#define _GNU_SOURCE
#include <stdio.h>
#include<dlfcn.h>
int sprintf (char * src , const char * format , char* argp)
{
int (*original_func)(char*,const char * , char*);
original_func = dlsym(RTLD_NEXT,"sprintf");
int ret = (*original_func)(src ,format,argp);
FILE* output = fopen("log.txt","a");
fprintf(output,"%s \n",src);
fclose(output);
return ret;
}
When I compile this code gcc -Wall -fPIC -shared -o my_lib.so test_ld.c -ldl
I got error
test_ld.c:5:5: error: conflicting types for ‘sprintf’
int sprintf (char * src , const char * format , char* argp)
^
In file included from test_ld.c:2:0:
/usr/include/stdio.h:364:12: note: previous declaration of ‘sprintf’ was here
extern int sprintf (char *__restrict __s,
How can I fix that?
The main problem you're having is that your prototype for sprintf doesn't match the official one. Your function has this signature:
int sprintf (char * src , const char * format , char* argp);
While the official one has:
int sprintf(char *str, const char *format, ...);
You'll need to change your function to have this signature. Once you do that, you'll need to use a va_list to get the variadic argument. Then you would use that to call vsprintf which takes an argument of this type instead of using dlsym to load sprintf.
#include <stdio.h>
#include <stdarg.h>
int sprintf (char * src , const char * format , ...)
{
va_list args;
va_start(args, format);
int ret = vsprintf(src, format, args);
va_end(args);
FILE* output = fopen("log.txt","a");
fprintf(output,"%s \n",src);
fclose(output);
return ret;
}
Alex's first solution nicely addresses one problem: the conflicting declarations of sprintf (although there is no reason to not use the same signature as in stdio.h, see dbush's answer) . However, even then there remains one large elephant in the room: sprintf is a variadic function.
That means that, whenever the wrapped program calls sprintf with anything other than one char * third argument, your output may not be correct (and may even depend on your compiler's -O level)
Calling variadic functions from variadic functions (what is essentially what you're doing here) is a known problem. Any solution will be non-portable. With gcc, you can use __buitlin_apply and tap into gccs own private way of handling argument lists:
/* sprintf.c, compile with gcc -Wall -fPIC -shared -o sprintf.so sprintf.c -ldl
and use with LD_PRELOAD=./sprintf.so <program> */
#define _GNU_SOURCE
#define sprintf xsprintf
#include <stdio.h>
#include<dlfcn.h>
#undef sprintf
# define ENOUGH 100 /* how many bytes of our call stack
to pass to the original function */
int sprintf (char *src) /* only needs the first argument */
{
void *original_func = dlsym(RTLD_NEXT,"sprintf");
void *arg = __builtin_apply_args();
void *ret = __builtin_apply((void *)original_func, arg, ENOUGH);
FILE* output = fopen("log.txt","a");
fprintf(output,"%s \n",src);
fclose(output);
__builtin_return(ret);
}
A few remarks:
In well-designed libraries variadic functions will have a non-variadic counterpart that uses one va_list argument instead of a variable number of arguments. In that case (and sprintf - vsprintf is such a case) you can use Alex's (portable) second solution with the va_* macros. If not, the solution with __builtin_apply() is the only possible, albeit gcc-specific, one.
See also: call printf using va_list
Possibly depending on the compiler version, when compiling main.c with the -O2 flag, main() will actually call __sprintf_chk() instead of sprintf() (regardless of -fno-builtin) and the wrapper won't work. To demonstrate the wrapper, compile main.c with -O0. Changing the main program to get the wrapper to work is the tail wagging the dog, of course. This shows the fragility of building wrappers: programs often don't call the library functions you expect. A ltrace <program> beforehand can save a lot of work....
You can rename the symbol in stdio, but then there's another problem, compilers like gcc use built-in implementations, unless you pass a flag like -fno-builtin, the compiler will generate the code inline in the executable, it won't link any library for functions like sprintf.
sprintf.c:
#define _GNU_SOURCE
#define sprintf xsprintf
#include <stdio.h>
#include<dlfcn.h>
#undef sprintf
int sprintf (char * src , const char * format , char* argp)
{
int (*original_func)(char*,const char * , char*);
original_func = dlsym(RTLD_NEXT,"sprintf");
int ret = (*original_func)(src ,format,argp);
FILE* output = fopen("log.txt","a");
fprintf(output,"%s \n",src);
fclose(output);
return ret;
}
main.c:
#include <stdio.h>
int main(int argc, char *argv[]) {
char buffer[80];
sprintf(buffer, "hello world");
puts(buffer);
return 0;
}
Makefile:
all: libsprintf.so main
main: main.c
gcc -Wall -O2 -fno-builtin -o main main.c
libsprintf.so: sprintf.c
gcc -Wall -O2 -shared -fPIC -fno-builtin -o libsprintf.so sprintf.c -ldl
.PHONY: clean
clean:
-rm -f main libsprintf.so
usage:
make
LD_PRELOAD=./libsprintf.so ./main
edit
sprintf.c with variadic implementation (it doesn't call sprintf):
#define _GNU_SOURCE
#define sprintf xsprintf
#include <stdio.h>
#include<dlfcn.h>
#undef sprintf
#include <stdarg.h>
int sprintf (char * src , const char * fmt , ...)
{
va_list args;
va_start(args, fmt);
int ret = vsprintf(src, fmt, args);
va_end(args);
FILE* output = fopen("log.txt","a");
fprintf(output,"%s \n", src);
fclose(output);
return ret;
}

snprintf function not declared?

I'm trying to use the snprintf function which based on the manual I've read is apart of the <stdio.h> header however I'm getting an error that it's been implicitly declared. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct users {
char* user_id;
};
typedef struct users users_t;
int save_user_detail(user_t);
int main() {
users_t users;
save_user_detail(users);
return 0;
}
int save_user_detail(users_t users)
{
printf("Type the filename = ");
scanf("%s", users.user_id);
char* extension = ".txt";
char fileSpec[strlen(users.user_id)+strlen(extension)+1];
FILE *file;
snprintf(fileSpec, sizeof(fileSpec), "%s%s", users.user_id, extension);
file = fopen(fileSpec, "w");
if(file==NULL)
{
printf("Error: can't open file.\n");
return 1;
}
else
{
printf("File written successfully.\n");
fprintf(file, "WORKS!\r\n");
}
fclose(file);
return 0;
}
You seem to be using gcc, but this compiler does not necessarily use the glibc, which is compliant with the C Standard and supports snprintf.
On the Windows architecture, you may be using the Microsoft C library, which in older versions did not have snprintf or renamed it as _snprintf.
Here are 2 ways you can try a work around your problem:
try using _snprintf instead of snprintf.
define snprintf manually after including <stdio.h> as
int snprintf(char *buf, size_t size, const char *fmt, ...);
The compiler should stop complaining about the missing prototype and if the runtime library does have a symbol for snprintf with a matching calling convention, it will link to it and the program should behave as expected.

Good Verbosity Macro (C99)

I'm looking to write what I would imagine is a fairly common macro. I want to emulate the repeated "-v" options on many POSIX programs by defining a bunch of macros of the following form:
#define V1(str, ...) if(optv >= 1){printf("%s: "str,prog,__VA_ARGS__);}
int main(int argc, char* argv[])
{
// ... stuff ...
int i = 1;
V1("This contains a variable: %d\n",i);
}
// Output:
// ./program: This contains a variable: 1
where optv counts the number of "-v" options found on the command line and prog contains the program name (neither shown). This works well, but the problem is that I have to use a variable. V1("Output") will generate a compiler error. I could always use V1("Output%s","") but there should be a cleaner solution.
The GNU C preprocessor has a special feature that lets you delete the trailing comma when there are no arguments filling the variadic portion by prepending the token-pasting operator ## to __VA_ARGS__:
#define V1(str, ...) if(optv < 1); else printf("%s: "str,prog, ## __VA_ARGS__)
Alternatively, if you wish to remain fully C99 compliant, you could incorporate the the format string parameter into the ellipsis, but in this instance you'll also need to refactor your code since you want to include the extra prog parameter between the format string and the varargs. Something like this might work:
#define V1(...) if(optv < 1); else myprintf(prog, __VA_ARGS__)
int myprintf(const char *prog, const char *fmt, ...)
{
// Print out the program name, then forward the rest onto printf
printf("%s: ", prog);
va_list ap;
va_start(ap, fmt);
int ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
Then, V1("Output") expands to myprintf(prog, "Output") without using any non-C99 compiler extensions.
EDIT
Also note that I inverted the if condition in the macro, due to some weird issues that can arise if you invoke the macro inside an if statement without braces—see this FAQ for a detailed explanation.
Why don't you use 2 different macros for each verbosity level; one which prints a message and variable, and one which just prints a message?
You should probably write yourself a small support function so that you can do the job cleanly:
extern void vb_print(const char *format, ...);
#define V1(...) do { if (optv >= 1) vb_print(__VA_ARGS__); } while (0)
I assume that both optv and prog are global variables. These would go into a header (you wouldn't write them out in the programs themselves, would you?).
The function can be:
#include <stdio.h>
#include <stdarg.h>
extern const char *prog;
void vb_print(const char *format, ...)
{
va_list args;
va_start(args, format);
printf("%s:", prog);
vprintf(format, args);
va_end(args);
}
There's no rocket science in there. You can tweak the system to your heart's content, allowing a choice of where the information is written, flushing the output, ensuring there's a newline at the end, etc.
Try this:
#define V1X(str, ...) if(optv >= 1) {printf("%s: "str,prog,__VA_ARGS__);} else
#define V1(...) V1X(__VA_ARGS__,0)
I believe that fixes the problem you described, and the else at the end fixed another problem.

Preloading my library for a few functions while using the original by others using LD_PRELOAD

I have written a wrapper for the open() syscall and preload it using the LD_PRELOAD environment variable. I want only a few functions of the program to use the modified open() whereas others would use the original. Separating the functions in two programs is not an option as one calls the other. How can it be done?
The use of function interposition in the following example is similar to this answer.
The example provides a write() wrapper function that calls the original write(). It is important to note that you cannot directly call the original write() because it will be interpreted as a call to the wrapper. The use of function pointers in main() demonstrates how you might go about avoiding confusion as to which write() you are calling.
Code: test.c
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
size_t write(int fd, const void *buf, size_t count)
{
static size_t (*write_func)(int, const void *, size_t) = NULL;
/* get reference to original (libc provided) write */
if (!write_func)
{
write_func = (size_t(*)(int, const void *, size_t)) dlsym(RTLD_NEXT, "write");
}
/* perform wrapper specific actions */
/* ... */
/* call original write() */
return write_func(fd, buf, count);
}
int main(int argc, char *argv[])
{
size_t (*wrap_write)(int, const void *, size_t);
size_t (*orig_write)(int, const void *, size_t);
char buf1[] = "write() wrapper called\n";
char buf2[] = "orignial write() called\n";
/* set pointer to write() wrapper to differentiate */
wrap_write = write;
/* get reference to original (libc provided) write() */
orig_write = (size_t(*)(int, const void *, size_t)) dlsym(RTLD_NEXT, "write");
/* call write() wrapper */
wrap_write(1, buf1, strlen(buf1));
/* call original write() */
orig_write(1, buf2, strlen(buf2));
return 0;
}
Output:
$ gcc -Wall -Werror -ldl test.c -o test
$ ./test
write() wrapper called
orignial write() called
$
First there must be a established way to distiguish the to-be-preloaded open from the default open. This can be done using a helper library (must be loaded dynamically), that offers another wrapped version of that special open. Replacing that one happens by preloading a variant of this library.

Pass format string through procedure to fprintf

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);
}

Resources