chiark / gitweb /
doxygen: don't crash during search building on too long function arguments.
authorVladimír Vondruš <mosra@centrum.cz>
Tue, 15 May 2018 15:25:25 +0000 (17:25 +0200)
committerVladimír Vondruš <mosra@centrum.cz>
Tue, 15 May 2018 15:29:58 +0000 (17:29 +0200)
In some very pathological cases the function parameter list might exceed
256 characters, which won't fit in the serialized data. But that also
won't fit in the search result list so there's no point in storing so
much. Truncating to 65 characters and adding an ellipsis after.

doxygen/dox2html5.py
doxygen/test/search_long_suffix_length/Doxyfile [new file with mode: 0644]
doxygen/test/search_long_suffix_length/File.h [new file with mode: 0644]
doxygen/test/test_search.py

index c70df8c7c38ee0658d54904c184e194b0e79c583..5c3b78a9d414ee0322ada895b3485b85f6cfefd7 100755 (executable)
@@ -1870,9 +1870,21 @@ def build_search_data(state: State, merge_subtrees=True, add_lookahead_barriers=
             name = result.name
             suffix_length = 0
             if hasattr(result, 'params') and result.params is not None:
-                params = strip_tags(', '.join(result.params))
-                name_with_args += '(' + params + ')'
-                suffix_length += len(html.unescape(params)) + 2
+                # Some very heavily templated function parameters might cause
+                # the suffix_length to exceed 256, which won't fit into the
+                # serialized search data. However that *also* won't fit in the
+                # search result list so there's no point in storing so much.
+                # Truncate it to 65 chars which could fit at least a part of
+                # the function name in the list in most cases, yet be still
+                # long enough to be able to distinguish particular overloads.
+                # TODO: the suffix_length has to be calculated on UTF-8 and I
+                # am (un)escaping a lot back and forth here -- needs to be
+                # cleaned up
+                params = html.unescape(strip_tags(', '.join(result.params)))
+                if len(params) > 65:
+                    params = params[:64] + '…'
+                name_with_args += '(' + html.escape(params) + ')'
+                suffix_length += len(params.encode('utf-8')) + 2
             if hasattr(result, 'suffix') and result.suffix:
                 name_with_args += result.suffix
                 # TODO: escape elsewhere so i don't have to unescape here
diff --git a/doxygen/test/search_long_suffix_length/Doxyfile b/doxygen/test/search_long_suffix_length/Doxyfile
new file mode 100644 (file)
index 0000000..44b01a4
--- /dev/null
@@ -0,0 +1,13 @@
+INPUT                   = File.h
+QUIET                   = YES
+GENERATE_HTML           = NO
+GENERATE_LATEX          = NO
+GENERATE_XML            = YES
+XML_PROGRAMLISTING      = NO
+
+M_PAGE_FINE_PRINT       =
+M_THEME_COLOR           =
+M_FAVICON               =
+M_LINKS_NAVBAR1         =
+M_LINKS_NAVBAR2         =
+M_SEARCH_DOWNLOAD_BINARY = YES
diff --git a/doxygen/test/search_long_suffix_length/File.h b/doxygen/test/search_long_suffix_length/File.h
new file mode 100644 (file)
index 0000000..8326f7c
--- /dev/null
@@ -0,0 +1,10 @@
+#include <string>
+#include <functional>
+#include <vector>
+
+/** @file
+ * @brief A file
+ */
+
+/** @brief One fun function */
+bool aVeryLongFunctionName(const std::reference_wrapper<const std::vector<std::string>>& a, const std::reference_wrapper<const std::vector<std::string>>& b, const std::reference_wrapper<const std::vector<std::string>>& c, const std::reference_wrapper<const std::vector<std::string>>& d, const std::reference_wrapper<const std::vector<std::string>>& e, const std::reference_wrapper<const std::vector<std::string>>& f, const std::reference_wrapper<const std::vector<std::string>>& g);
index a8c5da756e8a063a5a584d181623a1e07a0bfbde..05dfb2df87d57e39e1cb2344b24fe4c98284fd51 100755 (executable)
@@ -536,6 +536,34 @@ union [58]
 59: glUnion() [alias=58] ->
 """.strip())
 
+class SearchLongSuffixLength(IntegrationTestCase):
+    def __init__(self, *args, **kwargs):
+        super().__init__(__file__, 'long_suffix_length', *args, **kwargs)
+
+    def test(self):
+        self.run_dox2html5(index_pages=[], wildcard='*.xml')
+
+        with open(os.path.join(self.path, 'html', 'searchdata.bin'), 'rb') as f:
+            serialized = f.read()
+            search_data_pretty = pretty_print(serialized)[0]
+        #print(search_data_pretty)
+        self.assertEqual(len(serialized), 382)
+        # The parameters get cut off with an ellipsis
+        self.assertEqual(search_data_pretty, """
+2 symbols
+file.h [2]
+|     :$
+|      :averylongfunctionname [0]
+|                            ($
+|                             ) [1]
+averylongfunctionname [0]
+|                    ($
+|                     ) [1]
+0: ::aVeryLongFunctionName(const std::reference_wrapper<const std::vector<std::string>>&, c…) [prefix=2[:12], suffix_length=69, type=FUNC] -> #a1e9a11887275938ef5541070955c9d9c
+1:  [prefix=0[:46], suffix_length=67, type=FUNC] ->
+2: File.h [type=FILE] -> File_8h.html
+""".strip())
+
 if __name__ == '__main__': # pragma: no cover
     parser = argparse.ArgumentParser()
     parser.add_argument('file', help="file to pretty-print")