Skip to content

Commit a172416

Browse files
committed
Protect sass_value_op from thrown C++ exceptions
Errors get converted to a simple `Sass_Error` value
1 parent 5b4122d commit a172416

File tree

2 files changed

+57
-42
lines changed

2 files changed

+57
-42
lines changed

src/sass_context.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ extern "C" {
246246
c_ctx->source_map_string = 0;
247247
json_delete(json_err);
248248
}
249-
catch(std::bad_alloc& ba) {
249+
catch (std::bad_alloc& ba) {
250250
std::stringstream msg_stream;
251251
JsonNode* json_err = json_mkobject();
252252
msg_stream << "Unable to allocate memory: " << ba.what() << std::endl;

src/sass_values.cpp

Lines changed: 56 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -359,51 +359,66 @@ extern "C" {
359359

360360
Sass::Value* rv = 0;
361361
Memory_Manager<AST_Node> mem;
362-
Value* lhs = sass_value_to_ast_node(mem, a);
363-
Value* rhs = sass_value_to_ast_node(mem, b);
364-
365-
// see if it's a relational expression
366-
switch(op) {
367-
case Sass_OP::EQ: return sass_make_boolean(Eval::eq(lhs, rhs));
368-
case Sass_OP::NEQ: return sass_make_boolean(!Eval::eq(lhs, rhs));
369-
case Sass_OP::GT: return sass_make_boolean(!Eval::lt(lhs, rhs) && !Eval::eq(lhs, rhs));
370-
case Sass_OP::GTE: return sass_make_boolean(!Eval::lt(lhs, rhs));
371-
case Sass_OP::LT: return sass_make_boolean(Eval::lt(lhs, rhs));
372-
case Sass_OP::LTE: return sass_make_boolean(Eval::lt(lhs, rhs) || Eval::eq(lhs, rhs));
373-
default: break;
374-
}
375362

376-
if (sass_value_is_number(a) && sass_value_is_number(b)) {
377-
const Number* l_n = dynamic_cast<const Number*>(lhs);
378-
const Number* r_n = dynamic_cast<const Number*>(rhs);
379-
rv = Eval::op_numbers(mem, op, *l_n, *r_n);
380-
}
381-
else if (sass_value_is_number(a) && sass_value_is_color(a)) {
382-
const Number* l_n = dynamic_cast<const Number*>(lhs);
383-
const Color* r_c = dynamic_cast<const Color*>(rhs);
384-
rv = Eval::op_number_color(mem, op, *l_n, *r_c);
385-
}
386-
else if (sass_value_is_color(a) && sass_value_is_number(b)) {
387-
const Color* l_c = dynamic_cast<const Color*>(lhs);
388-
const Number* r_n = dynamic_cast<const Number*>(rhs);
389-
rv = Eval::op_color_number(mem, op, *l_c, *r_n);
390-
}
391-
else if (sass_value_is_color(a) && sass_value_is_color(b)) {
392-
const Color* l_c = dynamic_cast<const Color*>(lhs);
393-
const Color* r_c = dynamic_cast<const Color*>(rhs);
394-
rv = Eval::op_colors(mem, op, *l_c, *r_c);
395-
}
396-
else /* convert other stuff to string and apply operation */ {
397-
Value* l_v = dynamic_cast<Value*>(lhs);
398-
Value* r_v = dynamic_cast<Value*>(rhs);
399-
rv = Eval::op_strings(mem, op, *l_v, *r_v);
363+
try {
364+
365+
Value* lhs = sass_value_to_ast_node(mem, a);
366+
Value* rhs = sass_value_to_ast_node(mem, b);
367+
368+
// see if it's a relational expression
369+
switch(op) {
370+
case Sass_OP::EQ: return sass_make_boolean(Eval::eq(lhs, rhs));
371+
case Sass_OP::NEQ: return sass_make_boolean(!Eval::eq(lhs, rhs));
372+
case Sass_OP::GT: return sass_make_boolean(!Eval::lt(lhs, rhs) && !Eval::eq(lhs, rhs));
373+
case Sass_OP::GTE: return sass_make_boolean(!Eval::lt(lhs, rhs));
374+
case Sass_OP::LT: return sass_make_boolean(Eval::lt(lhs, rhs));
375+
case Sass_OP::LTE: return sass_make_boolean(Eval::lt(lhs, rhs) || Eval::eq(lhs, rhs));
376+
default: break;
377+
}
378+
379+
if (sass_value_is_number(a) && sass_value_is_number(b)) {
380+
const Number* l_n = dynamic_cast<const Number*>(lhs);
381+
const Number* r_n = dynamic_cast<const Number*>(rhs);
382+
rv = Eval::op_numbers(mem, op, *l_n, *r_n);
383+
}
384+
else if (sass_value_is_number(a) && sass_value_is_color(a)) {
385+
const Number* l_n = dynamic_cast<const Number*>(lhs);
386+
const Color* r_c = dynamic_cast<const Color*>(rhs);
387+
rv = Eval::op_number_color(mem, op, *l_n, *r_c);
388+
}
389+
else if (sass_value_is_color(a) && sass_value_is_number(b)) {
390+
const Color* l_c = dynamic_cast<const Color*>(lhs);
391+
const Number* r_n = dynamic_cast<const Number*>(rhs);
392+
rv = Eval::op_color_number(mem, op, *l_c, *r_n);
393+
}
394+
else if (sass_value_is_color(a) && sass_value_is_color(b)) {
395+
const Color* l_c = dynamic_cast<const Color*>(lhs);
396+
const Color* r_c = dynamic_cast<const Color*>(rhs);
397+
rv = Eval::op_colors(mem, op, *l_c, *r_c);
398+
}
399+
else /* convert other stuff to string and apply operation */ {
400+
Value* l_v = dynamic_cast<Value*>(lhs);
401+
Value* r_v = dynamic_cast<Value*>(rhs);
402+
rv = Eval::op_strings(mem, op, *l_v, *r_v);
403+
}
404+
405+
// ToDo: maybe we should should return null value?
406+
if (!rv) return sass_make_error("invalid return value");
407+
408+
// convert result back to ast node
409+
return ast_node_to_sass_value(rv);
410+
400411
}
401412

402-
// ToDo: maybe we should should return null value?
403-
if (!rv) return sass_make_error("invalid return value");
413+
// simply pass the error message back to the caller for now
414+
catch (Error_Invalid& e) { return sass_make_error(e.message.c_str()); }
415+
catch (std::bad_alloc& ba) { return sass_make_error("memory exhausted"); }
416+
catch (std::exception& e) { return sass_make_error(e.what()); }
417+
catch (std::string& e) { return sass_make_error(e.c_str()); }
418+
catch (const char* e) { return sass_make_error(e); }
419+
catch (...) { return sass_make_error("unknown"); }
404420

405-
// convert result back to ast node
406-
return ast_node_to_sass_value(rv);
421+
return 0;
407422

408423
}
409424

0 commit comments

Comments
 (0)