Skip to content

Commit

Permalink
Implement import recursion check
Browse files Browse the repository at this point in the history
Also adds import stack reports on errors.
  • Loading branch information
mgreter committed Jan 6, 2016
1 parent b9766ba commit c338fbf
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 14 deletions.
28 changes: 24 additions & 4 deletions src/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "listize.hpp"
#include "extend.hpp"
#include "remove_placeholders.hpp"
#include "sass_functions.hpp"
#include "functions.hpp"
#include "backtrace.hpp"
#include "sass2scss.h"
Expand Down Expand Up @@ -254,7 +255,7 @@ namespace Sass {

// register include with resolved path and its content
// memory of the resources will be freed by us on exit
void Context::register_resource(const Include& inc, const Resource& res)
void Context::register_resource(const Include& inc, const Resource& res, ParserState* prstate)
{

// do not parse same resource twice
Expand Down Expand Up @@ -297,6 +298,24 @@ namespace Sass {
strings.push_back(sass_strdup(inc.abs_path.c_str()));
// create the initial parser state from resource
ParserState pstate(strings.back(), contents, idx);

// check existing import stack for possible recursion
for (size_t i = 0; i < import_stack.size() - 2; ++i) {
auto parent = import_stack[i];
if (std::strcmp(parent->abs_path, import->abs_path) == 0) {
std::string stack("An @import loop has been found:");
for (size_t n = 1; n < i + 2; ++n) {
stack += "\n " + std::string(import_stack[n]->imp_path) +
" imports " + std::string(import_stack[n+1]->imp_path);
}
// implement error throw directly until we
// decided how to handle full stack traces
ParserState state = prstate ? *prstate : pstate;
throw Exception::InvalidSyntax(state, stack, &import_stack);
// error(stack, prstate ? *prstate : pstate, import_stack);
}
}

// create a parser instance from the given c_str buffer
Parser p(Parser::from_c_str(contents, *this, pstate));
// do not yet dispose these buffers
Expand Down Expand Up @@ -344,7 +363,7 @@ namespace Sass {
// the memory buffer returned must be freed by us!
if (char* contents = read_file(resolved[0].abs_path)) {
// register the newly resolved file resource
register_resource(resolved[0], { contents, 0 });
register_resource(resolved[0], { contents, 0 }, &pstate);
// return resolved entry
return resolved[0];
}
Expand Down Expand Up @@ -433,7 +452,7 @@ namespace Sass {
// handle error message passed back from custom importer
// it may (or may not) override the line and column info
if (const char* err_message = sass_import_get_error_message(include)) {
if (source || srcmap) register_resource({ importer, uniq_path }, { source, srcmap });
if (source || srcmap) register_resource({ importer, uniq_path }, { source, srcmap }, &pstate);
if (line == std::string::npos && column == std::string::npos) error(err_message, pstate);
else error(err_message, ParserState(ctx_path, source, Position(line, column)));
}
Expand All @@ -447,7 +466,7 @@ namespace Sass {
// attach information to AST node
imp->incs().push_back(include);
// register the resource buffers
register_resource(include, { source, srcmap });
register_resource(include, { source, srcmap }, &pstate);
}
// only a path was retuned
// try to load it like normal
Expand Down Expand Up @@ -639,6 +658,7 @@ namespace Sass {
Expand expand(*this, &global, &backtrace);
Cssize cssize(*this, &backtrace);
// expand and eval the tree
// debug_ast(root);
root = root->perform(&expand)->block();
// merge and bubble certain rules
root = root->perform(&cssize)->block();
Expand Down
2 changes: 1 addition & 1 deletion src/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ namespace Sass {
virtual char* render(Block* root);
virtual char* render_srcmap();

void register_resource(const Include&, const Resource&);
void register_resource(const Include&, const Resource&, ParserState* = 0);
std::vector<Include> find_includes(const Importer& import);
Include load_import(const Importer&, ParserState pstate);

Expand Down
9 changes: 5 additions & 4 deletions src/error_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ namespace Sass {

namespace Exception {

Base::Base(ParserState pstate, std::string msg)
Base::Base(ParserState pstate, std::string msg, std::vector<Sass_Import_Entry>* import_stack)
: std::runtime_error(msg),
msg(msg), pstate(pstate)
msg(msg), pstate(pstate),
import_stack(import_stack)
{ }

const char* Base::what() const throw()
Expand Down Expand Up @@ -44,8 +45,8 @@ namespace Sass {
msg += " for `" + fn + "'";
}

InvalidSyntax::InvalidSyntax(ParserState pstate, std::string msg)
: Base(pstate, msg)
InvalidSyntax::InvalidSyntax(ParserState pstate, std::string msg, std::vector<Sass_Import_Entry>* import_stack)
: Base(pstate, msg, import_stack)
{ }

}
Expand Down
5 changes: 3 additions & 2 deletions src/error_handling.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ namespace Sass {
std::string msg;
public:
ParserState pstate;
std::vector<Sass_Import_Entry>* import_stack;
public:
Base(ParserState pstate, std::string msg = def_msg);
Base(ParserState pstate, std::string msg = def_msg, std::vector<Sass_Import_Entry>* import_stack = 0);
virtual const char* what() const throw();
virtual ~Base() throw() {};
};
Expand Down Expand Up @@ -53,7 +54,7 @@ namespace Sass {

class InvalidSyntax : public Base {
public:
InvalidSyntax(ParserState pstate, std::string msg);
InvalidSyntax(ParserState pstate, std::string msg, std::vector<Sass_Import_Entry>* import_stack = 0);
virtual ~InvalidSyntax() throw() {};
};

Expand Down
17 changes: 14 additions & 3 deletions src/sass_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "util.hpp"
#include "context.hpp"
#include "sass_context.hpp"
#include "sass_functions.hpp"
#include "ast_fwd_decl.hpp"
#include "error_handling.hpp"

Expand Down Expand Up @@ -41,7 +42,6 @@ extern "C" {
catch (Exception::Base& e) {
std::stringstream msg_stream;
std::string cwd(Sass::File::get_cwd());
std::string rel_path(Sass::File::abs2rel(e.pstate.path, cwd, cwd));

std::string msg_prefix("Error: ");
bool got_newline = false;
Expand All @@ -60,8 +60,19 @@ extern "C" {
++ msg;
}
if (!got_newline) msg_stream << "\n";
msg_stream << std::string(msg_prefix.size(), ' ');
msg_stream << " on line " << e.pstate.line+1 << " of " << rel_path << "\n";
if (e.import_stack) {
for (size_t i = 1; i < e.import_stack->size() - 1; ++i) {
std::string path((*e.import_stack)[i]->imp_path);
std::string rel_path(Sass::File::abs2rel(path, cwd, cwd));
msg_stream << std::string(msg_prefix.size(), ' ');
msg_stream << (i == 1 ? " on line " : " from line ");
msg_stream << e.pstate.line+1 << " of " << rel_path << "\n";
}
} else {
std::string rel_path(Sass::File::abs2rel(e.pstate.path, cwd, cwd));
msg_stream << std::string(msg_prefix.size(), ' ');
msg_stream << " on line " << e.pstate.line+1 << " of " << rel_path << "\n";
}

// now create the code trace (ToDo: maybe have util functions?)
if (e.pstate.line != std::string::npos && e.pstate.column != std::string::npos) {
Expand Down

0 comments on commit c338fbf

Please sign in to comment.