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) { ...@@ -124,42 +124,42 @@ size_t hash_value(const Signature<T>& sig) {
return hash; 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> { class FixedSizeSignature : public Signature<T> {
public: public:
explicit FixedSizeSignature(std::array<T, num_returns + num_params> reps) explicit FixedSizeSignature(std::array<T, kNumReturns + kNumParams> reps)
: Signature<T>(num_returns, num_params, InitReps(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). // Add return types to this signature (only allowed if there are none yet).
template <typename... ReturnTypes> template <typename... ReturnTypes>
auto Returns(ReturnTypes... return_types) const { auto Returns(ReturnTypes... return_types) const {
static_assert(num_returns == 0, "Please specify all return types at once"); static_assert(kNumReturns == 0, "Please specify all return types at once");
return FixedSizeSignature<T, sizeof...(ReturnTypes), num_params>{Concat( return FixedSizeSignature<T, sizeof...(ReturnTypes), kNumParams>{
std::array<T, sizeof...(ReturnTypes)>{{return_types...}}, reps_)}; std::initializer_list<T>{return_types...}.begin(), reps_};
} }
// Add parameters to this signature (only allowed if there are none yet). // Add parameters to this signature (only allowed if there are none yet).
template <typename... ParamTypes> template <typename... ParamTypes>
auto Params(ParamTypes... param_types) const { auto Params(ParamTypes... param_types) const {
static_assert(num_params == 0, "Please specify all parameters at once"); static_assert(kNumParams == 0, "Please specify all parameters at once");
return FixedSizeSignature<T, num_returns, sizeof...(ParamTypes)>{ return FixedSizeSignature<T, kNumReturns, sizeof...(ParamTypes)>{
Concat(reps_, std::array<T, sizeof...(ParamTypes)>{{param_types...}})}; reps_, std::initializer_list<T>{param_types...}.begin()};
} }
private: private:
T* InitReps(const std::array<T, num_returns + num_params>& reps) { // Other template instantiations can call the private constructor.
reps_ = reps; template <typename T2, size_t kNumReturns2, size_t kNumParams2>
return reps_.data(); friend class FixedSizeSignature;
}
FixedSizeSignature(const T* returns, const T* params)
template <size_t sizeA, size_t sizeB> : Signature<T>(kNumReturns, kNumParams, reps_) {
static std::array<T, sizeA + sizeB> Concat(const std::array<T, sizeA>& a, std::copy(returns, returns + kNumReturns, reps_);
const std::array<T, sizeB>& b) { std::copy(params, params + kNumParams, reps_ + kNumReturns);
return base::make_array<sizeA + sizeB>(
[&a, &b](std::size_t i) { return i < sizeA ? a[i] : b[i - sizeA]; });
} }
std::array<T, num_returns + num_params> reps_; T reps_[kNumReturns + kNumParams];
}; };
} // namespace internal } // 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