Search code examples
cinitializationposixfuse

Read buffer is zero'd out when return variable is initialised


This is a real WTF situation... Am I going mad!?

I noticed that my FUSE read operation had started filling the buffer with zeros after I had updated my code to stop my linter complaining:

int cramp_read(const char* path, char* buf, size_t size, off_t offset, struct fuse_file_info* fi) {
  int res = 0;

  struct my_filep* f = get_filep(fi);
  (void)path;

  if (f) {
    switch (f->type) {
      case fd_normal:
        if (pread(f->filep, buf, size, offset) == -1) {
          res = -errno;
        }
        break;

      case fd_special:
        if (my_read(f->specialp, buf, size, offset) == -1) {
          res = -errno;
        }
        break;

      default:
        res = -EPERM;
    }
  } else {
    res = -EBADF;
  }

  return res;
}

That is, specifically the pread branch (I've yet to write my_read). However, debugging showed pread was correctly setting the buffer to the file contents... After some digging, I found the error was when I initialised my variables: that is, the int res = 0; seems to be causing this behaviour. If I change it back to int res;, it starts working again.

What's even more strange: When I leave the variable uninitialised and print it to stderr before the very last return -- i.e., after all the work has been done -- the pread fails and I get an EPERM error.

Could someone explain what is going on here? I've initialised my variables elsewhere, at my linter's request, and now I'm worried I've introduced a load of time bombs just waiting to be discovered!


Solution

  • OK, I'm an idiot! After reading the FUSE documentation, I found that ones read implementation is supposed to return the number of read bytes, rather than the usual FUSE interface of 0 for success and -errno on failure.

    The following fixed the problem, while leaving the initialisation:

    ...
    if ((res = pread(f->filep, buf, size, offset)) == -1) {
    ...
    

    (Likewise for my yet-to-be-implemented my_read branch.)