format: Don't crash on non-literal import

import() with non-literal as argument was crashing in attempting to sort
them during format. There's no much intelligent that we can do to sort
for example a function call in import() so just treat them as empty so
they go before the literal ones. A stable sort guarantees that as a
group the relative order stays the same.

Crash found by afl-fuzz.

Bug: gn:156
Change-Id: If38d4d81a20bc90f28dd60332e3bb66206c0293e
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/7980
Reviewed-by: Brett Wilson <brettw@chromium.org>
Commit-Queue: Scott Graham <scottmg@chromium.org>
diff --git a/src/gn/command_format.cc b/src/gn/command_format.cc
index d475893..67cd78b 100644
--- a/src/gn/command_format.cc
+++ b/src/gn/command_format.cc
@@ -443,9 +443,14 @@
       const auto& b_args = b->AsFunctionCall()->args()->contents();
       std::string_view a_name;
       std::string_view b_name;
-      if (!a_args.empty())
+
+      // Non-literal imports are treated as empty names, and order is
+      // maintained. Arbitrarily complex expressions in import() are
+      // rare, and it probably doesn't make sense to sort non-string
+      // literals anyway, see format_test_data/083.gn.
+      if (!a_args.empty() && a_args[0]->AsLiteral())
         a_name = a_args[0]->AsLiteral()->value().value();
-      if (!b_args.empty())
+      if (!b_args.empty() && b_args[0]->AsLiteral())
         b_name = b_args[0]->AsLiteral()->value().value();
 
       auto is_absolute = [](std::string_view import) {
diff --git a/src/gn/command_format_unittest.cc b/src/gn/command_format_unittest.cc
index 4dea55e..2141f6f 100644
--- a/src/gn/command_format_unittest.cc
+++ b/src/gn/command_format_unittest.cc
@@ -127,3 +127,4 @@
 FORMAT_TEST(080)
 FORMAT_TEST(081)
 FORMAT_TEST(082)
+FORMAT_TEST(083)
diff --git a/src/gn/format_test_data/083.gn b/src/gn/format_test_data/083.gn
new file mode 100644
index 0000000..6936bf5
--- /dev/null
+++ b/src/gn/format_test_data/083.gn
@@ -0,0 +1,7 @@
+# Crash found by afl-fuzz (non-literal import).
+import("x")
+import(sources)
+import(zip)
+import(zap)
+import(a+b+c+d)
+import(zzz+yyy)
diff --git a/src/gn/format_test_data/083.golden b/src/gn/format_test_data/083.golden
new file mode 100644
index 0000000..445534d
--- /dev/null
+++ b/src/gn/format_test_data/083.golden
@@ -0,0 +1,7 @@
+# Crash found by afl-fuzz (non-literal import).
+import(sources)
+import(zip)
+import(zap)
+import(a + b + c + d)
+import(zzz + yyy)
+import("x")