[hid-parser] Fix parsing on small inputs

Fix crashes that would happen when the
hid-parser was given null inputs, inputs
of size 0, or inputs without any tags.

ZX-4139 #comment

TEST: runtests -t hid-parser-test

Change-Id: Ieb0c4ac5e38843a5253e8e235986a062fb35cbf3
diff --git a/zircon/system/ulib/hid-parser/parser.cpp b/zircon/system/ulib/hid-parser/parser.cpp
index e9146e4..2e186cf 100644
--- a/zircon/system/ulib/hid-parser/parser.cpp
+++ b/zircon/system/ulib/hid-parser/parser.cpp
@@ -144,6 +144,11 @@
         // refer to collections in the source need to be translated to pointers
         // valid within the destination memory area.
 
+        // Check if we actually have items or report ids before going forward.
+        if (report_ids_.size() == 0 || coll_.size() == 0) {
+            return kParseMoreNeeded;
+        }
+
         // If report_ids_ has just the unnumbered report, then the device
         // doesn't declare report ids.
         bool no_report_id = !report_ids_[0].has_report_id;
@@ -703,6 +708,9 @@
 
     impl::ParseState state;
 
+    if (rpt_desc == nullptr || device == nullptr)
+        return kParseMoreNeeded;
+
     if (!state.Init())
         return kParseNoMemory;
 
diff --git a/zircon/system/ulib/hid-parser/test/hid-helper-test.cpp b/zircon/system/ulib/hid-parser/test/hid-helper-test.cpp
index a3882d5..b77e13c 100644
--- a/zircon/system/ulib/hid-parser/test/hid-helper-test.cpp
+++ b/zircon/system/ulib/hid-parser/test/hid-helper-test.cpp
@@ -18,6 +18,23 @@
 extern "C" const uint8_t push_pop_test[62];
 extern "C" const uint8_t minmax_signed_test[68];
 
+bool parse_empty_data() {
+    BEGIN_TEST;
+
+    hid::DeviceDescriptor* dev = nullptr;
+    uint8_t data[] = { 0 };
+    auto res = hid::ParseReportDescriptor(data, sizeof(data), &dev);
+    ASSERT_EQ(res, hid::ParseResult::kParseInvalidTag);
+
+    res = hid::ParseReportDescriptor(nullptr, 0, &dev);
+    ASSERT_EQ(res, hid::ParseResult::kParseMoreNeeded);
+
+    res = hid::ParseReportDescriptor(data, 0, &dev);
+    ASSERT_EQ(res, hid::ParseResult::kParseMoreNeeded);
+
+    END_TEST;
+}
+
 // Tests that the max values of the MinMax are parsed as unsigned
 // data when the min values are >= 0. Also tests that the max values
 // are parsed as signed data when the min values are < 0.
@@ -762,6 +779,7 @@
 }
 
 BEGIN_TEST_CASE(hidparser_helper_tests)
+RUN_TEST(parse_empty_data)
 RUN_TEST(parse_minmax_signed)
 RUN_TEST(parse_push_pop)
 RUN_TEST(usage_helper)