Commit cc09f7ff authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

Avoid UB in FixedSizeSignature

The initial implementation of {FixedSizeSignature} contains undefined
behaviour, because {InitReps} wrote to the {reps_} array before the
constructor of that array has been called.
This also resulted in bugs if {FixedSizeSignature} was used with types
that actually have a constructor (like {ValueType}). The array
constructor would call the default constructor on each contained
element, thus overwriting the values written by {InitReps}.

This CL fixes that by switching to a plain array, and only writing to
the array in the body of the constructor (after the field was properly
initialized).

It also removes the {Concat} method in favor or simply copying from two
input arrays in a private constructor.

Drive-by: Use proper constant names for the template parameters to
make cpplint happy.

R=ahaas@chromium.org

Bug: v8:11384
Change-Id: Id748c8fef3c846069f91843f74d0555ed8ca9fb7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2773799Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73540}
parent 1ffd5c22
......@@ -124,42 +124,42 @@ size_t hash_value(const Signature<T>& sig) {
return hash;
}
template <typename T, size_t num_returns = 0, size_t num_params = 0>
template <typename T, size_t kNumReturns = 0, size_t kNumParams = 0>
class FixedSizeSignature : public Signature<T> {
public:
explicit FixedSizeSignature(std::array<T, num_returns + num_params> reps)
: Signature<T>(num_returns, num_params, InitReps(reps)) {}
explicit FixedSizeSignature(std::array<T, kNumReturns + kNumParams> reps)
: Signature<T>(kNumReturns, kNumParams, reps_) {
std::copy(reps.begin(), reps.end(), reps_);
}
// Add return types to this signature (only allowed if there are none yet).
template <typename... ReturnTypes>
auto Returns(ReturnTypes... return_types) const {
static_assert(num_returns == 0, "Please specify all return types at once");
return FixedSizeSignature<T, sizeof...(ReturnTypes), num_params>{Concat(
std::array<T, sizeof...(ReturnTypes)>{{return_types...}}, reps_)};
static_assert(kNumReturns == 0, "Please specify all return types at once");
return FixedSizeSignature<T, sizeof...(ReturnTypes), kNumParams>{
std::initializer_list<T>{return_types...}.begin(), reps_};
}
// Add parameters to this signature (only allowed if there are none yet).
template <typename... ParamTypes>
auto Params(ParamTypes... param_types) const {
static_assert(num_params == 0, "Please specify all parameters at once");
return FixedSizeSignature<T, num_returns, sizeof...(ParamTypes)>{
Concat(reps_, std::array<T, sizeof...(ParamTypes)>{{param_types...}})};
static_assert(kNumParams == 0, "Please specify all parameters at once");
return FixedSizeSignature<T, kNumReturns, sizeof...(ParamTypes)>{
reps_, std::initializer_list<T>{param_types...}.begin()};
}
private:
T* InitReps(const std::array<T, num_returns + num_params>& reps) {
reps_ = reps;
return reps_.data();
}
template <size_t sizeA, size_t sizeB>
static std::array<T, sizeA + sizeB> Concat(const std::array<T, sizeA>& a,
const std::array<T, sizeB>& b) {
return base::make_array<sizeA + sizeB>(
[&a, &b](std::size_t i) { return i < sizeA ? a[i] : b[i - sizeA]; });
// Other template instantiations can call the private constructor.
template <typename T2, size_t kNumReturns2, size_t kNumParams2>
friend class FixedSizeSignature;
FixedSizeSignature(const T* returns, const T* params)
: Signature<T>(kNumReturns, kNumParams, reps_) {
std::copy(returns, returns + kNumReturns, reps_);
std::copy(params, params + kNumParams, reps_ + kNumReturns);
}
std::array<T, num_returns + num_params> reps_;
T reps_[kNumReturns + kNumParams];
};
} // namespace internal
......
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