Search code examples
c++cross-platformposixgoogletest

Why does `mkdtemp()` fail when called in googletest?


I've created a small RAII class that creates a unique temporary directory and deletes it again upon destruction. On Linux, it uses mkdtemp() to achieve this:

// temporaryDirectoryPath is an std::vector<char>
// containing u8"/tmp/nuclex-pixels-unittest-XXXXXX"

// Let mkdtemp() sort out a unique directory name for us (and create it!)
const char *directoryName = ::mkdtemp(&temporaryDirectoryPath[0]);
if(directoryName == nullptr) {
  perror("mkdtemp() failed."); // DEBUGGING. REMOVE.
  throw std::runtime_error("mkdtemp() failed.");
}

This works just fine when run on its own: runnable code on ideone.com


However, if I use that same code inside a GoogleTest 1.8.1 unit test declared like this:

TEST(MyTestFixture, CanFlumbleTempDirectory) {
  TemporaryDirectoryScope temporaryDirectory;
  // Could call temporaryDirectory.GetPath() here...
}

It fails:

Passing the following to mkdtemp(): /tmp/nuclex-pixels-unittest-XXXXXX
mkdtemp() failed.: Invalid argument

How can GoogleTest be interfering with mkdtemp()?


Solution

  • The string you pass to mkdtemp is not reliably null-terminated:

          // Then append our directory name template to it
          const char directoryNameTemplate[] = u8"nuclex-pixels-unittest-XXXXXX";
          {
            const char *iterator = directoryNameTemplate;
            while(*iterator != 0) {
              temporaryDirectoryPath.push_back(*iterator);
              ++iterator;
            }
          }
    

    std::vector<char> does not perform implicit null termination, unlike std::string. This works by accident if there happens to be a null byte after the "XXXXXX" suffix. Whether that this is the case depends on the execution environment.