Commit 6ba57378 authored by Benoît Lizé's avatar Benoît Lizé Committed by Commit Bot

blink/bindings: Fix UB in StringResource.

v8::string::ExternalStringResourceBase -> StringResource{8,16} cast is undefined
behavior, as there is now ParkableStringResource{8,16} and
StringResource{8,16}.

Add a common ancestor to these two classes, and cast to it to avoid UB.

Bug: 909796
Change-Id: I94c65e03f283ca3c9fee344743e3f607686d2846
Reviewed-on: https://chromium-review.googlesource.com/c/1355046
Commit-Queue: Benoit L <lizeb@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612250}
parent eabc228b
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/platform/bindings/string_resource.h" #include "third_party/blink/renderer/platform/bindings/string_resource.h"
#include <type_traits>
#include "third_party/blink/renderer/platform/bindings/v8_binding.h" #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
namespace blink { namespace blink {
...@@ -92,11 +94,28 @@ StringType ToBlinkString(v8::Local<v8::String> v8_string, ...@@ -92,11 +94,28 @@ StringType ToBlinkString(v8::Local<v8::String> v8_string,
v8::String::ExternalStringResourceBase* resource = v8::String::ExternalStringResourceBase* resource =
v8_string->GetExternalStringResourceBase(&encoding); v8_string->GetExternalStringResourceBase(&encoding);
if (LIKELY(!!resource)) { if (LIKELY(!!resource)) {
// Inheritance:
// - V8 side: v8::String::ExternalStringResourceBase
// -> v8::External{One,}ByteStringResource
// - Both: StringResource{8,16}Base inherits from the matching v8 class.
static_assert(std::is_base_of<v8::String::ExternalOneByteStringResource,
StringResource8Base>::value,
"");
static_assert(std::is_base_of<v8::String::ExternalStringResource,
StringResource16Base>::value,
"");
static_assert(
std::is_base_of<StringResourceBase, StringResource8Base>::value, "");
static_assert(
std::is_base_of<StringResourceBase, StringResource16Base>::value, "");
// Then StringResource{8,16}Base allows to go from one ancestry path to
// the other one. Even though it's empty, removing it causes UB, see
// crbug.com/909796.
StringResourceBase* base; StringResourceBase* base;
if (encoding == v8::String::ONE_BYTE_ENCODING) if (encoding == v8::String::ONE_BYTE_ENCODING)
base = static_cast<StringResource8*>(resource); base = static_cast<StringResource8Base*>(resource);
else else
base = static_cast<StringResource16*>(resource); base = static_cast<StringResource16Base*>(resource);
return StringTraits<StringType>::FromStringResource(base); return StringTraits<StringType>::FromStringResource(base);
} }
} }
......
...@@ -114,55 +114,53 @@ class StringResourceBase { ...@@ -114,55 +114,53 @@ class StringResourceBase {
DISALLOW_COPY_AND_ASSIGN(StringResourceBase); DISALLOW_COPY_AND_ASSIGN(StringResourceBase);
}; };
class StringResource16 final : public StringResourceBase, // Even though StringResource{8,16}Base are effectively empty in release mode,
public v8::String::ExternalStringResource { // they are needed as they serve as a common ancestor to Parkable and regular
// strings.
//
// See the comment in |ToBlinkString()|'s implementation for the rationale.
class StringResource16Base : public StringResourceBase,
public v8::String::ExternalStringResource {
public: public:
explicit StringResource16(const String& string) : StringResourceBase(string) { explicit StringResource16Base(const String& string)
: StringResourceBase(string) {
DCHECK(!string.Is8Bit()); DCHECK(!string.Is8Bit());
} }
explicit StringResource16(const AtomicString& string) explicit StringResource16Base(const AtomicString& string)
: StringResourceBase(string) { : StringResourceBase(string) {
DCHECK(!string.Is8Bit()); DCHECK(!string.Is8Bit());
} }
size_t length() const override { return plain_string_.Impl()->length(); } explicit StringResource16Base(const ParkableString& parkable_string)
const uint16_t* data() const override { : StringResourceBase(parkable_string) {
return reinterpret_cast<const uint16_t*>( DCHECK(!parkable_string.Is8Bit());
plain_string_.Impl()->Characters16());
} }
DISALLOW_COPY_AND_ASSIGN(StringResource16); DISALLOW_COPY_AND_ASSIGN(StringResource16Base);
}; };
class StringResource8 final : public StringResourceBase, class StringResource16 final : public StringResource16Base {
public v8::String::ExternalOneByteStringResource {
public: public:
explicit StringResource8(const String& string) : StringResourceBase(string) { explicit StringResource16(const String& string)
DCHECK(string.Is8Bit()); : StringResource16Base(string) {}
}
explicit StringResource8(const AtomicString& string) explicit StringResource16(const AtomicString& string)
: StringResourceBase(string) { : StringResource16Base(string) {}
DCHECK(string.Is8Bit());
}
size_t length() const override { return plain_string_.Impl()->length(); } size_t length() const override { return plain_string_.Impl()->length(); }
const char* data() const override { const uint16_t* data() const override {
return reinterpret_cast<const char*>(plain_string_.Impl()->Characters8()); return reinterpret_cast<const uint16_t*>(
plain_string_.Impl()->Characters16());
} }
DISALLOW_COPY_AND_ASSIGN(StringResource8); DISALLOW_COPY_AND_ASSIGN(StringResource16);
}; };
class ParkableStringResource16 final class ParkableStringResource16 final : public StringResource16Base {
: public StringResourceBase,
public v8::String::ExternalStringResource {
public: public:
explicit ParkableStringResource16(const ParkableString& string) explicit ParkableStringResource16(const ParkableString& string)
: StringResourceBase(string) { : StringResource16Base(string) {}
DCHECK(!parkable_string_.Is8Bit());
}
bool IsCacheable() const override { bool IsCacheable() const override {
return !parkable_string_.may_be_parked(); return !parkable_string_.may_be_parked();
...@@ -181,15 +179,48 @@ class ParkableStringResource16 final ...@@ -181,15 +179,48 @@ class ParkableStringResource16 final
DISALLOW_COPY_AND_ASSIGN(ParkableStringResource16); DISALLOW_COPY_AND_ASSIGN(ParkableStringResource16);
}; };
class ParkableStringResource8 final class StringResource8Base : public StringResourceBase,
: public StringResourceBase, public v8::String::ExternalOneByteStringResource {
public v8::String::ExternalOneByteStringResource {
public: public:
explicit ParkableStringResource8(const ParkableString& string) explicit StringResource8Base(const String& string)
: StringResourceBase(string) { : StringResourceBase(string) {
DCHECK(parkable_string_.Is8Bit()); DCHECK(string.Is8Bit());
}
explicit StringResource8Base(const AtomicString& string)
: StringResourceBase(string) {
DCHECK(string.Is8Bit());
}
explicit StringResource8Base(const ParkableString& parkable_string)
: StringResourceBase(parkable_string) {
DCHECK(parkable_string.Is8Bit());
}
DISALLOW_COPY_AND_ASSIGN(StringResource8Base);
};
class StringResource8 final : public StringResource8Base {
public:
explicit StringResource8(const String& string)
: StringResource8Base(string) {}
explicit StringResource8(const AtomicString& string)
: StringResource8Base(string) {}
size_t length() const override { return plain_string_.Impl()->length(); }
const char* data() const override {
return reinterpret_cast<const char*>(plain_string_.Impl()->Characters8());
} }
DISALLOW_COPY_AND_ASSIGN(StringResource8);
};
class ParkableStringResource8 final : public StringResource8Base {
public:
explicit ParkableStringResource8(const ParkableString& string)
: StringResource8Base(string) {}
bool IsCacheable() const override { bool IsCacheable() const override {
return !parkable_string_.may_be_parked(); return !parkable_string_.may_be_parked();
} }
......
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