summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2015-02-05 21:00:17 +0100
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2015-02-05 21:00:17 +0100
commit45d59165cb6b4c80fd26d555eae8ca8f2a7d0d6f (patch)
treeb320b64f58758e12055689509a73407d980dc191
parentc169085cc9a9eb9c7c911d1b68db1f08a95c0d27 (diff)
when an exception was thrown from out of an __invoke() or __call() method, a segmentation fault occured because memory was too early freed (the exception constructor still relied on data that was already freed)
-rw-r--r--zend/classimpl.cpp12
-rw-r--r--zend/delayedfree.h50
-rw-r--r--zend/includes.h1
3 files changed, 58 insertions, 5 deletions
diff --git a/zend/classimpl.cpp b/zend/classimpl.cpp
index fa1aa60..ab95455 100644
--- a/zend/classimpl.cpp
+++ b/zend/classimpl.cpp
@@ -85,8 +85,9 @@ void ClassImpl::callMethod(INTERNAL_FUNCTION_PARAMETERS)
ClassBase *meta = data->self->_base;
// the data structure was allocated by ourselves in the getMethod or
- // getStaticMethod functions, we no longer need it now
- efree(data);
+ // getStaticMethod functions, we no longer need it when the function falls
+ // out of scope
+ DelayedFree df(data);
// the function could throw an exception
try
@@ -131,8 +132,9 @@ void ClassImpl::callInvoke(INTERNAL_FUNCTION_PARAMETERS)
ClassBase *meta = data->self->_base;
// the data structure was allocated by ourselves in the getMethod or
- // getStaticMethod functions, we no longer need it now
- efree(data);
+ // getStaticMethod functions, we no longer need it when the function falls
+ // out of scope
+ DelayedFree df(data);
// the function could throw an exception
try
@@ -310,7 +312,7 @@ int ClassImpl::getClosure(zval *object, zend_class_entry **entry_ptr, zend_funct
data->self = self(entry);
// assign this dynamically allocated variable to the func parameter
- // the case is ok, because zend_internal_function is a member of the
+ // the cast is ok, because zend_internal_function is a member of the
// zend_function union
*func = (zend_function *)data;
diff --git a/zend/delayedfree.h b/zend/delayedfree.h
new file mode 100644
index 0000000..598d4f5
--- /dev/null
+++ b/zend/delayedfree.h
@@ -0,0 +1,50 @@
+/**
+ * DelayedFree.h
+ *
+ * Sometimes a piece of data must be freed when a function gets out of
+ * scope. In stead of putting the efree() call right before every possible
+ * function end point (exceptions, returns, zend_errors()), we can use
+ * this simple class instead
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2015 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class DelayedFree
+{
+private:
+ /**
+ * The data that has to be free'd when the object falls out of scope
+ * @var void*
+ */
+ void *_data;
+
+public:
+ /**
+ * Constructor
+ * @param data Data that will be freed on destruction
+ */
+ DelayedFree(void *data) : _data(data) {}
+
+ /**
+ * Destructor
+ */
+ virtual ~DelayedFree()
+ {
+ // free the data
+ efree(_data);
+ }
+};
+
+/**
+ * End of namespace
+ */
+}
diff --git a/zend/includes.h b/zend/includes.h
index 31d3963..44d2714 100644
--- a/zend/includes.h
+++ b/zend/includes.h
@@ -124,6 +124,7 @@
#include "opcodes.h"
#include "functor.h"
#include "constantimpl.h"
+#include "delayedfree.h"
#ifndef ZVAL_COPY_VALUE
#define ZVAL_COPY_VALUE(z, v) \