Search code examples
cposixstat

How can I write a function stub for stat() function?


I am trying to write a stub for the function stat() from <sys/stat.h>. I was able to successfully do this for fstat with the following code:

static int fstat_count;
static int fstat_fail_instance;
int my_fstat(const int fd, struct stat * st) {
  fstat_count ++;
  if (fstat_count == fstat_fail_instance) {
    return EINVAL;
  }
  st->st_size = ST_SIZE;
  return EOK;
}
#undef fstat
#define fstat my_fstat

When I try to do this with stat, I get errors like:

mkqfs_file_test.c:28:20: error: storage size of ‘sb’ isn’t known
  const struct stat sb;

which i believe is because when I do the #undef stat #define stat my_stat like i do for fstat, it is undefining the struct stat not the function. Any idea how I can resolve this, ie only undefine/redefine function?


Solution

  • [...] I get errors like:

    mkqfs_file_test.c:28:20: error: storage size of ‘sb’ isn’t known
      const struct stat sb;
    

    which i believe is because when I do the #undef stat #define stat my_stat like i do for fstat, it is undefining the struct stat not the function.

    No, #undef stat does not undefine any function or any struct type. It undefines any previous definition of a preprocessor macro with that name. As such, it is probably unnecessary, and at worst it is harmless. In the unlikely event that there were such an existing macro definition, however, a conforming program does need to undefine that before redefining it.

    The problem is rather with the #define. If the definition of the stat macro is visible where your struct declaration appears then it will be expanded where that identifier is used as a structure tag. As a result, this ...

      const struct stat sb;
    

    ... expands to ...

      const struct my_stat sb;
    

    . There being no definition of a type struct my_struct visible in scope, that declaration is not permitted. As the compiler says, it doesn't know how much space to provide for a struct my_stat, nor would it be usable anyway because the compiler doesn't know what any of its members are, either. Note that this does not prevent declaring or using pointers to a struct my_stat, but that has its own issues.

    Any idea how I can resolve this, ie only undefine/redefine function?

    Again, you are not undefining any function. There is no completely clean way to use a macro to substitute your my_stat() for stat() on account of stat being used for related purposes in different namespaces. There are three main things you could do:

    1. Use a function-like macro instead:

      #define stat(p,b) my_stat((p),(b))
      

      In that event, you must ensure that there is no attempt to compute a pointer to stat. This is probably your best option.

    2. Omit the #undefine and #define altogether, and name your replacement function stat(), the same as the original. This relies on the linker to choose your locally-defined version over the library version, which it probably will do. That risks having wider impact than you intend, however.

    3. Before the #undefine, declare a typedef for struct stat:

      typedef struct stat struct_stat;
      #undefine stat
      #define stat my_stat
      

      Then use the typedef instead of type struct stat everywhere that your macro definition is visible:

      struct_stat sb;