Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 228b39d

Browse files
committed
Return NULL if the Object cannot be unwrapped
Fix crash in List::SetValue() etc. when trying to add a bare JavaScript object. Check for bare objects in lists and maps in test. Don't use C++ exceptions in the binding code.
1 parent f6ebeab commit 228b39d

File tree

9 files changed

+95
-27
lines changed

9 files changed

+95
-27
lines changed

binding.gyp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,12 @@
6060
'-std=c++11'
6161
],
6262
'OTHER_LDFLAGS': [],
63-
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
63+
'GCC_ENABLE_CPP_EXCEPTIONS': 'NO',
6464
'MACOSX_DEPLOYMENT_TARGET': '10.7'
6565
}
6666
}],
67-
['OS=="win"', {
68-
'msvs_settings': {
69-
'VCCLCompilerTool': {
70-
'AdditionalOptions': [
71-
'/EHsc'
72-
]
73-
}
74-
}
75-
}],
7667
['OS!="win"', {
7768
'cflags_cc+': [
78-
'-fexceptions',
7969
'-std=c++0x'
8070
]
8171
}]

src/binding.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,7 @@ union Sass_Value* sass_custom_function(const union Sass_Value* s_args, Sass_Func
2929
argv.push_back((void*)sass_list_get_value(s_args, i));
3030
}
3131

32-
try {
33-
return bridge(argv);
34-
}
35-
catch (const std::exception& e) {
36-
return sass_make_error(e.what());
37-
}
32+
return bridge(argv);
3833
}
3934

4035
int ExtractOptions(v8::Local<v8::Object> options, void* cptr, sass_context_wrapper* ctx_w, bool is_file, bool is_sync) {

src/custom_function_bridge.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
#include <stdexcept>
33
#include "custom_function_bridge.h"
44
#include "sass_types/factory.h"
5+
#include "sass_types/value.h"
56

67
Sass_Value* CustomFunctionBridge::post_process_return_value(v8::Local<v8::Value> val) const {
7-
try {
8-
return SassTypes::Factory::unwrap(val)->get_sass_value();
9-
}
10-
catch (const std::invalid_argument& e) {
11-
return sass_make_error(e.what());
8+
SassTypes::Value *v_;
9+
if ((v_ = SassTypes::Factory::unwrap(val))) {
10+
return v_->get_sass_value();
11+
} else {
12+
return sass_make_error("A SassValue object was expected.");
1213
}
1314
}
1415

src/sass_types/boolean.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ namespace SassTypes
6767
}
6868

6969
NAN_METHOD(Boolean::GetValue) {
70-
info.GetReturnValue().Set(Nan::New(static_cast<Boolean*>(Factory::unwrap(info.This()))->value));
70+
Boolean *out;
71+
if ((out = static_cast<Boolean*>(Factory::unwrap(info.This())))) {
72+
info.GetReturnValue().Set(Nan::New(out->value));
73+
}
7174
}
7275
}

src/sass_types/factory.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ namespace SassTypes
6363
Value* Factory::unwrap(v8::Local<v8::Value> obj) {
6464
// Todo: non-SassValue objects could easily fall under that condition, need to be more specific.
6565
if (!obj->IsObject() || obj.As<v8::Object>()->InternalFieldCount() != 1) {
66-
throw std::invalid_argument("A SassValue object was expected.");
66+
return NULL;
6767
}
6868

6969
return static_cast<Value*>(Nan::GetInternalFieldPointer(obj.As<v8::Object>(), 0));

src/sass_types/list.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,11 @@ namespace SassTypes
7171
}
7272

7373
Value* sass_value = Factory::unwrap(info[1]);
74-
sass_list_set_value(unwrap(info.This())->value, Nan::To<uint32_t>(info[0]).FromJust(), sass_value->get_sass_value());
74+
if (sass_value) {
75+
sass_list_set_value(unwrap(info.This())->value, Nan::To<uint32_t>(info[0]).FromJust(), sass_value->get_sass_value());
76+
} else {
77+
Nan::ThrowTypeError(Nan::New<v8::String>("A SassValue is expected as the list item").ToLocalChecked());
78+
}
7579
}
7680

