// helper to aid dreaded MSVC debug mode char* sass_copy_string(std::string str) { // In MSVC the following can lead to segfault: // sass_copy_c_string(stream.str().c_str()); // Reason is that the string returned by str() is disposed before // sass_copy_c_string is invoked. The string is actually a stack // object, so indeed nobody is holding on to it. So it seems // perfectly fair to release it right away. So the const char* // by c_str will point to invalid memory. I'm not sure if this is // the behavior for all compiler, but I'm pretty sure we would // have gotten more issues reported if that would be the case. // Wrapping it in a functions seems the cleanest approach as the // function must hold on to the stack variable until it's done. return sass_copy_c_string(str.c_str()); }
static int handle_error(Sass_Context* c_ctx) { try { throw; } catch (Exception::Base& e) { std::stringstream msg_stream; std::string cwd(Sass::File::get_cwd()); std::string msg_prefix(e.errtype()); bool got_newline = false; msg_stream << msg_prefix << ": "; const char* msg = e.what(); while (msg && *msg) { if (*msg == '\r') { got_newline = true; } else if (*msg == '\n') { got_newline = true; } else if (got_newline) { msg_stream << std::string(msg_prefix.size() + 2, ' '); got_newline = false; } msg_stream << *msg; ++msg; } if (!got_newline) msg_stream << "\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() + 2, ' '); 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() + 2, ' '); 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) { size_t line = e.pstate.line; const char* line_beg = e.pstate.src; while (line_beg && *line_beg && line) { if (*line_beg == '\n') --line; ++line_beg; } const char* line_end = line_beg; while (line_end && *line_end && *line_end != '\n') { if (*line_end == '\n') break; if (*line_end == '\r') break; line_end++; } size_t max_left = 42; size_t max_right = 78; size_t move_in = e.pstate.column > max_left ? e.pstate.column - max_left : 0; size_t shorten = (line_end - line_beg) - move_in > max_right ? (line_end - line_beg) - move_in - max_right : 0; msg_stream << ">> " << std::string(line_beg + move_in, line_end - shorten) << "\n"; msg_stream << " " << std::string(e.pstate.column - move_in, '-') << "^\n"; } JsonNode* json_err = json_mkobject(); json_append_member(json_err, "status", json_mknumber(1)); json_append_member(json_err, "file", json_mkstring(e.pstate.path)); json_append_member(json_err, "line", json_mknumber((double)(e.pstate.line + 1))); json_append_member(json_err, "column", json_mknumber((double)(e.pstate.column + 1))); json_append_member(json_err, "message", json_mkstring(e.what())); json_append_member(json_err, "formatted", json_mkstream(msg_stream)); try { c_ctx->error_json = json_stringify(json_err, " "); } catch (...) {} c_ctx->error_message = sass_copy_string(msg_stream.str()); c_ctx->error_text = sass_copy_c_string(e.what()); c_ctx->error_status = 1; c_ctx->error_file = sass_copy_c_string(e.pstate.path); c_ctx->error_line = e.pstate.line + 1; c_ctx->error_column = e.pstate.column + 1; c_ctx->error_src = e.pstate.src; c_ctx->output_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); } catch (std::bad_alloc& ba) { std::stringstream msg_stream; JsonNode* json_err = json_mkobject(); msg_stream << "Unable to allocate memory: " << ba.what() << std::endl; json_append_member(json_err, "status", json_mknumber(2)); json_append_member(json_err, "message", json_mkstring(ba.what())); json_append_member(json_err, "formatted", json_mkstream(msg_stream)); try { c_ctx->error_json = json_stringify(json_err, " "); } catch (...) {} c_ctx->error_message = sass_copy_string(msg_stream.str()); c_ctx->error_text = sass_copy_c_string(ba.what()); c_ctx->error_status = 2; c_ctx->output_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); } catch (std::exception& e) { std::stringstream msg_stream; JsonNode* json_err = json_mkobject(); msg_stream << "Internal Error: " << e.what() << std::endl; json_append_member(json_err, "status", json_mknumber(3)); json_append_member(json_err, "message", json_mkstring(e.what())); json_append_member(json_err, "formatted", json_mkstream(msg_stream)); try { c_ctx->error_json = json_stringify(json_err, " "); } catch (...) {} c_ctx->error_message = sass_copy_string(msg_stream.str()); c_ctx->error_text = sass_copy_c_string(e.what()); c_ctx->error_status = 3; c_ctx->output_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); } catch (std::string& e) { std::stringstream msg_stream; JsonNode* json_err = json_mkobject(); msg_stream << "Internal Error: " << e << std::endl; json_append_member(json_err, "status", json_mknumber(4)); json_append_member(json_err, "message", json_mkstring(e.c_str())); json_append_member(json_err, "formatted", json_mkstream(msg_stream)); try { c_ctx->error_json = json_stringify(json_err, " "); } catch (...) {} c_ctx->error_message = sass_copy_string(msg_stream.str()); c_ctx->error_text = sass_copy_c_string(e.c_str()); c_ctx->error_status = 4; c_ctx->output_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); } catch (const char* e) { std::stringstream msg_stream; JsonNode* json_err = json_mkobject(); msg_stream << "Internal Error: " << e << std::endl; json_append_member(json_err, "status", json_mknumber(4)); json_append_member(json_err, "message", json_mkstring(e)); json_append_member(json_err, "formatted", json_mkstream(msg_stream)); try { c_ctx->error_json = json_stringify(json_err, " "); } catch (...) {} c_ctx->error_message = sass_copy_string(msg_stream.str()); c_ctx->error_text = sass_copy_c_string(e); c_ctx->error_status = 4; c_ctx->output_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); } catch (...) { std::stringstream msg_stream; JsonNode* json_err = json_mkobject(); msg_stream << "Unknown error occurred" << std::endl; json_append_member(json_err, "status", json_mknumber(5)); json_append_member(json_err, "message", json_mkstring("unknown")); try { c_ctx->error_json = json_stringify(json_err, " "); } catch (...) {} c_ctx->error_message = sass_copy_string(msg_stream.str()); c_ctx->error_text = sass_copy_c_string("unknown"); c_ctx->error_status = 5; c_ctx->output_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); } return c_ctx->error_status; }