Search code examples
cdebuggingc-preprocessorinstrumentation

Can I know the file and function names from where my function is called if it's from another .c?


I'm developing a library and I would like to know some data about the caller of one of the functions I'm offering. In particular, I would need to know the file name, function name and line where my function (a redefined malloc) is being called.

EDIT: Here's a minimum working example where I can detect when a user calls malloc and "redirect" him to my own malloc function:

main.c:

#include <stdio.h>
#include <stdlib.h>
#include "myLib.h"

int main(){
    printf("Inside main, asking for memory\n");

    int *p = malloc(sizeof(int));
    *p = 3;

    free(p);

    return 0;
}

myLib.c:

#include "myLib.h"

void * myAlloc (size_t size){
    void * p = NULL;

    fprintf(stderr, "Inside my own malloc\n");
    
    p = (malloc)(size);

    return p;
    
}
#undef malloc
#define malloc(size) myAlloc(size)

myLib.h:

#ifndef MYLIB_H
#define MYLIB_H

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

#define malloc(size) myAlloc(size)

void * myAlloc(size_t size);
#endif

I've tried using _FILE_ _func_ and _LINE_ keywords, but I can't make it work since it's in a different module.


Solution

  • You could:

    //mylib.h
    #ifndef MYLIB_H
    #define MYLIB_H
    
    #include <stdlib.h>
    // replace malloc in case it's already a macro
    #ifdef malloc
    #undef malloc
    #endif
    
    // I believe that from the standards point of view, this is undefined behavior
    #define malloc(size) my_alloc(size, __FILE__, __LINE__, __func__)
    
    #ifdef __GNUC__
    // Allow compiler to do static checking.
    __attribute__((__alloc_size__(1), __malloc__))
    #endif
    void *my_alloc(size_t size, const char *file, int line, const char *func);
    //    ^^^^^^^^ I do not like camelCase case - one snake case to rule them all.
    
    #endif
    
    // mylib.c
    #include "mylib.h" // do not ever mix uppercase and lowercase in filenames
    #undef malloc      // undef malloc so we don't call ourselves recursively
    #include <stdio.h>
    
    void *my_alloc(size_t size, const char *file, int line, const char *func){
        fprintf(stderr, "Och my god, you wouldn't believe it!\n"
              "A function %s in file %s at line %d called malloc!\n",
             func, file, line);
        return malloc(size);
    }
    

    You might also see how assert does it. If you are aiming at glibc, read glibc docs replacing malloc.

    Still as you discovered a user may do (malloc)(size) cicumvent macro expansion. You could do:

    void *my_alloc(size_t size, const char *file, int line, const char *func);
    
    static inline void *MY_ALLOC(size_t size) {
        return my_alloc(size, NULL, 0, NULL);
    }
    #define MY_ALLOC(size)  my_alloc(size, __FILE__, __LINE__, __func__)
    
    // if called with `malloc()` then MY_ALLOC is expanded
    // if called as `(malloc)`, then just expands to MY_ALLOC.
    #define malloc MY_ALLOC
    
    int main() {
        malloc(10);    // calls my_alloc(10, "main.c", 62, "main");
        (malloc)(20);  // calls my_alloc(20, NULL, 0, NULL);
    }