How to override standard printf defined in gcc library

This is a discussion on How to override standard printf defined in gcc library within the C Programming forums, part of the General Programming Boards category; Hi, I am Rahul. We have a complete software written out (with n other shared libraries maintained by various other ...

  1. #1
    Registered User
    Join Date
    Oct 2009
    Posts
    1

    How to override standard printf defined in gcc library

    Hi,

    I am Rahul. We have a complete software written out (with n other shared libraries maintained by various other teams). The shared libraries are loaded at run time by the main executable depending upon what feature user wants to run. All across our code, we are using printf and fprintf to print messages on the screen for the user. Now, we are adding a Graphical interface to our software and require that all such messages are displayed in a separate window inside that Graphical interface (whenever user is running in Graphical mode, else messages should be printed to screen only). For this, we need to overload printf and fprintf in our code. We have a combination of C and C++ code, as well as due to vast code base distributed across teams, it is not possible to replace printf/fprintf in all the code with some other function. So, what we did, we defined our own printf and fprintf functions that look something as follows -

    Code:
    extern "C" int fprintf (FILE *__restrict __stream,
           __const char *__restrict __format, ...)
    {
       va_list args;
    
       va_start(args,__format);
    
       int return_status = 0;
       if (is_gui && (__stream == stdout || __stream == stderr)) {
           return_status = showMessageInGui(NULL, __format, args);
       }
       else {
           return_status = vfprintf(__stream, __format, args);
       }
    
       va_end(args);
       return return_status;
    }
    Above function is defined in main executable (where our main() lies). So, above definition is loaded before fprintf from gcc library is loaded. I guess, no fprintf should be picked from libgcc now.
    Above code works fine for following fprintf calls (that pass variable argument list to fprintf) -

    fprintf (stdout,"This is a variable argument message - %s\n", "Rahul Jain");

    However, for following fprintf call (that is not taking any variable arguments), it seems fprintf from libgcc is getting picked up as then print comes on the screen instead of our Graphical interface window -

    fprintf (stdout,"This is a variable argument message - Rahul Jain\n");

    I am not sure why this is happening. Is fprintf implemented as macro, such that it is working for case1 and not for case2. Can anybody help.

    If we look at the way by which the loader resolves various symbols on loading an application, it does something as follows -

    1. Load symbols defined and already binded in the executable
    2. Load the shared library on which the application depends and then resolve the still undefined symbols in the application.

    In my case, loader finds that fprintf/printf are already defined in my executable, so it should not lookup for this function while loading gcc shared library.

    It seems to be the case as in case#1 (with variable argument list given to fprintf my own version is getting called). This does not happens for case #2 however.

    I have also narrowed down that this issue comes with gcc 4.2.4 and not with gcc 3.4.2.

    You can easily reproduce this issue by creating a printf.c and defining your version of fprintf in it and calling it from main (defined in main.c)

    Does anyone know if any changes made between gcc 342 and gcc 424 that might be causing this issue, and if there is any workaround to it by some build time flags.

    I would be really greateful if someone can help me and reply as soon as possible, we have a hight priority delivery item and is very critical... Really appreciate your help guys. Once again, thanks guys for your replies.

  2. #2
    cas
    cas is offline
    Registered User
    Join Date
    Sep 2007
    Posts
    991
    My gcc (and likely yours) is being smart and optimizing the fprintf() call to an fwrite() call, because it knows there are no conversion specifiers in your function. You unfortunately pulled the rug out from under it by defining your own fprintf() function. I suspect there's a way to disable such optimizations, but you'll have to check gcc's documentation. It might simply be easier, though, to just write your own fwrite() as well, if you're going down that road; that way you don't have to ensure that all teams build with the "correct" optimization.

  3. #3
    Registered User
    Join Date
    Dec 2008
    Location
    Black River
    Posts
    128
    I'm fairly certain cas is right, but if I recall correctly, it's actually puts that is used instead of fwrite. From what I remember, the static format analyzer can determine that puts is a suitable replacement when you only use the %s qualifier and a '\n' at the end of the format string. I'm not sure, but I expect that using a parameter workaround may return the call to fprintf:

    Code:
    fprintf (stdout,"This is a variable argument message - %s%c", "Rahul Jain", '\n');

  4. #4
    cas
    cas is offline
    Registered User
    Join Date
    Sep 2007
    Posts
    991
    For gcc 4.4.2, at least, it's definitely fwrite(). To be certain, though (since optimizing fprintf() to fputs(), puts(), etc is possible) you probably would want to reimplement a number of the stdio functions.

    To test your compiler, simply build a test file with the -S flag and inspect the assembly output; or try compiling and using nm -u on the program to get an idea of what functions it calls.

  5. #5
    Registered User
    Join Date
    Dec 2008
    Location
    Black River
    Posts
    128
    My gcc also uses fwrite. I remember puts being used at some point because of an infamous bug where doing:

    Code:
    printf("%s\n", NULL);
    Caused a segfault because it expanded to puts which called strlen and tried to access a null pointer (printf should actually print "(null)").

  6. #6
    cas
    cas is offline
    Registered User
    Join Date
    Sep 2007
    Posts
    991
    Code:
    printf("%s\n", NULL);
    This is actually illegal code (passing NULL to %s is undefined), and so a compiler is perfectly fine in generating code that causes a segfault. In fact, the latest gcc (4.4.2) does just this, calling puts(NULL).

    gcc has gotten good at making use of optimizations that break code (something I have no problem with as long as gcc doesn't violate the standard). I recall one optimization that made use of the fact that overflowing a signed integer is undefined. Some code expected it to wrap and got a nasty surprise.

  7. #7
    Registered User
    Join Date
    Dec 2008
    Location
    Black River
    Posts
    128
    Quote Originally Posted by cas View Post
    Code:
    printf("%s\n", NULL);
    This is actually illegal code (passing NULL to %s is undefined), and so a compiler is perfectly fine in generating code that causes a segfault.
    Well, I don't have a copy of the standard atm, so I couldn't say. However, the point is that in many gcc implementations, calling printf("%s ", NULL) prints "(null)" because it does not call puts. Add a \n after the %s, though, and you will get a segfault. It's inconsistent behaviour on part of gcc.

  8. #8
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,249
    I think it would be better to just take the pain, and change all calls to fprintf() to refer to an in-house function, instead of this weird overriding. This sort of hack is how a formerly nice piece of code degenerates into a piece of crap over time.

    I'm actually rather surprised that a large, distributed team of programmers is making calls directly to standard functions in the first place. That's exactly how this sort of problem arises, and it usually only takes one nightmare like this before they learn the lesson.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problems reading entered race times C
    By loopymoo26 in forum C Programming
    Replies: 12
    Last Post: 05-23-2009, 07:38 AM
  2. Replies: 2
    Last Post: 03-05-2009, 09:25 AM
  3. Data Structure Eror
    By prominababy in forum C Programming
    Replies: 3
    Last Post: 01-06-2009, 08:35 AM
  4. menu problem!!! need U R G E N T help!!!
    By catcat28 in forum C Programming
    Replies: 16
    Last Post: 11-19-2007, 12:32 PM
  5. DLL compiling question
    By Noose in forum Windows Programming
    Replies: 2
    Last Post: 12-16-2004, 06:16 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21