[clang-format][PR41964] Fix crash with SIGFPE when TabWidth is set to 0 and line...
authorPaul Hoad <mydeveloperday@gmail.com>
Wed, 18 Sep 2019 18:57:09 +0000 (18:57 +0000)
committerPaul Hoad <mydeveloperday@gmail.com>
Wed, 18 Sep 2019 18:57:09 +0000 (18:57 +0000)
Summary:
clang-format 8.0 crashes with SIGFPE (floating point exception) when formatting following file:
app.cpp:
void a() {
//line starts with '\t'
}

$ clang-format -style='{TabWidth: 0}' app.cpp

Reviewers: owenpan, klimek, russellmcc, timwoj

Reviewed By: klimek

Subscribers: cfe-commits

Tags: #clang-tools-extra, #clang

Differential Revision: https://reviews.llvm.org/D67670

llvm-svn: 372246

clang/lib/Format/Encoding.h
clang/lib/Format/FormatTokenLexer.cpp
clang/lib/Format/WhitespaceManager.cpp
clang/unittests/Format/FormatTest.cpp

index fe3d5f0..a0d6641 100644 (file)
@@ -67,7 +67,8 @@ inline unsigned columnWidthWithTabs(StringRef Text, unsigned StartColumn,
     if (TabPos == StringRef::npos)
       return TotalWidth + columnWidth(Tail, Encoding);
     TotalWidth += columnWidth(Tail.substr(0, TabPos), Encoding);
-    TotalWidth += TabWidth - (TotalWidth + StartColumn) % TabWidth;
+    if (TabWidth)
+      TotalWidth += TabWidth - (TotalWidth + StartColumn) % TabWidth;
     Tail = Tail.substr(TabPos + 1);
   }
 }
index 009b884..e59a059 100644 (file)
@@ -657,7 +657,8 @@ FormatToken *FormatTokenLexer::getNextToken() {
         ++Column;
         break;
       case '\t':
-        Column += Style.TabWidth - Column % Style.TabWidth;
+        Column +=
+            Style.TabWidth - (Style.TabWidth ? Column % Style.TabWidth : 0);
         break;
       case '\\':
         if (i + 1 == e || (Text[i + 1] != '\r' && Text[i + 1] != '\n'))
index 33c0d53..5a44500 100644 (file)
@@ -815,19 +815,24 @@ void WhitespaceManager::appendIndentText(std::string &Text,
     Text.append(Spaces, ' ');
     break;
   case FormatStyle::UT_Always: {
-    unsigned FirstTabWidth =
-        Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
-    // Insert only spaces when we want to end up before the next tab.
-    if (Spaces < FirstTabWidth || Spaces == 1) {
+    if (Style.TabWidth) {
+      unsigned FirstTabWidth =
+          Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
+
+      // Insert only spaces when we want to end up before the next tab.
+      if (Spaces < FirstTabWidth || Spaces == 1) {
+        Text.append(Spaces, ' ');
+        break;
+      }
+      // Align to the next tab.
+      Spaces -= FirstTabWidth;
+      Text.append("\t");
+
+      Text.append(Spaces / Style.TabWidth, '\t');
+      Text.append(Spaces % Style.TabWidth, ' ');
+    } else if (Spaces == 1) {
       Text.append(Spaces, ' ');
-      break;
     }
-    // Align to the next tab.
-    Spaces -= FirstTabWidth;
-    Text.append("\t");
-
-    Text.append(Spaces / Style.TabWidth, '\t');
-    Text.append(Spaces % Style.TabWidth, ' ');
     break;
   }
   case FormatStyle::UT_ForIndentation:
@@ -837,14 +842,16 @@ void WhitespaceManager::appendIndentText(std::string &Text,
       // the first one.
       if (Indentation > Spaces)
         Indentation = Spaces;
-      unsigned Tabs = Indentation / Style.TabWidth;
-      Text.append(Tabs, '\t');
-      Spaces -= Tabs * Style.TabWidth;
+      if (Style.TabWidth) {
+        unsigned Tabs = Indentation / Style.TabWidth;
+        Text.append(Tabs, '\t');
+        Spaces -= Tabs * Style.TabWidth;
+      }
     }
     Text.append(Spaces, ' ');
     break;
   case FormatStyle::UT_ForContinuationAndIndentation:
-    if (WhitespaceStartColumn == 0) {
+    if (WhitespaceStartColumn == 0 && Style.TabWidth) {
       unsigned Tabs = Spaces / Style.TabWidth;
       Text.append(Tabs, '\t');
       Spaces -= Tabs * Style.TabWidth;
index b1fcd39..dc20faf 100644 (file)
@@ -9877,6 +9877,79 @@ TEST_F(FormatTest, ConfigurableUseOfTab) {
                Tab);
 }
 
+TEST_F(FormatTest, ZeroTabWidth) {
+  FormatStyle Tab = getLLVMStyleWithColumns(42);
+  Tab.IndentWidth = 8;
+  Tab.UseTab = FormatStyle::UT_Never;
+  Tab.TabWidth = 0;
+  EXPECT_EQ("void a(){\n"
+            "    // line starts with '\t'\n"
+            "};",
+            format("void a(){\n"
+                   "\t// line starts with '\t'\n"
+                   "};",
+                   Tab));
+
+  EXPECT_EQ("void a(){\n"
+            "    // line starts with '\t'\n"
+            "};",
+            format("void a(){\n"
+                   "\t\t// line starts with '\t'\n"
+                   "};",
+                   Tab));
+
+  Tab.UseTab = FormatStyle::UT_ForIndentation;
+  EXPECT_EQ("void a(){\n"
+            "    // line starts with '\t'\n"
+            "};",
+            format("void a(){\n"
+                   "\t// line starts with '\t'\n"
+                   "};",
+                   Tab));
+
+  EXPECT_EQ("void a(){\n"
+            "    // line starts with '\t'\n"
+            "};",
+            format("void a(){\n"
+                   "\t\t// line starts with '\t'\n"
+                   "};",
+                   Tab));
+
+  Tab.UseTab = FormatStyle::UT_ForContinuationAndIndentation;
+  EXPECT_EQ("void a(){\n"
+            "    // line starts with '\t'\n"
+            "};",
+            format("void a(){\n"
+                   "\t// line starts with '\t'\n"
+                   "};",
+                   Tab));
+
+  EXPECT_EQ("void a(){\n"
+            "    // line starts with '\t'\n"
+            "};",
+            format("void a(){\n"
+                   "\t\t// line starts with '\t'\n"
+                   "};",
+                   Tab));
+
+  Tab.UseTab = FormatStyle::UT_Always;
+  EXPECT_EQ("void a(){\n"
+            "// line starts with '\t'\n"
+            "};",
+            format("void a(){\n"
+                   "\t// line starts with '\t'\n"
+                   "};",
+                   Tab));
+
+  EXPECT_EQ("void a(){\n"
+            "// line starts with '\t'\n"
+            "};",
+            format("void a(){\n"
+                   "\t\t// line starts with '\t'\n"
+                   "};",
+                   Tab));
+}
+
 TEST_F(FormatTest, CalculatesOriginalColumn) {
   EXPECT_EQ("\"qqqqqqqqqqqqqqqqqqqqqqqqqq\\\n"
             "q\"; /* some\n"