Remove endian-sensitivity from Abseil's RNG
authorBenjamin Barenblat <bbaren@google.com>
Tue, 9 Feb 2021 19:41:06 +0000 (19:41 +0000)
committerBenjamin Barenblat <bbaren@debian.org>
Tue, 9 Feb 2021 19:41:06 +0000 (19:41 +0000)
Forwarded: yes
Applied-Upstream: https://github.com/abseil/abseil-cpp/commit/c36d825d9a5443f81d2656685ae021d6326da90c

Ensure that the Abseil random number generator produces identical output
on both big- and little-endian platforms by byte-swapping appropriately
on big-endian systems.

The author works at Google. Upstream applied this patch as Piper
revision 355635051 and exported it to GitHub; the Applied-Upstream URL
above points to the exported commit.

Gbp-Pq: Name endian-random.diff

absl/base/BUILD.bazel
absl/base/CMakeLists.txt
absl/base/internal/endian.h
absl/random/CMakeLists.txt
absl/random/internal/BUILD.bazel
absl/random/internal/explicit_seed_seq.h
absl/random/internal/randen_engine.h
absl/random/internal/randen_slow_test.cc

index 9d96abeb33ae56b3e1f08440e8aef2c89cf7dbf9..dd1633b85369c7878fc3d6089af84a44f656a727 100644 (file)
@@ -479,6 +479,7 @@ cc_library(
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":base",
         ":config",
         ":core_headers",
     ],
