From 45d59165cb6b4c80fd26d555eae8ca8f2a7d0d6f Mon Sep 17 00:00:00 2001 From: Emiel Bruijntjes Date: Thu, 5 Feb 2015 21:00:17 +0100 Subject: 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) --- zend/classimpl.cpp | 12 +++++++----- zend/delayedfree.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ zend/includes.h | 1 + 3 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 zend/delayedfree.h 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 + * @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) \ -- cgit v1.2.3