Commit 2ce7841f authored by tkent's avatar tkent Committed by Commit bot

Avoid unchecked casts in UA shadow DOM.

If we have a way to leak UA shadow DOM to web authors or Chrome extension authors,
these unchecked casts would be dangerous.
This CL introduces toFooTypeOrDie() helpers, and apply it to UA shadow DOM.

BUG=668970

Review-Url: https://codereview.chromium.org/2534873004
Cr-Commit-Position: refs/heads/master@{#434899}
parent e7e2d51b
......@@ -48,6 +48,7 @@ inline bool isElementOfType<const {{tag.interface}}>(const {{namespace}}Element&
{% for tag in tags|sort if not tag.multipleTagNames and not tag.noTypeHelpers %}
#define to{{tag.interface}}(x) blink::toElement<blink::{{tag.interface}}>(x)
#define to{{tag.interface}}OrDie(x) blink::toElementOrDie<blink::{{tag.interface}}>(x)
{% endfor %}
{% if namespace == "HTML" %}
......
......@@ -961,6 +961,27 @@ inline const T* toElement(const Node* node) {
return static_cast<const T*>(node);
}
template <typename T>
inline T& toElementOrDie(Node& node) {
CHECK(isElementOfType<const T>(node));
return static_cast<T&>(node);
}
template <typename T>
inline T* toElementOrDie(Node* node) {
CHECK(!node || isElementOfType<const T>(*node));
return static_cast<T*>(node);
}
template <typename T>
inline const T& toElementOrDie(const Node& node) {
CHECK(isElementOfType<const T>(node));
return static_cast<const T&>(node);
}
template <typename T>
inline const T* toElementOrDie(const Node* node) {
CHECK(!node || isElementOfType<const T>(*node));
return static_cast<const T*>(node);
}
inline bool isDisabledFormControl(const Node* node) {
return node->isElementNode() && toElement(node)->isDisabledFormControl();
}
......
......@@ -112,9 +112,9 @@ Element* HTMLDetailsElement::findMainSummary() const {
return summary;
HTMLContentElement* content =
toHTMLContentElement(userAgentShadowRoot()->firstChild());
toHTMLContentElementOrDie(userAgentShadowRoot()->firstChild());
DCHECK(content->firstChild());
DCHECK(isHTMLSummaryElement(*content->firstChild()));
CHECK(isHTMLSummaryElement(*content->firstChild()));
return toElement(content->firstChild());
}
......
......@@ -127,7 +127,7 @@ void HTMLKeygenElement::resetImpl() {
HTMLSelectElement* HTMLKeygenElement::shadowSelect() const {
ShadowRoot* root = userAgentShadowRoot();
return root ? toHTMLSelectElement(root->firstChild()) : 0;
return root ? toHTMLSelectElementOrDie(root->firstChild()) : nullptr;
}
bool HTMLKeygenElement::isInteractiveContent() const {
......
......@@ -181,7 +181,7 @@ void HTMLOptGroupElement::updateGroupLabel() {
}
HTMLDivElement& HTMLOptGroupElement::optGroupLabelElement() const {
return *toHTMLDivElement(userAgentShadowRoot()->getElementById(
return *toHTMLDivElementOrDie(userAgentShadowRoot()->getElementById(
ShadowElementNames::optGroupLabel()));
}
......
......@@ -163,7 +163,7 @@ bool TextControlElement::placeholderShouldBeVisible() const {
}
HTMLElement* TextControlElement::placeholderElement() const {
return toHTMLElement(
return toHTMLElementOrDie(
userAgentShadowRoot()->getElementById(ShadowElementNames::placeholder()));
}
......@@ -900,7 +900,7 @@ String TextControlElement::directionForFormData() const {
}
HTMLElement* TextControlElement::innerEditorElement() const {
return toHTMLElement(
return toHTMLElementOrDie(
userAgentShadowRoot()->getElementById(ShadowElementNames::innerEditor()));
}
......
......@@ -62,7 +62,7 @@ void BaseButtonInputType::createShadowSubtree() {
}
void BaseButtonInputType::valueAttributeChanged() {
toText(element().userAgentShadowRoot()->firstChild())
toTextOrDie(element().userAgentShadowRoot()->firstChild())
->setData(displayValue());
}
......
......@@ -218,7 +218,8 @@ void ColorInputType::updateView() {
HTMLElement* ColorInputType::shadowColorSwatch() const {
ShadowRoot* shadow = element().userAgentShadowRoot();
return shadow ? toHTMLElement(shadow->firstChild()->firstChild()) : 0;
return shadow ? toHTMLElementOrDie(shadow->firstChild()->firstChild())
: nullptr;
}
Element& ColorInputType::ownerElement() const {
......
......@@ -274,7 +274,7 @@ void FileInputType::createShadowSubtree() {
void FileInputType::disabledAttributeChanged() {
DCHECK(element().shadow());
if (Element* button =
toElement(element().userAgentShadowRoot()->firstChild()))
toElementOrDie(element().userAgentShadowRoot()->firstChild()))
button->setBooleanAttribute(disabledAttr,
element().isDisabledFormControl());
}
......@@ -282,7 +282,7 @@ void FileInputType::disabledAttributeChanged() {
void FileInputType::multipleAttributeChanged() {
DCHECK(element().shadow());
if (Element* button =
toElement(element().userAgentShadowRoot()->firstChild()))
toElementOrDie(element().userAgentShadowRoot()->firstChild()))
button->setAttribute(
valueAttr,
AtomicString(locale().queryString(
......
......@@ -133,25 +133,28 @@ bool DateTimeFormatValidator::validateFormat(
DateTimeEditElement* MultipleFieldsTemporalInputTypeView::dateTimeEditElement()
const {
return toDateTimeEditElement(element().userAgentShadowRoot()->getElementById(
ShadowElementNames::dateTimeEdit()));
return toDateTimeEditElementOrDie(
element().userAgentShadowRoot()->getElementById(
ShadowElementNames::dateTimeEdit()));
}
SpinButtonElement* MultipleFieldsTemporalInputTypeView::spinButtonElement()
const {
return toSpinButtonElement(element().userAgentShadowRoot()->getElementById(
ShadowElementNames::spinButton()));
return toSpinButtonElementOrDie(
element().userAgentShadowRoot()->getElementById(
ShadowElementNames::spinButton()));
}
ClearButtonElement* MultipleFieldsTemporalInputTypeView::clearButtonElement()
const {
return toClearButtonElement(element().userAgentShadowRoot()->getElementById(
ShadowElementNames::clearButton()));
return toClearButtonElementOrDie(
element().userAgentShadowRoot()->getElementById(
ShadowElementNames::clearButton()));
}
PickerIndicatorElement*
MultipleFieldsTemporalInputTypeView::pickerIndicatorElement() const {
return toPickerIndicatorElement(
return toPickerIndicatorElementOrDie(
element().userAgentShadowRoot()->getElementById(
ShadowElementNames::pickerIndicator()));
}
......
......@@ -322,8 +322,9 @@ bool RangeInputType::shouldRespectListAttribute() {
}
inline SliderThumbElement* RangeInputType::sliderThumbElement() const {
return toSliderThumbElement(element().userAgentShadowRoot()->getElementById(
ShadowElementNames::sliderThumb()));
return toSliderThumbElementOrDie(
element().userAgentShadowRoot()->getElementById(
ShadowElementNames::sliderThumb()));
}
inline Element* RangeInputType::sliderTrackElement() const {
......
......@@ -125,8 +125,9 @@ InputType::ValueMode TextFieldInputType::valueMode() const {
}
SpinButtonElement* TextFieldInputType::spinButtonElement() const {
return toSpinButtonElement(element().userAgentShadowRoot()->getElementById(
ShadowElementNames::spinButton()));
return toSpinButtonElementOrDie(
element().userAgentShadowRoot()->getElementById(
ShadowElementNames::spinButton()));
}
bool TextFieldInputType::shouldShowFocusRingOnMouseFocus() const {
......
......@@ -524,7 +524,7 @@ DEFINE_TRACE(DateTimeEditElement) {
inline Element* DateTimeEditElement::fieldsWrapperElement() const {
DCHECK(firstChild());
return toElement(firstChild());
return toElementOrDie(firstChild());
}
void DateTimeEditElement::addField(DateTimeFieldElement* field) {
......
......@@ -451,7 +451,8 @@ void SVGUseElement::buildShadowAndInstanceTree(SVGElement& target) {
// If the instance root was a <use>, it could have been replaced now, so
// reset |m_targetElementInstance|.
m_targetElementInstance = toSVGElement(shadowTreeRootElement->firstChild());
m_targetElementInstance =
toSVGElementOrDie(shadowTreeRootElement->firstChild());
ASSERT(m_targetElementInstance->parentNode() == shadowTreeRootElement);
// Update relative length information.
......
......@@ -270,26 +270,52 @@ class WTF_EXPORT ScopedLogger {
}
// DEFINE_TYPE_CASTS
// Provide static_cast<> wrappers with SECURITY_DCHECK for bad casts.
#define DEFINE_TYPE_CASTS(thisType, argumentType, argumentName, \
pointerPredicate, referencePredicate) \
inline thisType* to##thisType(argumentType* argumentName) { \
SECURITY_DCHECK(!argumentName || (pointerPredicate)); \
return static_cast<thisType*>(argumentName); \
} \
inline const thisType* to##thisType(const argumentType* argumentName) { \
SECURITY_DCHECK(!argumentName || (pointerPredicate)); \
return static_cast<const thisType*>(argumentName); \
} \
inline thisType& to##thisType(argumentType& argumentName) { \
SECURITY_DCHECK(referencePredicate); \
return static_cast<thisType&>(argumentName); \
} \
inline const thisType& to##thisType(const argumentType& argumentName) { \
SECURITY_DCHECK(referencePredicate); \
return static_cast<const thisType&>(argumentName); \
} \
void to##thisType(const thisType*); \
void to##thisType(const thisType&)
//
// toType() functions are static_cast<> wrappers with SECURITY_DCHECK. It's
// helpful to find bad casts.
//
// toTypeOrDie() has a runtime type check, and it crashes if the specified
// object is not an instance of the destination type. It is used if
// * it's hard to prevent from passing unexpected objects,
// * proceeding with the following code doesn't make sense, and
// * cost of runtime type check is acceptable.
#define DEFINE_TYPE_CASTS(thisType, argumentType, argument, pointerPredicate, \
referencePredicate) \
inline thisType* to##thisType(argumentType* argument) { \
SECURITY_DCHECK(!argument || (pointerPredicate)); \
return static_cast<thisType*>(argument); \
} \
inline const thisType* to##thisType(const argumentType* argument) { \
SECURITY_DCHECK(!argument || (pointerPredicate)); \
return static_cast<const thisType*>(argument); \
} \
inline thisType& to##thisType(argumentType& argument) { \
SECURITY_DCHECK(referencePredicate); \
return static_cast<thisType&>(argument); \
} \
inline const thisType& to##thisType(const argumentType& argument) { \
SECURITY_DCHECK(referencePredicate); \
return static_cast<const thisType&>(argument); \
} \
void to##thisType(const thisType*); \
void to##thisType(const thisType&); \
inline thisType* to##thisType##OrDie(argumentType* argument) { \
CHECK(!argument || (pointerPredicate)); \
return static_cast<thisType*>(argument); \
} \
inline const thisType* to##thisType##OrDie(const argumentType* argument) { \
CHECK(!argument || (pointerPredicate)); \
return static_cast<const thisType*>(argument); \
} \
inline thisType& to##thisType##OrDie(argumentType& argument) { \
CHECK(referencePredicate); \
return static_cast<thisType&>(argument); \
} \
inline const thisType& to##thisType##OrDie(const argumentType& argument) { \
CHECK(referencePredicate); \
return static_cast<const thisType&>(argument); \
} \
void to##thisType##OrDie(const thisType*); \
void to##thisType##OrDie(const thisType&)
#endif // WTF_Assertions_h
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