aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChad Austin <chad@imvu.com>2013-08-29 13:39:54 -0700
committerBruce Mitchener <bruce.mitchener@gmail.com>2014-02-04 16:16:10 +0700
commit1511e68f617e555b5342fe9df693eed07ffac8cb (patch)
tree5c3611d9e2da0530e42b5f79edcd2b2caf21531c
parent04b624f10d7f040e5e9551e9c956c4b0ca7c66b0 (diff)
Fix a possible memory corruption bug when using val::as
-rw-r--r--src/embind/emval.js7
-rw-r--r--system/include/emscripten/val.h32
-rw-r--r--system/include/emscripten/wire.h1
-rw-r--r--tests/embind/embind.test.js12
-rw-r--r--tests/embind/embind_test.cpp8
5 files changed, 53 insertions, 7 deletions
diff --git a/src/embind/emval.js b/src/embind/emval.js
index 0d075188..d4e4271d 100644
--- a/src/embind/emval.js
+++ b/src/embind/emval.js
@@ -3,7 +3,7 @@
/*global new_*/
/*global createNamedFunction*/
/*global readLatin1String, writeStringToMemory*/
-/*global requireRegisteredType, throwBindingError*/
+/*global requireRegisteredType, throwBindingError, runDestructors*/
/*jslint sub:true*/ /* The symbols 'fromWireType' and 'toWireType' must be accessed via array notation to be closure-safe since craftInvokerFunction crafts functions as strings that can't be closured. */
var Module = Module || {};
@@ -199,11 +199,12 @@ function __emval_set_property(handle, key, value) {
_emval_handle_array[handle].value[_emval_handle_array[key].value] = _emval_handle_array[value].value;
}
-function __emval_as(handle, returnType) {
+function __emval_as(handle, returnType, runDestructorsRef) {
requireHandle(handle);
returnType = requireRegisteredType(returnType, 'emval::as');
var destructors = [];
- // caller owns destructing
+ var rd = __emval_register(runDestructors.bind(undefined, destructors));
+ HEAP32[runDestructorsRef >> 2] = rd;
return returnType['toWireType'](destructors, _emval_handle_array[handle].value);
}
diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h
index b712d164..5a04d30f 100644
--- a/system/include/emscripten/val.h
+++ b/system/include/emscripten/val.h
@@ -11,6 +11,11 @@ namespace emscripten {
void _emval_register_symbol(const char*);
typedef struct _EM_VAL* EM_VAL;
+
+ // TODO: functions returning this are reinterpret_cast
+ // into the correct return type. this needs some thought
+ // for asm.js.
+ typedef void _POLYMORPHIC_RESULT;
void _emval_incref(EM_VAL value);
void _emval_decref(EM_VAL value);
@@ -32,7 +37,8 @@ namespace emscripten {
EM_VAL _emval_get_module_property(const char* name);
EM_VAL _emval_get_property(EM_VAL object, EM_VAL key);
void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value);
- void _emval_as(EM_VAL value, TYPEID returnType);
+ _POLYMORPHIC_RESULT _emval_as(EM_VAL value, TYPEID returnType, EM_VAL* runDestructors);
+
EM_VAL _emval_call(
EM_VAL value,
unsigned argCount,
@@ -94,6 +100,22 @@ namespace emscripten {
toWireType(std::forward<Args>(args))...);
}
};
+
+ struct DestructorsRunner {
+ public:
+ DestructorsRunner(EM_VAL v)
+ : dr(v)
+ {}
+ DestructorsRunner(const DestructorsRunner&) = delete;
+ void operator=(const DestructorsRunner&) = delete;
+ ~DestructorsRunner() {
+ EM_VAL rv = _emval_call(dr, 0, 0);
+ _emval_decref(rv); // TODO: if we had an _emval_call_void we wouldn't need this
+ _emval_decref(dr);
+ }
+ private:
+ EM_VAL dr;
+ };
}
#define EMSCRIPTEN_SYMBOL(name) \
@@ -262,11 +284,13 @@ namespace emscripten {
typedef typename BT::WireType (*TypedAs)(
EM_VAL value,
- TYPEID returnType);
+ TYPEID returnType,
+ EM_VAL* runDestructors);
TypedAs typedAs = reinterpret_cast<TypedAs>(&_emval_as);
- typename BT::WireType wt = typedAs(handle, TypeID<T>::get());
- WireDeleter<T> deleter(wt);
+ EM_VAL runDestructors;
+ typename BT::WireType wt = typedAs(handle, TypeID<T>::get(), &runDestructors);
+ DestructorsRunner dr(runDestructors);
return BT::fromWireType(wt);
}
diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h
index a5892216..70deb2c7 100644
--- a/system/include/emscripten/wire.h
+++ b/system/include/emscripten/wire.h
@@ -7,6 +7,7 @@
//
// We'll call the on-the-wire type WireType.
+#include <stdio.h>
#include <cstdlib>
#include <memory>
#include <string>
diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js
index da81a81e..ee80da0c 100644
--- a/tests/embind/embind.test.js
+++ b/tests/embind/embind.test.js
@@ -1888,6 +1888,18 @@ module({
sh.delete();
});
});
+
+ BaseFixture.extend("val::as from pointer to value", function() {
+ test("calling as on pointer with value makes a copy", function() {
+ var sh1 = new cm.StringHolder("Hello world");
+ var sh2 = cm.return_StringHolder_copy(sh1);
+ assert.equal("Hello world", sh1.get());
+ assert.equal("Hello world", sh2.get());
+ assert.false(sh1.isAliasOf(sh2));
+ sh2.delete();
+ sh1.delete();
+ });
+ });
});
/* global run_all_tests */
diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp
index d6b27bce..f723f240 100644
--- a/tests/embind/embind_test.cpp
+++ b/tests/embind/embind_test.cpp
@@ -2243,3 +2243,11 @@ void clear_StringHolder(StringHolder& sh) {
EMSCRIPTEN_BINDINGS(references) {
function("clear_StringHolder", &clear_StringHolder);
}
+
+StringHolder return_StringHolder_copy(val func) {
+ return func.as<StringHolder>();
+}
+
+EMSCRIPTEN_BINDINGS(return_values) {
+ function("return_StringHolder_copy", &return_StringHolder_copy);
+}