Skip to content

[pull] master from CopernicaMarketingSoftware:master #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ INSTALL_LIB = ${INSTALL_PREFIX}/lib
#

SONAME = 2.4
VERSION = 2.4.3
VERSION = 2.4.5


#
Expand Down
9 changes: 5 additions & 4 deletions include/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* this class.
*
* @author Emiel Bruijntjes <[email protected]>
* @copyright 2013 - 2019 Copernica BV
* @copyright 2013 - 2024 Copernica BV
*/

/**
Expand Down Expand Up @@ -1133,7 +1133,7 @@ class PHPCPP_EXPORT Value : private HashParent
* @param argv The parameters
* @return Value
*/
Value exec(int argc, Value *argv) const;
Value exec(int argc, Value argv[]) const;

/**
* Call method with a number of parameters
Expand All @@ -1142,8 +1142,8 @@ class PHPCPP_EXPORT Value : private HashParent
* @param argv The parameters
* @return Value
*/
Value exec(const char *name, int argc, Value *argv) const;
Value exec(const char *name, int argc, Value *argv);
Value exec(const char *name, int argc, Value argv[]) const;
Value exec(const char *name, int argc, Value argv[]);

/**
* Refcount - the number of references to the value
Expand Down Expand Up @@ -1242,6 +1242,7 @@ class PHPCPP_EXPORT Value : private HashParent
friend class Script;
friend class ConstantImpl;
friend class Stream;
friend class ExecArguments;

/**
* Friend functions which have to access that zval directly
Expand Down
7 changes: 5 additions & 2 deletions zend/classimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Implementation file for the ClassImpl class
*
* @author Emiel Bruijntjes <[email protected]>
* @copyright 2014 - 2019 Copernica BV
* @copyright 2014 - 2024 Copernica BV
*/
#include "includes.h"
#include <cstring>
Expand Down Expand Up @@ -207,7 +207,10 @@ zend_function *ClassImpl::getMethod(zend_object **object, zend_string *method, c
// had an implementation here that used a static variable, and that worked too,
// but we'll follow thread safe implementation of the Zend engine here, although
// it is strange to allocate and free memory in one and the same method call (free()
// call happens in call_method())
// call happens in call_method()) (2024-10-13 extra info: the method_exists()
// function and our own Value::isCallable() method expect this to be emalloc()-
// allocated buffer, because they both call zend_free_trampoline() (which is
// effectively an efree() call) on the returned function-structure)
auto *data = (CallData *)emalloc(sizeof(CallData));
auto *function = &data->func;

Expand Down
102 changes: 102 additions & 0 deletions zend/execarguments.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* ExecArguments.h
*
* Helper class that we use to turn an array of Value objects into an
* array of zval parameters
*
* @author Emiel Bruijntjes <[email protected]>
* @copyright 2024 Copernica BV
*/

/**
* Include guard
*/
#pragma once

/**
* Begin of namespace
*/
namespace Php {

/**
* Class definition
*/
class ExecArguments
{
private:
/**
* Short-array-optimization (most exec calls do not have more than 10 parameters)
* @var zval[]
*/
zval _preallocated[10];

/**
* The actual arguments
* @var zval[]
*/
zval *_argv;

/**
* The number of arguments
* @var size_t
*/
size_t _argc;

public:
/**
* Default constructor
*/
ExecArguments() : _argv(_preallocated), _argc(0) {}

/**
* Constructor
* @param argc
* @param argv
*/
ExecArguments(size_t argc, Value argv[]) : _argv(_preallocated), _argc(argc)
{
// if there are too many arguments, we allocate them right away
if (_argc > 10) _argv = (zval *)malloc(sizeof(zval) * _argc);

// convert Value objects to zval array with references
for (size_t i = 0; i < argc; ++i)
{
// make sure the original variable is a reference so that our copy points to the same data
// @todo not sure if this is needed, do we need to turn the parameters into references to allow for pass-by-reference parameters?
//if (!Z_ISREF_P(argv[i]._val)) ZVAL_MAKE_REF(argv[i]._val);

// copy the zval
ZVAL_COPY(&_argv[i], argv[i]._val);
}
}

/**
* No copying (we could implement this later, but for now this is not needed)
* @param that
*/
ExecArguments(const ExecArguments &that) = delete;

/**
* Destructor
*/
virtual ~ExecArguments()
{
// destruct all zval objects
for (size_t i = 0; i < _argc; ++i) zval_ptr_dtor(&_argv[i]);

// deallocate memory
if (_argv != _preallocated) free(_argv);
}

/**
* Convert to a argv[]
* @return zval[]
*/
zval *argv() { return _argv; }
int argc() { return _argc; }
};

/**
* End of namespace
*/
}
48 changes: 28 additions & 20 deletions zend/value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@
*
*
* @author Emiel Bruijntjes <[email protected]>
* @copyright 2013 - 2019 Copernica BV
* @copyright 2019 - 2024 Copernica BV
*/
#include "includes.h"
#include "string.h"
#include "lowercase.h"
#include "macros.h"
#include "execarguments.h"

/**
* Set up namespace
Expand Down Expand Up @@ -822,6 +823,19 @@ static Value do_exec(const zval *object, zval *method, int argc, zval *argv)
}
}

/**
* Helper function that runs the actual call
* @param object The object to call it on
* @param method The function or method to call
* @param args The parameters
* @return Value
*/
static Value do_exec(const zval *object, zval *method, ExecArguments &args)
{
// pass on
return do_exec(object, method, args.argc(), args.argv());
}

/**
* Call the function in PHP
* We have ten variants of this function, depending on the number of parameters
Expand Down Expand Up @@ -877,8 +891,11 @@ bool Value::isCallable(const char *name)
bool result = func->common.scope == zend_ce_closure && zend_string_equals_cstr(methodname.value(), ZEND_INVOKE_FUNC_NAME, ::strlen(ZEND_INVOKE_FUNC_NAME));
#endif

// free resources (still don't get this code, copied from zend_builtin_functions.c)
zend_string_release(func->common.function_name);
// in method_exists(), there is also a zend_string_release() call here, but I dont think we
// need it here, because the methodname is already cleanup by the destructor of the LowerCase class
//zend_string_release(func->common.function_name);

// free resources, just like method_exists() does
zend_free_trampoline(func);

// done
Expand Down Expand Up @@ -919,16 +936,13 @@ Value Value::call(const char *name)
* @param argv The parameters
* @return Value
*/
Value Value::exec(int argc, Value *argv) const
Value Value::exec(int argc, Value argv[]) const
{
// array of zvals to execute
zval* params = static_cast<zval*>(alloca(argc * sizeof(zval)));

// convert all the values
for(int i = 0; i < argc; i++) { params[i] = *argv[i]._val; }

ExecArguments args(argc, argv);

// call helper function
return do_exec(nullptr, _val, argc, params);
return do_exec(nullptr, _val, args);
}

/**
Expand All @@ -944,13 +958,10 @@ Value Value::exec(const char *name, int argc, Value *argv) const
Value method(name);

// array of zvals to execute
zval* params = static_cast<zval*>(alloca(argc * sizeof(zval)));

// convert all the values
for(int i = 0; i < argc; i++) { params[i] = *argv[i]._val; }
ExecArguments args(argc, argv);

// call helper function
return do_exec(_val, method._val, argc, params);
return do_exec(_val, method._val, args);
}

/**
Expand All @@ -966,13 +977,10 @@ Value Value::exec(const char *name, int argc, Value *argv)
Value method(name);

// array of zvals to execute
zval* params = static_cast<zval*>(alloca(argc * sizeof(zval)));

// convert all the values
for(int i = 0; i < argc; i++) { params[i] = *argv[i]._val; }
ExecArguments args(argc, argv);

// call helper function
return do_exec(_val, method._val, argc, params);
return do_exec(_val, method._val, args);
}

/**
Expand Down