From 0fbe9cea692f8c302bfb5104547403d42b676ff5 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 29 Dec 2024 19:39:41 -0500 Subject: [PATCH] have better ubsan stack trace --- include/ada/implementation-inl.h | 26 +++++++++++------------ include/ada/url_pattern.h | 32 ++++++++++++++--------------- include/ada/url_pattern_helpers.h | 5 +++-- src/parser.cpp | 24 +++++++++++----------- src/url_pattern.cpp | 34 ++++++++++++++++--------------- src/url_pattern_helpers.cpp | 6 +++--- tests/wpt_urlpattern_tests.cpp | 2 +- 7 files changed, 66 insertions(+), 63 deletions(-) diff --git a/include/ada/implementation-inl.h b/include/ada/implementation-inl.h index 8ac50a60e..7132ff39f 100644 --- a/include/ada/implementation-inl.h +++ b/include/ada/implementation-inl.h @@ -19,7 +19,7 @@ parse_url_pattern(std::variant input, // Set init to the result of running parse a constructor string given input. auto parse_result = url_pattern_helpers::constructor_string_parser::parse( std::get(input)); - if (!parse_result) { + if (!parse_result.has_value()) { ada_log("constructor_string_parser::parse failed"); return tl::unexpected(parse_result.error()); } @@ -53,7 +53,7 @@ parse_url_pattern(std::variant input, auto processed_init = url_pattern_init::process( init, "pattern", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt); - if (!processed_init) { + if (!processed_init.has_value()) { ada_log("url_pattern_init::process failed for init and 'pattern'"); return tl::unexpected(processed_init.error()); } @@ -103,7 +103,7 @@ parse_url_pattern(std::variant input, processed_init->protocol.value(), url_pattern_helpers::canonicalize_protocol, url_pattern_compile_component_options::DEFAULT); - if (!protocol_component) { + if (!protocol_component.has_value()) { ada_log("url_pattern_component::compile failed for protocol ", processed_init->protocol.value()); return tl::unexpected(protocol_component.error()); @@ -117,7 +117,7 @@ parse_url_pattern(std::variant input, processed_init->username.value(), url_pattern_helpers::canonicalize_username, url_pattern_compile_component_options::DEFAULT); - if (!username_component) { + if (!username_component.has_value()) { ada_log("url_pattern_component::compile failed for username ", processed_init->username.value()); return tl::unexpected(username_component.error()); @@ -131,7 +131,7 @@ parse_url_pattern(std::variant input, processed_init->password.value(), url_pattern_helpers::canonicalize_password, url_pattern_compile_component_options::DEFAULT); - if (!password_component) { + if (!password_component.has_value()) { ada_log("url_pattern_component::compile failed for password ", processed_init->password.value()); return tl::unexpected(password_component.error()); @@ -153,7 +153,7 @@ parse_url_pattern(std::variant input, processed_init->hostname.value(), url_pattern_helpers::canonicalize_ipv6_hostname, url_pattern_compile_component_options::DEFAULT); - if (!hostname_component) { + if (!hostname_component.has_value()) { ada_log("url_pattern_component::compile failed for ipv6 hostname ", processed_init->hostname.value()); return tl::unexpected(hostname_component.error()); @@ -167,7 +167,7 @@ parse_url_pattern(std::variant input, processed_init->hostname.value(), url_pattern_helpers::canonicalize_hostname, url_pattern_compile_component_options::HOSTNAME); - if (!hostname_component) { + if (!hostname_component.has_value()) { ada_log("url_pattern_component::compile failed for hostname ", processed_init->hostname.value()); return tl::unexpected(hostname_component.error()); @@ -180,7 +180,7 @@ parse_url_pattern(std::variant input, auto port_component = url_pattern_component::compile( processed_init->port.value(), url_pattern_helpers::canonicalize_port, url_pattern_compile_component_options::DEFAULT); - if (!port_component) { + if (!port_component.has_value()) { ada_log("url_pattern_component::compile failed for port ", processed_init->port.value()); return tl::unexpected(port_component.error()); @@ -190,7 +190,7 @@ parse_url_pattern(std::variant input, // Let compileOptions be a copy of the default options with the ignore case // property set to options["ignoreCase"]. auto compile_options = url_pattern_compile_component_options::DEFAULT; - if (options) { + if (options != nullptr) { compile_options.ignore_case = options->ignore_case; } @@ -212,7 +212,7 @@ parse_url_pattern(std::variant input, auto pathname_component = url_pattern_component::compile( processed_init->pathname.value(), url_pattern_helpers::canonicalize_pathname, path_compile_options); - if (!pathname_component) { + if (!pathname_component.has_value()) { ada_log("url_pattern_component::compile failed for pathname ", processed_init->pathname.value()); return tl::unexpected(pathname_component.error()); @@ -225,7 +225,7 @@ parse_url_pattern(std::variant input, auto pathname_component = url_pattern_component::compile( processed_init->pathname.value(), url_pattern_helpers::canonicalize_opaque_pathname, compile_options); - if (!pathname_component) { + if (!pathname_component.has_value()) { ada_log("url_pattern_component::compile failed for opaque pathname ", processed_init->pathname.value()); return tl::unexpected(pathname_component.error()); @@ -238,7 +238,7 @@ parse_url_pattern(std::variant input, auto search_component = url_pattern_component::compile( processed_init->search.value(), url_pattern_helpers::canonicalize_search, compile_options); - if (!search_component) { + if (!search_component.has_value()) { ada_log("url_pattern_component::compile failed for search ", processed_init->search.value()); return tl::unexpected(search_component.error()); @@ -250,7 +250,7 @@ parse_url_pattern(std::variant input, auto hash_component = url_pattern_component::compile( processed_init->hash.value(), url_pattern_helpers::canonicalize_hash, compile_options); - if (!hash_component) { + if (!hash_component.has_value()) { ada_log("url_pattern_component::compile failed for hash ", processed_init->hash.value()); return tl::unexpected(hash_component.error()); diff --git a/include/ada/url_pattern.h b/include/ada/url_pattern.h index 13466dd62..818dcba6c 100644 --- a/include/ada/url_pattern.h +++ b/include/ada/url_pattern.h @@ -128,12 +128,12 @@ enum class url_pattern_part_modifier : uint8_t { class url_pattern_part { public: url_pattern_part(url_pattern_part_type _type, std::string&& _value, - url_pattern_part_modifier _modifier) + url_pattern_part_modifier _modifier) noexcept : type(_type), value(_value), modifier(_modifier) {} url_pattern_part(url_pattern_part_type _type, std::string&& _value, url_pattern_part_modifier _modifier, std::string&& _name, - std::string&& _prefix, std::string&& _suffix) + std::string&& _prefix, std::string&& _suffix) noexcept : type(_type), value(_value), modifier(_modifier), @@ -159,10 +159,10 @@ class url_pattern_part { // @see https://urlpattern.spec.whatwg.org/#options-header struct url_pattern_compile_component_options { - url_pattern_compile_component_options() = default; + url_pattern_compile_component_options() noexcept = default; explicit url_pattern_compile_component_options( std::optional new_delimiter = std::nullopt, - std::optional new_prefix = std::nullopt) + std::optional new_prefix = std::nullopt) noexcept : delimiter(new_delimiter), prefix(new_prefix) {} std::string_view get_delimiter() const ada_warn_unused; @@ -188,25 +188,25 @@ struct url_pattern_compile_component_options { // URLPatternComponentResult API is defined as part of the URLPattern // specification. struct url_pattern_component_result { - std::string input; - std::unordered_map groups; + std::string input{}; + std::unordered_map groups{}; }; class url_pattern_component { public: - url_pattern_component() = default; + url_pattern_component() noexcept = default; // This function explicitly takes a std::string because it is moved. // To avoid unnecessary copy, move each value while calling the constructor. - url_pattern_component(std::string_view new_pattern, std::regex&& new_regexp, + url_pattern_component(std::string&& new_pattern, std::regex&& new_regexp, std::regex_constants::syntax_option_type new_flags, std::vector&& new_group_name_list, - bool new_has_regexp_groups) - : regexp(new_regexp), + bool new_has_regexp_groups) noexcept + : has_regexp_groups(new_has_regexp_groups), + regexp(new_regexp), + group_name_list(std::move(new_group_name_list)), pattern(std::move(new_pattern)), - flags(new_flags), - group_name_list(new_group_name_list), - has_regexp_groups(new_has_regexp_groups) {} + flags(new_flags) {} // @see https://urlpattern.spec.whatwg.org/#compile-a-component template @@ -220,11 +220,11 @@ class url_pattern_component { std::string to_string() const; + bool has_regexp_groups{false}; std::regex regexp{}; - std::string pattern{}; - std::regex_constants::syntax_option_type flags = std::regex::ECMAScript; std::vector group_name_list{}; - bool has_regexp_groups = false; + std::string pattern{}; + std::regex_constants::syntax_option_type flags{std::regex::ECMAScript}; }; using url_pattern_input = std::variant; diff --git a/include/ada/url_pattern_helpers.h b/include/ada/url_pattern_helpers.h index a2f685992..5845d05bf 100644 --- a/include/ada/url_pattern_helpers.h +++ b/include/ada/url_pattern_helpers.h @@ -83,9 +83,9 @@ class url_pattern_parser { // @see https://urlpattern.spec.whatwg.org/#is-a-duplicate-name bool is_duplicate_name(std::string_view name); - std::vector tokens{}; F encoding_callback; std::string segment_wildcard_regexp; + std::vector tokens{}; std::vector parts{}; std::string pending_fixed_value{}; size_t index = 0; @@ -136,7 +136,8 @@ class Tokenizer { }; // @see https://urlpattern.spec.whatwg.org/#constructor-string-parser -struct constructor_string_parser { +class constructor_string_parser { + public: explicit constructor_string_parser(std::string_view new_input, std::vector&& new_token_list) : input(new_input), token_list(std::move(new_token_list)) {} diff --git a/src/parser.cpp b/src/parser.cpp index d7d31336e..78ec07733 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -911,7 +911,7 @@ tl::expected parse_url_pattern_impl( // Set init to the result of running parse a constructor string given input. auto parse_result = url_pattern_helpers::constructor_string_parser::parse( std::get(input)); - if (!parse_result) { + if (!parse_result.has_value()) { ada_log("constructor_string_parser::parse failed"); return tl::unexpected(parse_result.error()); } @@ -945,7 +945,7 @@ tl::expected parse_url_pattern_impl( auto processed_init = url_pattern_init::process( init, "pattern", std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt); - if (!processed_init) { + if (!processed_init.has_value()) { ada_log("url_pattern_init::process failed for init and 'pattern'"); return tl::unexpected(processed_init.error()); } @@ -995,7 +995,7 @@ tl::expected parse_url_pattern_impl( processed_init->protocol.value(), url_pattern_helpers::canonicalize_protocol, url_pattern_compile_component_options::DEFAULT); - if (!protocol_component) { + if (!protocol_component.has_value()) { ada_log("url_pattern_component::compile failed for protocol ", processed_init->protocol.value()); return tl::unexpected(protocol_component.error()); @@ -1009,7 +1009,7 @@ tl::expected parse_url_pattern_impl( processed_init->username.value(), url_pattern_helpers::canonicalize_username, url_pattern_compile_component_options::DEFAULT); - if (!username_component) { + if (!username_component.has_value()) { ada_log("url_pattern_component::compile failed for username ", processed_init->username.value()); return tl::unexpected(username_component.error()); @@ -1023,7 +1023,7 @@ tl::expected parse_url_pattern_impl( processed_init->password.value(), url_pattern_helpers::canonicalize_password, url_pattern_compile_component_options::DEFAULT); - if (!password_component) { + if (!password_component.has_value()) { ada_log("url_pattern_component::compile failed for password ", processed_init->password.value()); return tl::unexpected(password_component.error()); @@ -1045,7 +1045,7 @@ tl::expected parse_url_pattern_impl( processed_init->hostname.value(), url_pattern_helpers::canonicalize_ipv6_hostname, url_pattern_compile_component_options::DEFAULT); - if (!hostname_component) { + if (!hostname_component.has_value()) { ada_log("url_pattern_component::compile failed for ipv6 hostname ", processed_init->hostname.value()); return tl::unexpected(hostname_component.error()); @@ -1059,7 +1059,7 @@ tl::expected parse_url_pattern_impl( processed_init->hostname.value(), url_pattern_helpers::canonicalize_hostname, url_pattern_compile_component_options::HOSTNAME); - if (!hostname_component) { + if (!hostname_component.has_value()) { ada_log("url_pattern_component::compile failed for hostname ", processed_init->hostname.value()); return tl::unexpected(hostname_component.error()); @@ -1072,7 +1072,7 @@ tl::expected parse_url_pattern_impl( auto port_component = url_pattern_component::compile( processed_init->port.value(), url_pattern_helpers::canonicalize_port, url_pattern_compile_component_options::DEFAULT); - if (!port_component) { + if (!port_component.has_value()) { ada_log("url_pattern_component::compile failed for port ", processed_init->port.value()); return tl::unexpected(port_component.error()); @@ -1104,7 +1104,7 @@ tl::expected parse_url_pattern_impl( auto pathname_component = url_pattern_component::compile( processed_init->pathname.value(), url_pattern_helpers::canonicalize_pathname, path_compile_options); - if (!pathname_component) { + if (!pathname_component.has_value()) { ada_log("url_pattern_component::compile failed for pathname ", processed_init->pathname.value()); return tl::unexpected(pathname_component.error()); @@ -1117,7 +1117,7 @@ tl::expected parse_url_pattern_impl( auto pathname_component = url_pattern_component::compile( processed_init->pathname.value(), url_pattern_helpers::canonicalize_opaque_pathname, compile_options); - if (!pathname_component) { + if (!pathname_component.has_value()) { ada_log("url_pattern_component::compile failed for opaque pathname ", processed_init->pathname.value()); return tl::unexpected(pathname_component.error()); @@ -1130,7 +1130,7 @@ tl::expected parse_url_pattern_impl( auto search_component = url_pattern_component::compile( processed_init->search.value(), url_pattern_helpers::canonicalize_search, compile_options); - if (!search_component) { + if (!search_component.has_value()) { ada_log("url_pattern_component::compile failed for search ", processed_init->search.value()); return tl::unexpected(search_component.error()); @@ -1142,7 +1142,7 @@ tl::expected parse_url_pattern_impl( auto hash_component = url_pattern_component::compile( processed_init->hash.value(), url_pattern_helpers::canonicalize_hash, compile_options); - if (!hash_component) { + if (!hash_component.has_value()) { ada_log("url_pattern_component::compile failed for hash ", processed_init->hash.value()); return tl::unexpected(hash_component.error()); diff --git a/src/url_pattern.cpp b/src/url_pattern.cpp index 7f1e80187..b24c69d59 100644 --- a/src/url_pattern.cpp +++ b/src/url_pattern.cpp @@ -82,7 +82,7 @@ tl::expected url_pattern_init::process( // Set baseURL to the result of parsing init["baseURL"]. auto parsing_result = ada::parse(*init.base_url); // If baseURL is failure, then throw a TypeError. - if (!parsing_result) { + if (!parsing_result.has_value()) { return tl::unexpected(url_pattern_errors::type_error); } base_url = std::move(*parsing_result); @@ -177,7 +177,7 @@ tl::expected url_pattern_init::process( // process protocol for init given init["protocol"] and type. if (init.protocol) { auto process_result = process_protocol(*init.protocol, type); - if (!process_result) { + if (!process_result.has_value()) { return tl::unexpected(process_result.error()); } result.protocol = std::move(*process_result); @@ -187,7 +187,7 @@ tl::expected url_pattern_init::process( // process username for init given init["username"] and type. if (init.username.has_value()) { auto process_result = process_username(*init.username, type); - if (!process_result) { + if (!process_result.has_value()) { return tl::unexpected(process_result.error()); } result.username = std::move(*process_result); @@ -197,7 +197,7 @@ tl::expected url_pattern_init::process( // process password for init given init["password"] and type. if (init.password.has_value()) { auto process_result = process_password(*init.password, type); - if (!process_result) { + if (!process_result.has_value()) { return tl::unexpected(process_result.error()); } result.password = std::move(*process_result); @@ -207,7 +207,7 @@ tl::expected url_pattern_init::process( // process hostname for init given init["hostname"] and type. if (init.hostname.has_value()) { auto process_result = process_hostname(*init.hostname, type); - if (!process_result) { + if (!process_result.has_value()) { return tl::unexpected(process_result.error()); } result.hostname = std::move(*process_result); @@ -218,7 +218,7 @@ tl::expected url_pattern_init::process( if (init.port) { auto process_result = process_port(*init.port, result.protocol.value_or("fake"), type); - if (!process_result) { + if (!process_result.has_value()) { return tl::unexpected(process_result.error()); } result.port = std::move(*process_result); @@ -263,7 +263,7 @@ tl::expected url_pattern_init::process( // result["pathname"], result["protocol"], and type. auto pathname_processing_result = process_pathname( *result.pathname, result.protocol.value_or("fake"), type); - if (!pathname_processing_result) { + if (!pathname_processing_result.has_value()) { return tl::unexpected(pathname_processing_result.error()); } result.pathname = std::move(*pathname_processing_result); @@ -273,7 +273,7 @@ tl::expected url_pattern_init::process( // search for init given init["search"] and type. if (init.search) { auto process_result = process_search(*init.search, type); - if (!process_result) { + if (!process_result.has_value()) { return tl::unexpected(process_result.error()); } result.search = std::move(*process_result); @@ -283,7 +283,7 @@ tl::expected url_pattern_init::process( // hash for init given init["hash"] and type. if (init.hash) { auto process_result = process_hash(*init.hash, type); - if (!process_result) { + if (!process_result.has_value()) { return tl::unexpected(process_result.error()); } result.hash = std::move(*process_result); @@ -489,7 +489,7 @@ url_pattern_component::compile(std::string_view input, F encoding_callback, auto part_list = url_pattern_helpers::parse_pattern_string(input, options, encoding_callback); - if (!part_list) { + if (!part_list.has_value()) { ada_log("parse_pattern_string failed"); return tl::unexpected(part_list.error()); } @@ -529,15 +529,17 @@ url_pattern_component::compile(std::string_view input, F encoding_callback, // For each part of part list: // - If part’s type is "regexp", then set has regexp groups to true. const auto has_regexp = [](const auto& part) { return part.is_regexp(); }; - const bool has_regexp_groups = std::ranges::any_of(*part_list, has_regexp); + const bool has_regexp_groups = + std::ranges::any_of(part_list.value(), has_regexp); ada_log("has regexp groups: ", has_regexp_groups); // Return a new component whose pattern string is pattern string, regular // expression is regular expression, group name list is name list, and has // regexp groups is has regexp groups. - return url_pattern_component(pattern_string, std::move(regular_expression), - flags, std::move(name_list), has_regexp_groups); + return tl::expected( + tl::in_place, std::move(pattern_string), std::move(regular_expression), + flags, std::move(name_list), has_regexp_groups); } namespace url_pattern_helpers { @@ -550,7 +552,7 @@ generate_regular_expression_and_name_list( // Let name list be a new list std::vector name_list{}; - const std::string full_wildcard_regexp_value = ".*"; + constexpr std::string_view full_wildcard_regexp_value = ".*"; // For each part of part list: for (const url_pattern_part& part : part_list) { @@ -836,7 +838,7 @@ url_pattern::match(url_pattern_input&& input, base_url = ada::parse(*base_url_string, nullptr); // If baseURL is failure, return null. - if (!base_url) { + if (!base_url.has_value()) { return std::nullopt; } @@ -852,7 +854,7 @@ url_pattern::match(url_pattern_input&& input, ada::parse(url.get_href(), base_url_value); // If url is failure, return null. - if (!parsed_url) { + if (!parsed_url.has_value()) { return std::nullopt; } diff --git a/src/url_pattern_helpers.cpp b/src/url_pattern_helpers.cpp index 602449317..751ee628c 100644 --- a/src/url_pattern_helpers.cpp +++ b/src/url_pattern_helpers.cpp @@ -20,7 +20,7 @@ constructor_string_parser::compute_protocol_matches_special_scheme_flag() { auto protocol_component = url_pattern_component::compile( protocol_string, canonicalize_protocol, url_pattern_compile_component_options::DEFAULT); - if (!protocol_component) { + if (!protocol_component.has_value()) { ada_log("url_pattern_component::compile failed for protocol_string ", protocol_string); return protocol_component.error(); @@ -273,7 +273,7 @@ constructor_string_parser::parse(std::string_view input) { // Let parser be a new constructor string parser whose input is input and // token list is the result of running tokenize given input and "lenient". auto token_list = tokenize(input, token_policy::LENIENT); - if (!token_list) { + if (!token_list.has_value()) { return tl::unexpected(token_list.error()); } auto parser = constructor_string_parser(input, std::move(*token_list)); @@ -927,7 +927,7 @@ parse_pattern_string(std::string_view input, // Set parser’s token list to the result of running tokenize given input and // "strict". auto tokenize_result = tokenize(input, token_policy::STRICT); - if (!tokenize_result) { + if (!tokenize_result.has_value()) { ada_log("parse_pattern_string tokenize failed"); return tl::unexpected(tokenize_result.error()); } diff --git a/tests/wpt_urlpattern_tests.cpp b/tests/wpt_urlpattern_tests.cpp index e234373bb..38970bda1 100644 --- a/tests/wpt_urlpattern_tests.cpp +++ b/tests/wpt_urlpattern_tests.cpp @@ -18,7 +18,7 @@ TEST(wpt_urlpattern_tests, basic_tests) { auto init = ada::url_pattern_init{}; init.pathname = "/books"; auto url = ada::parse_url_pattern(init); - ASSERT_TRUE(url); + ASSERT_TRUE(url.has_value()); ASSERT_EQ(url->get_protocol(), "*"); ASSERT_EQ(url->get_hostname(), "*"); ASSERT_EQ(url->get_username(), "*");