7781
NAN_METHOD(List::GetSeparator) {

src/sass_types/map.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ namespace SassTypes
6262
}
6363

6464
Value* sass_value = Factory::unwrap(info[1]);
65-
sass_map_set_value(unwrap(info.This())->value, Nan::To<uint32_t>(info[0]).FromJust(), sass_value->get_sass_value());
65+
if (sass_value) {
66+
sass_map_set_value(unwrap(info.This())->value, Nan::To<uint32_t>(info[0]).FromJust(), sass_value->get_sass_value());
67+
} else {
68+
Nan::ThrowTypeError(Nan::New<v8::String>("A SassValue is expected as a map value").ToLocalChecked());
69+
}
6670
}
6771

6872
NAN_METHOD(Map::GetKey) {
@@ -100,7 +104,11 @@ namespace SassTypes
100104
}
101105

102106
Value* sass_value = Factory::unwrap(info[1]);
103-
sass_map_set_key(unwrap(info.This())->value, Nan::To<uint32_t>(info[0]).FromJust(), sass_value->get_sass_value());
107+
if (sass_value) {
108+
sass_map_set_key(unwrap(info.This())->value, Nan::To<uint32_t>(info[0]).FromJust(), sass_value->get_sass_value());
109+
} else {
110+
Nan::ThrowTypeError(Nan::New<v8::String>("A SassValue is expected as a map key").ToLocalChecked());
111+
}
104112
}
105113

106114
NAN_METHOD(Map::GetLength) {

src/sass_types/sass_value_wrapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ namespace SassTypes
118118

119119
template <class T>
120120
T* SassValueWrapper<T>::unwrap(v8::Local<v8::Object> obj) {
121+
/* This maybe NULL */
121122
return static_cast<T*>(Factory::unwrap(obj));
122123
}
123124

test/api.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,72 @@ describe('api', function() {
859859
});
860860
});
861861

862+
it('should fail when trying to set a bare number as the List item', function(done) {
863+
sass.render({
864+
data: 'div { color: foo(); }',
865+
functions: {
866+
'foo()': function() {
867+
var out = new sass.types.List(1);
868+
out.setValue(0, 2);
869+
return out;
870+
}
871+
}
872+
}, function(error) {
873+
assert.ok(/Supplied value should be a SassValue object/.test(error.message));
874+
done();
875+
});
876+
});
877+
878+
it('should fail when trying to set a bare Object as the List item', function(done) {
879+
sass.render({
880+
data: 'div { color: foo(); }',
881+
functions: {
882+
'foo()': function() {
883+
var out = new sass.types.List(1);
884+
out.setValue(0, {});
885+
return out;
886+
}
887+
}
888+
}, function(error) {
889+
assert.ok(/A SassValue is expected as the list item/.test(error.message));
890+
done();
891+
});
892+
});
893+
894+
it('should fail when trying to set a bare Object as the Map key', function(done) {
895+
sass.render({
896+
data: 'div { color: foo(); }',
897+
functions: {
898+
'foo()': function() {
899+
var out = new sass.types.Map(1);
900+
out.setKey(0, {});
901+
out.setValue(0, new sass.types.String('aaa'));
902+
return out;
903+
}
904+
}
905+
}, function(error) {
906+
assert.ok(/A SassValue is expected as a map key/.test(error.message));
907+
done();
908+
});
909+
});
910+
911+
it('should fail when trying to set a bare Object as the Map value', function(done) {
912+
sass.render({
913+
data: 'div { color: foo(); }',
914+
functions: {
915+
'foo()': function() {
916+
var out = new sass.types.Map(1);
917+
out.setKey(0, new sass.types.String('aaa'));
918+
out.setValue(0, {});
919+
return out;
920+
}
921+
}
922+
}, function(error) {
923+
assert.ok(/A SassValue is expected as a map value/.test(error.message));
924+
done();
925+
});
926+
});
927+
862928
it('should always map null, true and false to the same (immutable) object', function(done) {
863929
var counter = 0;
864930

0 commit comments

Comments
 (0)