index 9ff5aa243ca115fd2fd42fae7883e389390cb358..cd8b604c9cea1091bcc0ec8b3c377e286596f409 100644 (file)
@@ -418,6 +418,7 @@ absl_cc_library(
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::base
     absl::config
     absl::core_headers
   PUBLIC
index 9677530e8de320bf3f8d00e9bd0e1567996a2377..dad0e9aeb0d64e0465fe49dc761bed7d86d26d16 100644 (file)
@@ -26,6 +26,7 @@
 #endif
 
 #include <cstdint>
+#include "absl/base/casts.h"
 #include "absl/base/config.h"
 #include "absl/base/internal/unaligned_access.h"
 #include "absl/base/port.h"
@@ -173,6 +174,36 @@ inline constexpr bool IsLittleEndian() { return false; }
 
 #endif /* ENDIAN */
 
+inline uint8_t FromHost(uint8_t x) { return x; }
+inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
+inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
+inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
+inline uint8_t ToHost(uint8_t x) { return x; }
+inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
+inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
+inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
+
+inline int8_t FromHost(int8_t x) { return x; }
+inline int16_t FromHost(int16_t x) {
+  return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t FromHost(int32_t x) {
+  return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t FromHost(int64_t x) {
+  return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
+}
+inline int8_t ToHost(int8_t x) { return x; }
+inline int16_t ToHost(int16_t x) {
+  return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t ToHost(int32_t x) {
+  return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t ToHost(int64_t x) {
+  return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
+}
+
 // Functions to do unaligned loads and stores in little-endian order.
 inline uint16_t Load16(const void *p) {
   return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
@@ -233,6 +264,36 @@ inline constexpr bool IsLittleEndian() { return false; }
 
 #endif /* ENDIAN */
 
+inline uint8_t FromHost(uint8_t x) { return x; }
+inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
+inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
+inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
+inline uint8_t ToHost(uint8_t x) { return x; }
+inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
+inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
+inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
+
+inline int8_t FromHost(int8_t x) { return x; }
+inline int16_t FromHost(int16_t x) {
+  return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t FromHost(int32_t x) {
+  return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t FromHost(int64_t x) {
+  return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
+}
+inline int8_t ToHost(int8_t x) { return x; }
+inline int16_t ToHost(int16_t x) {
+  return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t ToHost(int32_t x) {
+  return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t ToHost(int64_t x) {
+  return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
+}
+
 // Functions to do unaligned loads and stores in big-endian order.
 inline uint16_t Load16(const void *p) {
   return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
index 7d7bec83d994bac1745291c83d15b72c6b9d113b..13093d6d46ad7665622c34d3a56761a818a9bd75 100644 (file)
@@ -611,6 +611,7 @@ absl_cc_library(
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::config
+    absl::endian
   TESTONLY
 )
 
@@ -758,6 +759,7 @@ absl_cc_library(
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::endian
     absl::random_internal_iostream_state_saver
     absl::random_internal_randen
     absl::raw_logging_internal
@@ -1119,6 +1121,7 @@ absl_cc_test(
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::endian
     absl::random_internal_randen_slow
     gtest_main
 )
index 8485e28b010bdd760230f9028d3db742e51a13e8..153797837684664d4290252ab184ada77c53ec50 100644 (file)
@@ -124,7 +124,10 @@ cc_library(
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = ["//absl/base:config"],
+    deps = [
+        "//absl/base:config",
+        "//absl/base:endian",
+    ],
 )
 
 cc_library(
@@ -241,6 +244,7 @@ cc_library(
     deps = [
         ":iostream_state_saver",
         ":randen",
+        "//absl/base:endian",
         "//absl/meta:type_traits",
     ],
 )
@@ -606,6 +610,7 @@ cc_test(
         ":platform",
         ":randen_slow",
         "@com_google_googletest//:gtest_main",
+        "//absl/base:endian",
     ],
 )
 
index 6a743eaf46cc224a20aec7b39a5c6912f368b940..e3aa31a184a1ff195daab3ed538bf34517a7d853 100644 (file)
@@ -23,6 +23,7 @@
 #include <vector>
 
 #include "absl/base/config.h"
+#include "absl/base/internal/endian.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -73,7 +74,7 @@ class ExplicitSeedSeq {
   template <typename OutIterator>
   void generate(OutIterator begin, OutIterator end) {
     for (size_t index = 0; begin != end; begin++) {
-      *begin = state_.empty() ? 0 : state_[index++];
+      *begin = state_.empty() ? 0 : little_endian::FromHost32(state_[index++]);
       if (index >= state_.size()) {
         index = 0;
       }
index 6b33731336e788f84f29f09d36317c64c2e32eb1..92bb8905f738a03a2e7087c1f8625fedb7a81a1f 100644 (file)
@@ -23,6 +23,7 @@
 #include <limits>
 #include <type_traits>
 
+#include "absl/base/internal/endian.h"
 #include "absl/meta/type_traits.h"
 #include "absl/random/internal/iostream_state_saver.h"
 #include "absl/random/internal/randen.h"
@@ -76,7 +77,7 @@ class alignas(16) randen_engine {
       impl_.Generate(state_);
     }
 
-    return state_[next_++];
+    return little_endian::ToHost(state_[next_++]);
   }
 
   template <class SeedSequence>
@@ -181,7 +182,8 @@ class alignas(16) randen_engine {
       // In the case that `elem` is `uint8_t`, it must be cast to something
       // larger so that it prints as an integer rather than a character. For
       // simplicity, apply the cast all circumstances.
-      os << static_cast<numeric_type>(elem) << os.fill();
+      os << static_cast<numeric_type>(little_endian::FromHost(elem))
+         << os.fill();
     }
     os << engine.next_;
     return os;
@@ -200,7 +202,7 @@ class alignas(16) randen_engine {
       // necessary to read a wider type and then cast it to uint8_t.
       numeric_type value;
       is >> value;
-      elem = static_cast<result_type>(value);
+      elem = little_endian::ToHost(static_cast<result_type>(value));
     }
     is >> next;
     if (is.fail()) {
index 4a535837058606f7e2ce517e5d4443fa5b5996f6..4861ffa4f180db50f477f6c677cd744f65348faa 100644 (file)
@@ -17,6 +17,7 @@
 #include <cstring>
 
 #include "gtest/gtest.h"
+#include "absl/base/internal/endian.h"
 #include "absl/random/internal/randen_traits.h"
 
 namespace {
@@ -56,7 +57,7 @@ TEST(RandenSlowTest, Default) {
 
   uint64_t* id = d.state;
   for (const auto& elem : kGolden) {
-    EXPECT_EQ(elem, *id++);
+    EXPECT_EQ(absl::little_endian::FromHost64(elem), *id++);
   }
 }