Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix extend edge case going endlessly #3156

Merged
merged 1 commit into from
May 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/ast_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ namespace Sass {
// Implement compare and hashing operations for AST Nodes
// ###########################################################################

// TODO: get rid of funtions and use ObjEquality<T>
// TODO: get rid of functions and use ObjEquality<T>

template <class T>
// Hash the raw pointer instead of object
Expand Down
2 changes: 1 addition & 1 deletion src/ast_sel_unify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace Sass {
SASS_ASSERT(!complexes.empty(), "Can't unify empty list");
if (complexes.size() == 1) return complexes;

CompoundSelectorObj unifiedBase = SASS_MEMORY_NEW(CompoundSelector, SourceSpan("[phony]"));
CompoundSelectorObj unifiedBase = SASS_MEMORY_NEW(CompoundSelector, SourceSpan("[unify]"));
for (auto complex : complexes) {
SelectorComponentObj base = complex.back();
if (CompoundSelector * comp = base->getCompound()) {
Expand Down
6 changes: 6 additions & 0 deletions src/error_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ namespace Sass {
msg = "stack level too deep";
}

EndlessExtendError::EndlessExtendError(Backtraces traces, const AST_Node& node)
: Base(node.pstate(), def_msg, traces), node(node)
{
msg = "Extend is creating an absurdly big selector, aborting!";
}

IncompatibleUnits::IncompatibleUnits(const Units& lhs, const Units& rhs)
{
msg = "Incompatible units: '" + rhs.unit() + "' and '" + lhs.unit() + "'.";
Expand Down
9 changes: 9 additions & 0 deletions src/error_handling.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ namespace Sass {
virtual ~StackError() throw() {};
};

class EndlessExtendError : public Base {
protected:
const AST_Node& node;
public:
EndlessExtendError(Backtraces traces, const AST_Node& node);
virtual const char* errtype() const { return "EndlessExtendError"; }
virtual ~EndlessExtendError() throw() {};
};

/* common virtual base class (has no pstate or trace) */
class OperationError : public std::runtime_error {
protected:
Expand Down
19 changes: 15 additions & 4 deletions src/extender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ namespace Sass {

for (sass::vector<SelectorComponentObj>& components : weaved) {

ComplexSelectorObj cplx = SASS_MEMORY_NEW(ComplexSelector, "[phony]");
ComplexSelectorObj cplx = SASS_MEMORY_NEW(ComplexSelector, complex->pstate());
cplx->hasPreLineFeed(complex->hasPreLineFeed());
for (auto& pp : path) {
if (pp->hasPreLineFeed()) {
Expand All @@ -643,7 +643,18 @@ namespace Sass {
}
first = false;

result.push_back(cplx);
auto it = result.begin();
while (it != result.end()) {
if (ObjEqualityFn(*it, cplx)) break;
it += 1;
}
if (it == result.end()) {
result.push_back(cplx);
}

if (result.size() > 500) {
throw Exception::EndlessExtendError(traces, complex);
}

}

Expand Down Expand Up @@ -838,7 +849,7 @@ namespace Sass {
}
if (!originals.empty()) {
CompoundSelectorObj merged =
SASS_MEMORY_NEW(CompoundSelector, "[phony]");
SASS_MEMORY_NEW(CompoundSelector, "[compound]");
merged->concat(originals);
toUnify.insert(toUnify.begin(), { merged });
}
Expand Down Expand Up @@ -1050,7 +1061,7 @@ namespace Sass {
}
}

SelectorListObj list = SASS_MEMORY_NEW(SelectorList, "[phony]");
SelectorListObj list = SASS_MEMORY_NEW(SelectorList, "[pseudo]");
list->concat(expanded);
return { pseudo->withSelector(list) };

Expand Down
2 changes: 1 addition & 1 deletion src/fn_selectors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ namespace Sass {

for (auto& complex : sel->elements()) {
if (complex->empty()) {
complex->append(SASS_MEMORY_NEW(CompoundSelector, "[phony]"));
complex->append(SASS_MEMORY_NEW(CompoundSelector, "[append]"));
}
if (CompoundSelector* comp = Cast<CompoundSelector>(complex->first())) {
comp->hasRealParent(true);
Expand Down
1 change: 1 addition & 0 deletions src/sass_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ namespace Sass {
// now create the code trace (ToDo: maybe have util functions?)
if (e.pstate.position.line != sass::string::npos &&
e.pstate.position.column != sass::string::npos &&
e.pstate.getRawData() != nullptr &&
e.pstate.source != nullptr) {
Offset offset(e.pstate.position);
size_t lines = offset.line;
Expand Down