Commit 9c5a434b authored by Clemens Backes's avatar Clemens Backes Committed by V8 LUCI CQ

[wasm][fuzzer] Simplify boolean decisions

The wasm-compile fuzzer sometimes needs to generate a boolean flag from
the input bytes. Since the general {DataRange::get} method results in
undefined behaviour if instantiated with the {bool} type, we are getting
an 8-bit value instead and looking at the least significant bit only.
This CL improves this situation by implementing a template
specialization for {bool} which uses the same trick, and uses that
instead of hand-coding the modulo operation at the call sites.

R=manoskouk@chromium.org

Bug: v8:11879
Change-Id: I6f9ce02dd8d9cd0998b83e081e4c6ca773e6cb53
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3129429Reviewed-by: 's avatarManos Koukoutos <manoskouk@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76588}
parent db164965
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <algorithm> #include <algorithm>
#include "src/base/macros.h"
#include "src/execution/isolate.h" #include "src/execution/isolate.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
#include "src/objects/objects.h" #include "src/objects/objects.h"
...@@ -69,13 +70,8 @@ class DataRange { ...@@ -69,13 +70,8 @@ class DataRange {
template <typename T, size_t max_bytes = sizeof(T)> template <typename T, size_t max_bytes = sizeof(T)>
T get() { T get() {
// DISABLE FOR BOOL // Bool needs special handling (see template specialization below).
// The -O3 on release will break the result. This creates a different static_assert(!std::is_same<T, bool>::value, "bool needs special handling");
// observable side effect when invoking get<bool> between debug and release
// version, which eventually makes the code output different as well as
// raising various unrecoverable errors on runtime. It is caused by
// undefined behavior of assigning boolean via memcpy from randomized bytes.
STATIC_ASSERT(!(std::is_same<T, bool>::value));
STATIC_ASSERT(max_bytes <= sizeof(T)); STATIC_ASSERT(max_bytes <= sizeof(T));
// We want to support the case where we have less than sizeof(T) bytes // We want to support the case where we have less than sizeof(T) bytes
// remaining in the slice. For example, if we emit an i32 constant, it's // remaining in the slice. For example, if we emit an i32 constant, it's
...@@ -88,6 +84,19 @@ class DataRange { ...@@ -88,6 +84,19 @@ class DataRange {
data_ += num_bytes; data_ += num_bytes;
return result; return result;
} }
template <>
bool get() {
// The general implementation above is not instantiable for bool, as that
// would cause undefinied behaviour when memcpy'ing random bytes to the
// bool. This can result in different observable side effects when invoking
// get<bool> between debug and release version, which eventually makes the
// code output different as well as raising various unrecoverable errors on
// runtime.
// Hence we specialize get<bool> to consume a full byte and use the least
// significant bit only (0 == false, 1 == true).
return get<uint8_t>() % 2;
}
}; };
ValueType GetValueType(uint32_t num_types, DataRange* data, ValueType GetValueType(uint32_t num_types, DataRange* data,
...@@ -213,11 +222,10 @@ class WasmGenerator { ...@@ -213,11 +222,10 @@ class WasmGenerator {
} }
void try_block_helper(ValueType return_type, DataRange* data) { void try_block_helper(ValueType return_type, DataRange* data) {
bool has_catch_all = data->get<uint8_t>() % 2; bool has_catch_all = data->get<bool>();
uint8_t num_catch = uint8_t num_catch =
data->get<uint8_t>() % (builder_->builder()->NumExceptions() + 1); data->get<uint8_t>() % (builder_->builder()->NumExceptions() + 1);
bool is_delegate = bool is_delegate = num_catch == 0 && !has_catch_all && data->get<bool>();
num_catch == 0 && !has_catch_all && data->get<uint8_t>() % 2 == 0;
// Allow one more target than there are enclosing try blocks, for delegating // Allow one more target than there are enclosing try blocks, for delegating
// to the caller. // to the caller.
uint8_t delegate_target = data->get<uint8_t>() % (try_blocks_.size() + 1); uint8_t delegate_target = data->get<uint8_t>() % (try_blocks_.size() + 1);
...@@ -737,7 +745,7 @@ class WasmGenerator { ...@@ -737,7 +745,7 @@ class WasmGenerator {
void set_global(DataRange* data) { global_op<kVoid>(data); } void set_global(DataRange* data) { global_op<kVoid>(data); }
void throw_or_rethrow(DataRange* data) { void throw_or_rethrow(DataRange* data) {
bool rethrow = data->get<uint8_t>() % 2; bool rethrow = data->get<bool>();
if (rethrow && !catch_blocks_.empty()) { if (rethrow && !catch_blocks_.empty()) {
int control_depth = static_cast<int>(blocks_.size() - 1); int control_depth = static_cast<int>(blocks_.size() - 1);
int catch_index = int catch_index =
...@@ -782,7 +790,7 @@ class WasmGenerator { ...@@ -782,7 +790,7 @@ class WasmGenerator {
} }
void new_object(HeapType type, DataRange* data) { void new_object(HeapType type, DataRange* data) {
if (liftoff_as_reference_ && type.is_index()) { if (liftoff_as_reference_ && type.is_index()) {
bool new_default = data->get<uint8_t>() % 2; bool new_default = data->get<bool>();
uint32_t index = type.ref_index(); uint32_t index = type.ref_index();
if (builder_->builder()->IsStructType(index)) { if (builder_->builder()->IsStructType(index)) {
if (new_default) { if (new_default) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment