diff options
-rw-r--r-- | absl/base/internal/direct_mmap.h | 3 | ||||
-rw-r--r-- | absl/base/macros.h | 3 | ||||
-rw-r--r-- | absl/container/internal/raw_hash_set.h | 26 | ||||
-rw-r--r-- | absl/container/internal/raw_hash_set_test.cc | 12 | ||||
-rw-r--r-- | absl/crc/internal/crc32_x86_arm_combined_simd.h | 6 | ||||
-rw-r--r-- | absl/crc/internal/crc_memcpy.h | 7 | ||||
-rw-r--r-- | absl/crc/internal/crc_memcpy_fallback.cc | 4 | ||||
-rw-r--r-- | absl/crc/internal/crc_memcpy_x86_64.cc | 4 | ||||
-rw-r--r-- | absl/flags/internal/parse.h | 4 | ||||
-rw-r--r-- | absl/flags/parse.cc | 74 | ||||
-rw-r--r-- | absl/flags/parse_test.cc | 74 | ||||
-rw-r--r-- | absl/status/BUILD.bazel | 1 | ||||
-rw-r--r-- | absl/strings/internal/escaping.cc | 22 |
13 files changed, 202 insertions, 38 deletions
diff --git a/absl/base/internal/direct_mmap.h b/absl/base/internal/direct_mmap.h index fdf88f0b..14efc637 100644 --- a/absl/base/internal/direct_mmap.h +++ b/absl/base/internal/direct_mmap.h @@ -101,8 +101,7 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, static_cast<size_t>(offset / pagesize)); #else return reinterpret_cast<void*>( - syscall(SYS_mmap2, start, length, prot, flags, fd, - offset / pagesize)); + syscall(SYS_mmap2, start, length, prot, flags, fd, offset / pagesize)); #endif #elif defined(__s390x__) // On s390x, mmap() arguments are passed in memory. diff --git a/absl/base/macros.h b/absl/base/macros.h index bbf7494f..f33cd192 100644 --- a/absl/base/macros.h +++ b/absl/base/macros.h @@ -138,7 +138,4 @@ ABSL_NAMESPACE_END #define ABSL_INTERNAL_RETHROW do {} while (false) #endif // ABSL_HAVE_EXCEPTIONS -// TODO(b/261916195): Replace ABSL_INTERNAL_UNREACHABLE with ABSL_UNREACHABLE(). -#define ABSL_INTERNAL_UNREACHABLE ABSL_UNREACHABLE() - #endif // ABSL_BASE_MACROS_H_ diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 3762820d..0baca2a3 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -832,8 +832,8 @@ class HashSetIteratorGenerationInfoEnabled { void set_generation_ptr(const GenerationType* ptr) { generation_ptr_ = ptr; } private: - const GenerationType* generation_ptr_ = nullptr; - GenerationType generation_ = 0; + const GenerationType* generation_ptr_ = EmptyGeneration(); + GenerationType generation_ = *generation_ptr_; }; class HashSetIteratorGenerationInfoDisabled { @@ -1021,12 +1021,17 @@ size_t SelectBucketCountForIterRange(InputIter first, InputIter last, } while (0) // Note that for comparisons, null/end iterators are valid. -// TODO(b/254649633): when generations are enabled, detect cases of invalid -// iterators being compared. -inline void AssertIsValidForComparison(const ctrl_t* ctrl) { +inline void AssertIsValidForComparison(const ctrl_t* ctrl, + GenerationType generation, + const GenerationType* generation_ptr) { ABSL_HARDENING_ASSERT((ctrl == nullptr || IsFull(*ctrl)) && "Invalid iterator comparison. The element might have " "been erased or the table might have rehashed."); + if (SwisstableGenerationsEnabled() && generation != *generation_ptr) { + ABSL_INTERNAL_LOG(FATAL, + "Invalid iterator comparison. The table could have " + "rehashed since this iterator was initialized."); + } } // If the two iterators come from the same container, then their pointers will @@ -1426,8 +1431,8 @@ class raw_hash_set { friend bool operator==(const iterator& a, const iterator& b) { AssertSameContainer(a.ctrl_, b.ctrl_, a.slot_, b.slot_); - AssertIsValidForComparison(a.ctrl_); - AssertIsValidForComparison(b.ctrl_); + AssertIsValidForComparison(a.ctrl_, a.generation(), a.generation_ptr()); + AssertIsValidForComparison(b.ctrl_, b.generation(), b.generation_ptr()); return a.ctrl_ == b.ctrl_; } friend bool operator!=(const iterator& a, const iterator& b) { @@ -1444,6 +1449,9 @@ class raw_hash_set { // not equal to any end iterator. ABSL_ASSUME(ctrl != nullptr); } + // For end() iterators. + explicit iterator(const GenerationType* generation_ptr) + : HashSetIteratorGenerationInfo(generation_ptr) {} // Fixes up `ctrl_` to point to a full by advancing it and `slot_` until // they reach one. @@ -1700,12 +1708,12 @@ class raw_hash_set { it.skip_empty_or_deleted(); return it; } - iterator end() { return {}; } + iterator end() { return iterator(common().generation_ptr()); } const_iterator begin() const { return const_cast<raw_hash_set*>(this)->begin(); } - const_iterator end() const { return {}; } + const_iterator end() const { return iterator(common().generation_ptr()); } const_iterator cbegin() const { return begin(); } const_iterator cend() const { return end(); } diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index 8096567c..801b758e 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -1819,7 +1819,6 @@ TEST(Table, HeterogeneousLookupOverloads) { EXPECT_TRUE((VerifyResultOf<CallCount, TransparentTable>())); } -// TODO(alkis): Expand iterator tests. TEST(Iterator, IsDefaultConstructible) { StringTable::iterator i; EXPECT_TRUE(i == StringTable::iterator()); @@ -2249,7 +2248,8 @@ TEST(Table, AlignOne) { // Invalid iterator use can trigger heap-use-after-free in asan, // use-of-uninitialized-value in msan, or invalidated iterator assertions. constexpr const char* kInvalidIteratorDeathMessage = - "heap-use-after-free|use-of-uninitialized-value|invalidated iterator"; + "heap-use-after-free|use-of-uninitialized-value|invalidated " + "iterator|Invalid iterator"; #if defined(__clang__) && defined(_MSC_VER) constexpr bool kLexan = true; @@ -2257,7 +2257,7 @@ constexpr bool kLexan = true; constexpr bool kLexan = false; #endif -TEST(Table, InvalidIteratorUse) { +TEST(Iterator, InvalidUseCrashesWithSanitizers) { if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled."; if (kLexan) GTEST_SKIP() << "Lexan doesn't support | in regexp."; @@ -2268,10 +2268,12 @@ TEST(Table, InvalidIteratorUse) { auto it = t.begin(); t.insert(i); EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage); + EXPECT_DEATH_IF_SUPPORTED(void(it == t.begin()), + kInvalidIteratorDeathMessage); } } -TEST(Table, InvalidIteratorUseWithReserve) { +TEST(Iterator, InvalidUseWithReserveCrashesWithSanitizers) { if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled."; if (kLexan) GTEST_SKIP() << "Lexan doesn't support | in regexp."; @@ -2290,6 +2292,8 @@ TEST(Table, InvalidIteratorUseWithReserve) { // Unreserved growth can rehash. t.insert(10); EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage); + EXPECT_DEATH_IF_SUPPORTED(void(it == t.begin()), + kInvalidIteratorDeathMessage); } TEST(Table, ReservedGrowthUpdatesWhenTableDoesntGrow) { diff --git a/absl/crc/internal/crc32_x86_arm_combined_simd.h b/absl/crc/internal/crc32_x86_arm_combined_simd.h index f23cd75e..344042d8 100644 --- a/absl/crc/internal/crc32_x86_arm_combined_simd.h +++ b/absl/crc/internal/crc32_x86_arm_combined_simd.h @@ -25,8 +25,10 @@ // We define a translation layer for both x86 and ARM for the ease of use and // most performance gains. -// We need CRC (part of SSE 4.2) and PCLMULQDQ instructions. -#if defined(__SSE4_2__) && defined(__PCLMUL__) +// This implementation requires 64-bit CRC instructions (part of SSE 4.2) and +// PCLMULQDQ instructions. 32-bit builds with SSE 4.2 do exist, so the +// __x86_64__ condition is necessary. +#if defined(__x86_64__) && defined(__SSE4_2__) && defined(__PCLMUL__) #include <x86intrin.h> #define ABSL_CRC_INTERNAL_HAVE_X86_SIMD diff --git a/absl/crc/internal/crc_memcpy.h b/absl/crc/internal/crc_memcpy.h index ae9cccad..4909d433 100644 --- a/absl/crc/internal/crc_memcpy.h +++ b/absl/crc/internal/crc_memcpy.h @@ -21,6 +21,13 @@ #include "absl/base/config.h" #include "absl/crc/crc32c.h" +// Defined if the class AcceleratedCrcMemcpyEngine exists. +#if defined(__x86_64__) && defined(__SSE4_2__) +#define ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE 1 +#elif defined(_MSC_VER) && defined(__AVX__) +#define ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE 1 +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { diff --git a/absl/crc/internal/crc_memcpy_fallback.cc b/absl/crc/internal/crc_memcpy_fallback.cc index 4579c164..15b4b055 100644 --- a/absl/crc/internal/crc_memcpy_fallback.cc +++ b/absl/crc/internal/crc_memcpy_fallback.cc @@ -54,7 +54,7 @@ absl::crc32c_t FallbackCrcMemcpyEngine::Compute(void* __restrict dst, } // Compile the following only if we don't have -#ifndef __SSE4_2__ +#ifndef ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE CrcMemcpy::ArchSpecificEngines CrcMemcpy::GetArchSpecificEngines() { CrcMemcpy::ArchSpecificEngines engines; @@ -68,7 +68,7 @@ std::unique_ptr<CrcMemcpyEngine> CrcMemcpy::GetTestEngine(int /*vector*/, return std::make_unique<FallbackCrcMemcpyEngine>(); } -#endif +#endif // ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE } // namespace crc_internal ABSL_NAMESPACE_END diff --git a/absl/crc/internal/crc_memcpy_x86_64.cc b/absl/crc/internal/crc_memcpy_x86_64.cc index a148fe17..66f784de 100644 --- a/absl/crc/internal/crc_memcpy_x86_64.cc +++ b/absl/crc/internal/crc_memcpy_x86_64.cc @@ -59,7 +59,7 @@ #include "absl/crc/internal/crc_memcpy.h" #include "absl/strings/string_view.h" -#if defined(__SSE4_2__) || (defined(_MSC_VER) && defined(__AVX__)) +#ifdef ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE namespace absl { ABSL_NAMESPACE_BEGIN @@ -431,4 +431,4 @@ std::unique_ptr<CrcMemcpyEngine> CrcMemcpy::GetTestEngine(int vector, ABSL_NAMESPACE_END } // namespace absl -#endif // defined(__SSE4_2__) || (defined(_MSC_VER) && defined(__AVX__)) +#endif // ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE diff --git a/absl/flags/internal/parse.h b/absl/flags/internal/parse.h index de706c89..0a7012fc 100644 --- a/absl/flags/internal/parse.h +++ b/absl/flags/internal/parse.h @@ -52,6 +52,10 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], // command line or specified in flag file present on the original command line. bool WasPresentOnCommandLine(absl::string_view flag_name); +// Return existing flags similar to the parameter, in order to help in case of +// misspellings. +std::vector<std::string> GetMisspellingHints(absl::string_view flag); + } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc index 2851c0f7..cd61e80a 100644 --- a/absl/flags/parse.cc +++ b/absl/flags/parse.cc @@ -18,6 +18,7 @@ #include <stdlib.h> #include <algorithm> +#include <cstdint> #include <fstream> #include <iostream> #include <iterator> @@ -47,7 +48,9 @@ #include "absl/flags/usage.h" #include "absl/flags/usage_config.h" #include "absl/strings/ascii.h" +#include "absl/strings/internal/damerau_levenshtein_distance.h" #include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" #include "absl/synchronization/mutex.h" @@ -72,6 +75,11 @@ ABSL_CONST_INIT absl::Mutex specified_flags_guard(absl::kConstInit); ABSL_CONST_INIT std::vector<const CommandLineFlag*>* specified_flags ABSL_GUARDED_BY(specified_flags_guard) = nullptr; +// Suggesting at most kMaxHints flags in case of misspellings. +ABSL_CONST_INIT const size_t kMaxHints = 100; +// Suggesting only flags which have a smaller distance than kMaxDistance. +ABSL_CONST_INIT const size_t kMaxDistance = 3; + struct SpecifiedFlagsCompare { bool operator()(const CommandLineFlag* a, const CommandLineFlag* b) const { return a->Name() < b->Name(); @@ -605,6 +613,55 @@ bool WasPresentOnCommandLine(absl::string_view flag_name) { // -------------------------------------------------------------------- +struct BestHints { + explicit BestHints(uint8_t _max) : best_distance(_max + 1) {} + bool AddHint(absl::string_view hint, uint8_t distance) { + if (hints.size() >= kMaxHints) return false; + if (distance == best_distance) { + hints.emplace_back(hint); + } + if (distance < best_distance) { + best_distance = distance; + hints = std::vector<std::string>{std::string(hint)}; + } + return true; + } + + uint8_t best_distance; + std::vector<std::string> hints; +}; + +// Return the list of flags with the smallest Damerau-Levenshtein distance to +// the given flag. +std::vector<std::string> GetMisspellingHints(const absl::string_view flag) { + const size_t maxCutoff = std::min(flag.size() / 2 + 1, kMaxDistance); + auto undefok = absl::GetFlag(FLAGS_undefok); + BestHints best_hints(static_cast<uint8_t>(maxCutoff)); + absl::flags_internal::ForEachFlag([&](const CommandLineFlag& f) { + if (best_hints.hints.size() >= kMaxHints) return; + uint8_t distance = strings_internal::CappedDamerauLevenshteinDistance( + flag, f.Name(), best_hints.best_distance); + best_hints.AddHint(f.Name(), distance); + // For boolean flags, also calculate distance to the negated form. + if (f.IsOfType<bool>()) { + const std::string negated_flag = absl::StrCat("no", f.Name()); + distance = strings_internal::CappedDamerauLevenshteinDistance( + flag, negated_flag, best_hints.best_distance); + best_hints.AddHint(negated_flag, distance); + } + }); + // Finally calculate distance to flags in "undefok". + absl::c_for_each(undefok, [&](const absl::string_view f) { + if (best_hints.hints.size() >= kMaxHints) return; + uint8_t distance = strings_internal::CappedDamerauLevenshteinDistance( + flag, f, best_hints.best_distance); + best_hints.AddHint(absl::StrCat(f, " (undefok)"), distance); + }); + return best_hints.hints; +} + +// -------------------------------------------------------------------- + std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], ArgvListAction arg_list_act, UsageFlagsAction usage_flag_act, @@ -755,10 +812,19 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], for (const auto& flag_name : undefined_flag_names) { if (CanIgnoreUndefinedFlag(flag_name.second)) continue; - - flags_internal::ReportUsageError( - absl::StrCat("Unknown command line flag '", flag_name.second, "'"), - true); + // Verify if flag_name has the "no" already removed + std::vector<std::string> flags; + if (flag_name.first) flags = GetMisspellingHints(flag_name.second); + if (flags.empty()) { + flags_internal::ReportUsageError( + absl::StrCat("Unknown command line flag '", flag_name.second, "'"), + true); + } else { + flags_internal::ReportUsageError( + absl::StrCat("Unknown command line flag '", flag_name.second, + "'. Did you mean: ", absl::StrJoin(flags, ", "), " ?"), + true); + } success = false; } diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc index 8dc91db2..418b0e55 100644 --- a/absl/flags/parse_test.cc +++ b/absl/flags/parse_test.cc @@ -17,6 +17,7 @@ #include <stdlib.h> +#include <cstddef> #include <fstream> #include <string> #include <vector> @@ -39,6 +40,36 @@ #include <windows.h> #endif +// Define 125 similar flags to test kMaxHints for flag suggestions. +#define FLAG_MULT(x) F3(x) +#define TEST_FLAG_HEADER FLAG_HEADER_ + +#define F(name) ABSL_FLAG(int, name, 0, ""); + +#define F1(name) \ + F(name##1); \ + F(name##2); \ + F(name##3); \ + F(name##4); \ + F(name##5); +/**/ +#define F2(name) \ + F1(name##1); \ + F1(name##2); \ + F1(name##3); \ + F1(name##4); \ + F1(name##5); +/**/ +#define F3(name) \ + F2(name##1); \ + F2(name##2); \ + F2(name##3); \ + F2(name##4); \ + F2(name##5); +/**/ + +FLAG_MULT(TEST_FLAG_HEADER) + namespace { using absl::base_internal::ScopedSetEnv; @@ -565,6 +596,49 @@ TEST_F(ParseDeathTest, TestInvalidUDTFlagFormat) { // -------------------------------------------------------------------- +TEST_F(ParseDeathTest, TestFlagSuggestions) { + const char* in_args1[] = { + "testbin", + "--legacy_boo", + }; + EXPECT_DEATH_IF_SUPPORTED( + InvokeParse(in_args1), + "Unknown command line flag 'legacy_boo'. Did you mean: legacy_bool ?"); + + const char* in_args2[] = {"testbin", "--foo", "--undefok=foo1"}; + EXPECT_DEATH_IF_SUPPORTED( + InvokeParse(in_args2), + "Unknown command line flag 'foo'. Did you mean: foo1 \\(undefok\\)?"); + + const char* in_args3[] = { + "testbin", + "--nolegacy_ino", + }; + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args3), + "Unknown command line flag 'nolegacy_ino'. Did " + "you mean: nolegacy_bool, legacy_int ?"); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, GetHints) { + EXPECT_THAT(absl::flags_internal::GetMisspellingHints("legacy_boo"), + testing::ContainerEq(std::vector<std::string>{"legacy_bool"})); + EXPECT_THAT(absl::flags_internal::GetMisspellingHints("nolegacy_itn"), + testing::ContainerEq(std::vector<std::string>{"legacy_int"})); + EXPECT_THAT(absl::flags_internal::GetMisspellingHints("nolegacy_int1"), + testing::ContainerEq(std::vector<std::string>{"legacy_int"})); + EXPECT_THAT(absl::flags_internal::GetMisspellingHints("nolegacy_int"), + testing::ContainerEq(std::vector<std::string>{"legacy_int"})); + EXPECT_THAT(absl::flags_internal::GetMisspellingHints("nolegacy_ino"), + testing::ContainerEq( + std::vector<std::string>{"nolegacy_bool", "legacy_int"})); + EXPECT_THAT( + absl::flags_internal::GetMisspellingHints("FLAG_HEADER_000").size(), 100); +} + +// -------------------------------------------------------------------- + TEST_F(ParseTest, TestLegacyFlags) { const char* in_args1[] = { "testbin", diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel index ce0ea70c..1f58b307 100644 --- a/absl/status/BUILD.bazel +++ b/absl/status/BUILD.bazel @@ -61,6 +61,7 @@ cc_test( name = "status_test", srcs = ["status_test.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":status", "//absl/strings", diff --git a/absl/strings/internal/escaping.cc b/absl/strings/internal/escaping.cc index cfea0961..8bd0890d 100644 --- a/absl/strings/internal/escaping.cc +++ b/absl/strings/internal/escaping.cc @@ -28,19 +28,11 @@ size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) { // Base64 encodes three bytes of input at a time. If the input is not // divisible by three, we pad as appropriate. // - // (from https://tools.ietf.org/html/rfc3548) - // Special processing is performed if fewer than 24 bits are available - // at the end of the data being encoded. A full encoding quantum is - // always completed at the end of a quantity. When fewer than 24 input - // bits are available in an input group, zero bits are added (on the - // right) to form an integral number of 6-bit groups. Padding at the - // end of the data is performed using the '=' character. Since all base - // 64 input is an integral number of octets, only the following cases - // can arise: - // Base64 encodes each three bytes of input into four bytes of output. size_t len = (input_len / 3) * 4; + // Since all base 64 input is an integral number of octets, only the following + // cases can arise: if (input_len % 3 == 0) { // (from https://tools.ietf.org/html/rfc3548) // (1) the final quantum of encoding input is an integral multiple of 24 @@ -83,6 +75,16 @@ size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest, char* const limit_dest = dest + szdest; const unsigned char* const limit_src = src + szsrc; + // (from https://tools.ietf.org/html/rfc3548) + // Special processing is performed if fewer than 24 bits are available + // at the end of the data being encoded. A full encoding quantum is + // always completed at the end of a quantity. When fewer than 24 input + // bits are available in an input group, zero bits are added (on the + // right) to form an integral number of 6-bit groups. + // + // If do_padding is true, padding at the end of the data is performed. This + // output padding uses the '=' character. + // Three bytes of data encodes to four characters of cyphertext. // So we can pump through three-byte chunks atomically. if (szsrc >= 3) { // "limit_src - 3" is UB if szsrc < 3. |