diff options
author | Johannes Hofmann <Johannes.Hofmann@gmx.de> | 2014-03-05 21:48:42 +0100 |
---|---|---|
committer | Johannes Hofmann <Johannes.Hofmann@gmx.de> | 2014-03-05 21:48:42 +0100 |
commit | 4ef5572a6256155b6213987f71f4d836cb891ffe (patch) | |
tree | d44acbc088d4d97421a5798b5184b0d2f144baf4 | |
parent | 0b04276e8e917bad961e1178a959483a7aeb5620 (diff) |
use a singe matchCache per CssContext
This fixes a crash with the following HTML:
<head>
<style type="text/css">
.first .second .third{
border-top-color:#aaa !important;
}
#n .a, .b{
color: #aaa !important;
border:#bbb;
}
</style>
</head>
<body>
<div id="submit" value="Submit" class="a">
jhu
</div>
</body>
The problem is that CssSelectors can be shared between normal and
!important rules. The matchCacheOffset was overwritten in that case
causing the crash on access.
noticed-by and test-case-by: corvid
-rw-r--r-- | src/css.cc | 37 | ||||
-rw-r--r-- | src/css.hh | 20 |
2 files changed, 31 insertions, 26 deletions
@@ -399,9 +399,9 @@ void CssStyleSheet::addRule (CssRule *rule) { } if (ruleList) { - rule->selector->setMatchCacheOffset (matchCacheOffset); - matchCacheOffset += rule->selector->size (); ruleList->insert (rule); + if (rule->selector->getRequiredMatchCache () > requiredMatchCache) + requiredMatchCache = rule->selector->getRequiredMatchCache (); } else { assert (top->getElement () == CssSimpleSelector::ELEMENT_NONE); delete rule; @@ -488,7 +488,7 @@ CssStyleSheet CssContext::userAgentSheet; CssContext::CssContext () { pos = 0; - matchCache[CSS_PRIMARY_USER_AGENT].setSize (userAgentSheet.matchCacheOffset, -1); + matchCache.setSize (userAgentSheet.getRequiredMatchCache (), -1); } /** @@ -505,28 +505,25 @@ void CssContext::apply (CssPropertyList *props, Doctree *docTree, CssPropertyList *tagStyle, CssPropertyList *tagStyleImportant, CssPropertyList *nonCssHints) { - userAgentSheet.apply (props, docTree, node, - &matchCache[CSS_PRIMARY_USER_AGENT]); - sheet[CSS_PRIMARY_USER].apply (props, docTree, node, - &matchCache[CSS_PRIMARY_USER]); + userAgentSheet.apply (props, docTree, node, &matchCache); + + sheet[CSS_PRIMARY_USER].apply (props, docTree, node, &matchCache); if (nonCssHints) nonCssHints->apply (props); - sheet[CSS_PRIMARY_AUTHOR].apply (props, docTree, node, - &matchCache[CSS_PRIMARY_AUTHOR]); + sheet[CSS_PRIMARY_AUTHOR].apply (props, docTree, node, &matchCache); if (tagStyle) tagStyle->apply (props); sheet[CSS_PRIMARY_AUTHOR_IMPORTANT].apply (props, docTree, node, - &matchCache[CSS_PRIMARY_AUTHOR_IMPORTANT]); + &matchCache); if (tagStyleImportant) tagStyleImportant->apply (props); - sheet[CSS_PRIMARY_USER_IMPORTANT].apply (props, docTree, node, - &matchCache[CSS_PRIMARY_USER_IMPORTANT]); + sheet[CSS_PRIMARY_USER_IMPORTANT].apply (props, docTree, node, &matchCache); } void CssContext::addRule (CssSelector *sel, CssPropertyList *props, @@ -540,12 +537,16 @@ void CssContext::addRule (CssSelector *sel, CssPropertyList *props, !rule->isSafe ()) { MSG_WARN ("Ignoring unsafe author style that might reveal browsing history\n"); delete rule; - } else if (order == CSS_PRIMARY_USER_AGENT) { - userAgentSheet.addRule (rule); - matchCache[CSS_PRIMARY_USER_AGENT].setSize (userAgentSheet.matchCacheOffset, -1); - } else { - sheet[order].addRule (rule); - matchCache[order].setSize (sheet[order].matchCacheOffset, -1); + } else { + rule->selector->setMatchCacheOffset(matchCache.size ()); + if (rule->selector->getRequiredMatchCache () > matchCache.size ()) + matchCache.setSize (rule->selector->getRequiredMatchCache (), -1); + + if (order == CSS_PRIMARY_USER_AGENT) { + userAgentSheet.addRule (rule); + } else { + sheet[order].addRule (rule); + } } } } @@ -402,16 +402,20 @@ class CssSelector { void addSimpleSelector (Combinator c); inline CssSimpleSelector *top () { return selectorList.getRef (selectorList.size () - 1)->selector; - }; + } inline int size () { return selectorList.size (); }; inline bool match (Doctree *dt, const DoctreeNode *node, MatchCache *matchCache) { return match (dt, node, selectorList.size () - 1, COMB_NONE, matchCache); - }; + } inline void setMatchCacheOffset (int mo) { - matchCacheOffset = mo; - }; + if (matchCacheOffset == -1) + matchCacheOffset = mo; + } + inline int getRequiredMatchCache () { + return matchCacheOffset + size (); + } int specificity (); bool checksPseudoClass (); void print (); @@ -484,14 +488,14 @@ class CssStyleSheet { RuleList elementTable[ntags], anyTable; RuleMap idTable, classTable; + int requiredMatchCache; public: - int matchCacheOffset; - - CssStyleSheet () { matchCacheOffset = 0; } + CssStyleSheet () { requiredMatchCache = 0; } void addRule (CssRule *rule); void apply (CssPropertyList *props, Doctree *docTree, const DoctreeNode *node, MatchCache *matchCache) const; + int getRequiredMatchCache () { return requiredMatchCache; } }; /** @@ -501,7 +505,7 @@ class CssContext { private: static CssStyleSheet userAgentSheet; CssStyleSheet sheet[CSS_PRIMARY_USER_IMPORTANT + 1]; - MatchCache matchCache[CSS_PRIMARY_USER_IMPORTANT + 1]; + MatchCache matchCache; int pos; public: |