Browse Source

Autogen: Check if a file is empty before reading it

Calling `std::string::front()` on an empty string results
in an undefined behavior by the C++ standard.
In gcc8 it causes an assertion to fail.

This adds a check to `AUTOGEN` if a file to read is empty
and in case avoids the use of an empty `std::string` buffer.

Closes #17793
Sebastian Holtermann 7 years ago
parent
commit
50b7be6d1f
1 changed files with 18 additions and 11 deletions
  1. 18 11
      Source/cmQtAutoGenerator.cxx

+ 18 - 11
Source/cmQtAutoGenerator.cxx

@@ -190,25 +190,32 @@ bool cmQtAutoGenerator::FileSystem::FileRead(std::string& content,
   bool success = false;
   {
     std::lock_guard<std::mutex> lock(Mutex_);
-    if (cmSystemTools::FileExists(filename)) {
+    if (cmSystemTools::FileExists(filename, true)) {
       std::size_t const length = cmSystemTools::FileLength(filename);
       cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
       if (ifs) {
-        content.resize(length);
-        ifs.read(&content.front(), content.size());
-        if (ifs) {
-          success = true;
+        if (length > 0) {
+          content.resize(length);
+          ifs.read(&content.front(), content.size());
+          if (ifs) {
+            success = true;
+          } else {
+            content.clear();
+            if (error != nullptr) {
+              error->append("Reading from the file failed.");
+            }
+          }
         } else {
+          // Readable but empty file
           content.clear();
-          if (error != nullptr) {
-            error->append("Reading from the file failed.");
-          }
+          success = true;
         }
       } else if (error != nullptr) {
         error->append("Opening the file for reading failed.");
       }
     } else if (error != nullptr) {
-      error->append("The file does not exist.");
+      error->append(
+        "The file does not exist, is not readable or is a directory.");
     }
   }
   return success;
@@ -539,8 +546,8 @@ void cmQtAutoGenerator::ReadOnlyProcessT::UVExit(uv_process_t* handle,
 void cmQtAutoGenerator::ReadOnlyProcessT::UVTryFinish()
 {
   // There still might be data in the pipes after the process has finished.
-  // Therefore check if the process is finished AND all pipes are closed before
-  // signaling the worker thread to continue.
+  // Therefore check if the process is finished AND all pipes are closed
+  // before signaling the worker thread to continue.
   if (UVProcess_.get() == nullptr) {
     if (UVPipeOut_.uv_pipe() == nullptr) {
       if (UVPipeErr_.uv_pipe() == nullptr) {