aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--absl/base/internal/direct_mmap.h3
-rw-r--r--absl/base/macros.h3
-rw-r--r--absl/container/internal/raw_hash_set.h26
-rw-r--r--absl/container/internal/raw_hash_set_test.cc12
-rw-r--r--absl/crc/internal/crc32_x86_arm_combined_simd.h6
-rw-r--r--absl/crc/internal/crc_memcpy.h7
-rw-r--r--absl/crc/internal/crc_memcpy_fallback.cc4
-rw-r--r--absl/crc/internal/crc_memcpy_x86_64.cc4
-rw-r--r--absl/flags/internal/parse.h4
-rw-r--r--absl/flags/parse.cc74
-rw-r--r--absl/flags/parse_test.cc74
-rw-r--r--absl/status/BUILD.bazel1
-rw-r--r--absl/strings/internal/escaping.cc22
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.