Merge "Fix bug found by fuzzer."
diff --git a/demangle/Android.mk b/demangle/Android.mk
new file mode 100644
index 0000000..e3cfc2a
--- /dev/null
+++ b/demangle/Android.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := demangle_fuzzer
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := \
+    Demangler.cpp \
+    demangle_fuzzer.cpp \
+
+LOCAL_CFLAGS := \
+    -Wall \
+    -Werror \
+    -Wextra \
+
+include $(BUILD_FUZZ_TEST)
diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp
index fb68119..5e17362 100644
--- a/demangle/DemangleTest.cpp
+++ b/demangle/DemangleTest.cpp
@@ -22,7 +22,14 @@
 
 #include "Demangler.h"
 
-TEST(DemangleTest, VoidArgumentTest) {
+TEST(DemangleTest, IllegalArgumentModifiers) {
+  Demangler demangler;
+
+  ASSERT_EQ("_Zpp4FUNKK", demangler.Parse("_Zpp4FUNKK"));
+  ASSERT_EQ("_Zpp4FUNVV", demangler.Parse("_Zpp4FUNVV"));
+}
+
+TEST(DemangleTest, VoidArgument) {
   Demangler demangler;
 
   ASSERT_EQ("func()", demangler.Parse("_ZN4funcEv"));
diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp
index 77cfd3b..1b7406d 100644
--- a/demangle/Demangler.cpp
+++ b/demangle/Demangler.cpp
@@ -542,9 +542,8 @@
     } else {
       suffix = " volatile";
     }
-    if (name[-1] == 'K' || name[-1] == 'V') {
+    if (!cur_state_.suffixes.empty() && (name[-1] == 'K' || name[-1] == 'V')) {
       // Special case, const/volatile apply as a single entity.
-      assert(!cur_state_.suffixes.empty());
       size_t index = cur_state_.suffixes.size();
       cur_state_.suffixes[index-1].insert(0, suffix);
     } else {
@@ -723,7 +722,8 @@
       && static_cast<size_t>(cur_name - name) < max_length) {
     cur_name = (this->*parse_func_)(cur_name);
   }
-  if (cur_name == nullptr || *cur_name != '\0' || function_name_.empty()) {
+  if (cur_name == nullptr || *cur_name != '\0' || function_name_.empty() ||
+      !cur_state_.suffixes.empty()) {
     return name;
   }
 
diff --git a/demangle/demangle_fuzzer.cpp b/demangle/demangle_fuzzer.cpp
new file mode 100644
index 0000000..83fafc2
--- /dev/null
+++ b/demangle/demangle_fuzzer.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <string>
+
+#include "Demangler.h"
+
+extern "C" void LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  std::vector<char> data_str(size + 1);
+  memcpy(data_str.data(), data, size);
+  data_str[size] = '\0';
+
+  Demangler demangler;
+  std::string demangled_name = demangler.Parse(data_str.data());
+  if (size != 0 && data_str[0] != '\0' && demangled_name.empty()) {
+    abort();
+  }
+}