tmpfile_windows: fix temp file name collisions when appending an extension

Formerly, tmpnam_s was used to ensure a unique file name, but then we'd
append an extension to it, invalidating its uniqueness. Instead, we now
do our own uniqueness check by attempting to create a unique empty file
for write with new names until it succeeds.

Bug: tint:812
Change-Id: I90b85074ad2281f9904f24e8fddda80d67e61ba7
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/53061
Auto-Submit: Antonio Maiorano <amaiorano@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/utils/io/tmpfile_windows.cc b/src/utils/io/tmpfile_windows.cc
index 93634a8..a641d5f 100644
--- a/src/utils/io/tmpfile_windows.cc
+++ b/src/utils/io/tmpfile_windows.cc
@@ -22,17 +22,26 @@
 
 namespace {
 
-std::string TmpFilePath() {
+std::string TmpFilePath(const std::string& ext) {
   char name[L_tmpnam];
-  if (tmpnam_s(name, L_tmpnam - 1) == 0) {
-    return name;
+  // As we're adding an extension, to ensure the file is really unique, try
+  // creating it, failing if it already exists.
+  while (tmpnam_s(name, L_tmpnam - 1) == 0) {
+    std::string name_with_ext = std::string(name) + ext;
+    FILE* f = nullptr;
+    // The "x" arg forces the function to fail if the file already exists.
+    fopen_s(&f, name_with_ext.c_str(), "wbx");
+    if (f) {
+      fclose(f);
+      return name_with_ext;
+    }
   }
-  return "";
+  return {};
 }
 
 }  // namespace
 
-TmpFile::TmpFile(std::string ext) : path_(TmpFilePath() + ext) {}
+TmpFile::TmpFile(std::string ext) : path_(TmpFilePath(ext)) {}
 
 TmpFile::~TmpFile() {
   if (!path_.empty()) {