ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat
This commit is contained in:
@@ -36,7 +36,7 @@
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_global.h"
|
||||
|
||||
#include "bpy_rna_driver.h" /* for pyrna_driver_get_variable_value */
|
||||
#include "bpy_rna_driver.h" /* for pyrna_driver_get_variable_value */
|
||||
|
||||
#include "bpy_intern_string.h"
|
||||
|
||||
@@ -66,137 +66,136 @@ static PyObject *bpy_pydriver_Dict__whitelist = NULL;
|
||||
*/
|
||||
int bpy_pydriver_create_dict(void)
|
||||
{
|
||||
PyObject *d, *mod;
|
||||
PyObject *d, *mod;
|
||||
|
||||
/* validate namespace for driver evaluation */
|
||||
if (bpy_pydriver_Dict) {
|
||||
return -1;
|
||||
}
|
||||
/* validate namespace for driver evaluation */
|
||||
if (bpy_pydriver_Dict) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
d = PyDict_New();
|
||||
if (d == NULL) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
bpy_pydriver_Dict = d;
|
||||
}
|
||||
d = PyDict_New();
|
||||
if (d == NULL) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
bpy_pydriver_Dict = d;
|
||||
}
|
||||
|
||||
/* import some modules: builtins, bpy, math, (Blender.noise)*/
|
||||
PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins());
|
||||
/* import some modules: builtins, bpy, math, (Blender.noise)*/
|
||||
PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins());
|
||||
|
||||
mod = PyImport_ImportModule("math");
|
||||
if (mod) {
|
||||
PyDict_Merge(d, PyModule_GetDict(mod), 0); /* 0 - don't overwrite existing values */
|
||||
Py_DECREF(mod);
|
||||
}
|
||||
mod = PyImport_ImportModule("math");
|
||||
if (mod) {
|
||||
PyDict_Merge(d, PyModule_GetDict(mod), 0); /* 0 - don't overwrite existing values */
|
||||
Py_DECREF(mod);
|
||||
}
|
||||
#ifdef USE_BYTECODE_WHITELIST
|
||||
PyObject *mod_math = mod;
|
||||
PyObject *mod_math = mod;
|
||||
#endif
|
||||
|
||||
/* add bpy to global namespace */
|
||||
mod = PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
|
||||
if (mod) {
|
||||
PyDict_SetItemString(bpy_pydriver_Dict, "bpy", mod);
|
||||
Py_DECREF(mod);
|
||||
}
|
||||
/* add bpy to global namespace */
|
||||
mod = PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
|
||||
if (mod) {
|
||||
PyDict_SetItemString(bpy_pydriver_Dict, "bpy", mod);
|
||||
Py_DECREF(mod);
|
||||
}
|
||||
|
||||
/* add noise to global namespace */
|
||||
mod = PyImport_ImportModuleLevel("mathutils", NULL, NULL, NULL, 0);
|
||||
if (mod) {
|
||||
PyObject *modsub = PyDict_GetItemString(PyModule_GetDict(mod), "noise");
|
||||
PyDict_SetItemString(bpy_pydriver_Dict, "noise", modsub);
|
||||
Py_DECREF(mod);
|
||||
}
|
||||
/* add noise to global namespace */
|
||||
mod = PyImport_ImportModuleLevel("mathutils", NULL, NULL, NULL, 0);
|
||||
if (mod) {
|
||||
PyObject *modsub = PyDict_GetItemString(PyModule_GetDict(mod), "noise");
|
||||
PyDict_SetItemString(bpy_pydriver_Dict, "noise", modsub);
|
||||
Py_DECREF(mod);
|
||||
}
|
||||
|
||||
#ifdef USE_BYTECODE_WHITELIST
|
||||
/* setup the whitelist */
|
||||
{
|
||||
bpy_pydriver_Dict__whitelist = PyDict_New();
|
||||
const char *whitelist[] = {
|
||||
/* builtins (basic) */
|
||||
"all",
|
||||
"any",
|
||||
"len",
|
||||
/* builtins (numeric) */
|
||||
"max",
|
||||
"min",
|
||||
"pow",
|
||||
"round",
|
||||
"sum",
|
||||
/* types */
|
||||
"bool",
|
||||
"float",
|
||||
"int",
|
||||
/* setup the whitelist */
|
||||
{
|
||||
bpy_pydriver_Dict__whitelist = PyDict_New();
|
||||
const char *whitelist[] = {
|
||||
/* builtins (basic) */
|
||||
"all",
|
||||
"any",
|
||||
"len",
|
||||
/* builtins (numeric) */
|
||||
"max",
|
||||
"min",
|
||||
"pow",
|
||||
"round",
|
||||
"sum",
|
||||
/* types */
|
||||
"bool",
|
||||
"float",
|
||||
"int",
|
||||
|
||||
NULL,
|
||||
};
|
||||
NULL,
|
||||
};
|
||||
|
||||
for (int i = 0; whitelist[i]; i++) {
|
||||
PyDict_SetItemString(bpy_pydriver_Dict__whitelist, whitelist[i], Py_None);
|
||||
}
|
||||
for (int i = 0; whitelist[i]; i++) {
|
||||
PyDict_SetItemString(bpy_pydriver_Dict__whitelist, whitelist[i], Py_None);
|
||||
}
|
||||
|
||||
/* Add all of 'math' functions. */
|
||||
if (mod_math != NULL) {
|
||||
PyObject *mod_math_dict = PyModule_GetDict(mod_math);
|
||||
PyObject *arg_key, *arg_value;
|
||||
Py_ssize_t arg_pos = 0;
|
||||
while (PyDict_Next(mod_math_dict, &arg_pos, &arg_key, &arg_value)) {
|
||||
const char *arg_str = _PyUnicode_AsString(arg_key);
|
||||
if (arg_str[0] && arg_str[1] != '_') {
|
||||
PyDict_SetItem(bpy_pydriver_Dict__whitelist, arg_key, Py_None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* USE_BYTECODE_WHITELIST */
|
||||
/* Add all of 'math' functions. */
|
||||
if (mod_math != NULL) {
|
||||
PyObject *mod_math_dict = PyModule_GetDict(mod_math);
|
||||
PyObject *arg_key, *arg_value;
|
||||
Py_ssize_t arg_pos = 0;
|
||||
while (PyDict_Next(mod_math_dict, &arg_pos, &arg_key, &arg_value)) {
|
||||
const char *arg_str = _PyUnicode_AsString(arg_key);
|
||||
if (arg_str[0] && arg_str[1] != '_') {
|
||||
PyDict_SetItem(bpy_pydriver_Dict__whitelist, arg_key, Py_None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* USE_BYTECODE_WHITELIST */
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* note, this function should do nothing most runs, only when changing frame */
|
||||
/* not thread safe but neither is python */
|
||||
static struct {
|
||||
float evaltime;
|
||||
float evaltime;
|
||||
|
||||
/* borrowed reference to the 'self' in 'bpy_pydriver_Dict'
|
||||
* keep for as long as the same self is used. */
|
||||
PyObject *self;
|
||||
/* borrowed reference to the 'self' in 'bpy_pydriver_Dict'
|
||||
* keep for as long as the same self is used. */
|
||||
PyObject *self;
|
||||
} g_pydriver_state_prev = {
|
||||
.evaltime = FLT_MAX,
|
||||
.self = NULL,
|
||||
.evaltime = FLT_MAX,
|
||||
.self = NULL,
|
||||
};
|
||||
|
||||
static void bpy_pydriver_namespace_update_frame(const float evaltime)
|
||||
{
|
||||
if (g_pydriver_state_prev.evaltime != evaltime) {
|
||||
PyObject *item = PyFloat_FromDouble(evaltime);
|
||||
PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_frame, item);
|
||||
Py_DECREF(item);
|
||||
if (g_pydriver_state_prev.evaltime != evaltime) {
|
||||
PyObject *item = PyFloat_FromDouble(evaltime);
|
||||
PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_frame, item);
|
||||
Py_DECREF(item);
|
||||
|
||||
g_pydriver_state_prev.evaltime = evaltime;
|
||||
}
|
||||
g_pydriver_state_prev.evaltime = evaltime;
|
||||
}
|
||||
}
|
||||
|
||||
static void bpy_pydriver_namespace_update_self(struct PathResolvedRNA *anim_rna)
|
||||
{
|
||||
if ((g_pydriver_state_prev.self == NULL) ||
|
||||
(pyrna_driver_is_equal_anim_rna(anim_rna, g_pydriver_state_prev.self) == false))
|
||||
{
|
||||
PyObject *item = pyrna_driver_self_from_anim_rna(anim_rna);
|
||||
PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_self, item);
|
||||
Py_DECREF(item);
|
||||
if ((g_pydriver_state_prev.self == NULL) ||
|
||||
(pyrna_driver_is_equal_anim_rna(anim_rna, g_pydriver_state_prev.self) == false)) {
|
||||
PyObject *item = pyrna_driver_self_from_anim_rna(anim_rna);
|
||||
PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_self, item);
|
||||
Py_DECREF(item);
|
||||
|
||||
g_pydriver_state_prev.self = item;
|
||||
}
|
||||
g_pydriver_state_prev.self = item;
|
||||
}
|
||||
}
|
||||
|
||||
static void bpy_pydriver_namespace_clear_self(void)
|
||||
{
|
||||
if (g_pydriver_state_prev.self) {
|
||||
PyDict_DelItem(bpy_pydriver_Dict, bpy_intern_str_self);
|
||||
if (g_pydriver_state_prev.self) {
|
||||
PyDict_DelItem(bpy_pydriver_Dict, bpy_intern_str_self);
|
||||
|
||||
g_pydriver_state_prev.self = NULL;
|
||||
}
|
||||
g_pydriver_state_prev.self = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update function, it gets rid of pydrivers global dictionary, forcing
|
||||
@@ -206,171 +205,176 @@ static void bpy_pydriver_namespace_clear_self(void)
|
||||
*/
|
||||
void BPY_driver_reset(void)
|
||||
{
|
||||
PyGILState_STATE gilstate;
|
||||
bool use_gil = true; /* !PyC_IsInterpreterActive(); */
|
||||
PyGILState_STATE gilstate;
|
||||
bool use_gil = true; /* !PyC_IsInterpreterActive(); */
|
||||
|
||||
if (use_gil) {
|
||||
gilstate = PyGILState_Ensure();
|
||||
}
|
||||
if (use_gil) {
|
||||
gilstate = PyGILState_Ensure();
|
||||
}
|
||||
|
||||
if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
|
||||
PyDict_Clear(bpy_pydriver_Dict);
|
||||
Py_DECREF(bpy_pydriver_Dict);
|
||||
bpy_pydriver_Dict = NULL;
|
||||
}
|
||||
if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
|
||||
PyDict_Clear(bpy_pydriver_Dict);
|
||||
Py_DECREF(bpy_pydriver_Dict);
|
||||
bpy_pydriver_Dict = NULL;
|
||||
}
|
||||
|
||||
#ifdef USE_BYTECODE_WHITELIST
|
||||
if (bpy_pydriver_Dict__whitelist) {
|
||||
PyDict_Clear(bpy_pydriver_Dict__whitelist);
|
||||
Py_DECREF(bpy_pydriver_Dict__whitelist);
|
||||
bpy_pydriver_Dict__whitelist = NULL;
|
||||
}
|
||||
if (bpy_pydriver_Dict__whitelist) {
|
||||
PyDict_Clear(bpy_pydriver_Dict__whitelist);
|
||||
Py_DECREF(bpy_pydriver_Dict__whitelist);
|
||||
bpy_pydriver_Dict__whitelist = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
g_pydriver_state_prev.evaltime = FLT_MAX;
|
||||
g_pydriver_state_prev.evaltime = FLT_MAX;
|
||||
|
||||
/* freed when clearing driver dict */
|
||||
g_pydriver_state_prev.self = NULL;
|
||||
/* freed when clearing driver dict */
|
||||
g_pydriver_state_prev.self = NULL;
|
||||
|
||||
if (use_gil) {
|
||||
PyGILState_Release(gilstate);
|
||||
}
|
||||
if (use_gil) {
|
||||
PyGILState_Release(gilstate);
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
/* error return function for BPY_eval_pydriver */
|
||||
static void pydriver_error(ChannelDriver *driver)
|
||||
{
|
||||
driver->flag |= DRIVER_FLAG_INVALID; /* py expression failed */
|
||||
fprintf(stderr, "\nError in Driver: The following Python expression failed:\n\t'%s'\n\n", driver->expression);
|
||||
driver->flag |= DRIVER_FLAG_INVALID; /* py expression failed */
|
||||
fprintf(stderr,
|
||||
"\nError in Driver: The following Python expression failed:\n\t'%s'\n\n",
|
||||
driver->expression);
|
||||
|
||||
// BPy_errors_to_report(NULL); // TODO - reports
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
// BPy_errors_to_report(NULL); // TODO - reports
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
#ifdef USE_BYTECODE_WHITELIST
|
||||
|
||||
#define OK_OP(op) [op] = 1
|
||||
# define OK_OP(op) [op] = 1
|
||||
|
||||
static const char secure_opcodes[255] = {
|
||||
OK_OP(POP_TOP),
|
||||
OK_OP(ROT_TWO),
|
||||
OK_OP(ROT_THREE),
|
||||
OK_OP(DUP_TOP),
|
||||
OK_OP(DUP_TOP_TWO),
|
||||
OK_OP(NOP),
|
||||
OK_OP(UNARY_POSITIVE),
|
||||
OK_OP(UNARY_NEGATIVE),
|
||||
OK_OP(UNARY_NOT),
|
||||
OK_OP(UNARY_INVERT),
|
||||
OK_OP(BINARY_MATRIX_MULTIPLY),
|
||||
OK_OP(INPLACE_MATRIX_MULTIPLY),
|
||||
OK_OP(BINARY_POWER),
|
||||
OK_OP(BINARY_MULTIPLY),
|
||||
OK_OP(BINARY_MODULO),
|
||||
OK_OP(BINARY_ADD),
|
||||
OK_OP(BINARY_SUBTRACT),
|
||||
OK_OP(BINARY_SUBSCR),
|
||||
OK_OP(BINARY_FLOOR_DIVIDE),
|
||||
OK_OP(BINARY_TRUE_DIVIDE),
|
||||
OK_OP(INPLACE_FLOOR_DIVIDE),
|
||||
OK_OP(INPLACE_TRUE_DIVIDE),
|
||||
OK_OP(INPLACE_ADD),
|
||||
OK_OP(INPLACE_SUBTRACT),
|
||||
OK_OP(INPLACE_MULTIPLY),
|
||||
OK_OP(INPLACE_MODULO),
|
||||
OK_OP(BINARY_LSHIFT),
|
||||
OK_OP(BINARY_RSHIFT),
|
||||
OK_OP(BINARY_AND),
|
||||
OK_OP(BINARY_XOR),
|
||||
OK_OP(BINARY_OR),
|
||||
OK_OP(INPLACE_POWER),
|
||||
OK_OP(INPLACE_LSHIFT),
|
||||
OK_OP(INPLACE_RSHIFT),
|
||||
OK_OP(INPLACE_AND),
|
||||
OK_OP(INPLACE_XOR),
|
||||
OK_OP(INPLACE_OR),
|
||||
OK_OP(RETURN_VALUE),
|
||||
OK_OP(BUILD_TUPLE),
|
||||
OK_OP(BUILD_LIST),
|
||||
OK_OP(BUILD_SET),
|
||||
OK_OP(BUILD_MAP),
|
||||
OK_OP(COMPARE_OP),
|
||||
OK_OP(JUMP_FORWARD),
|
||||
OK_OP(JUMP_IF_FALSE_OR_POP),
|
||||
OK_OP(JUMP_IF_TRUE_OR_POP),
|
||||
OK_OP(JUMP_ABSOLUTE),
|
||||
OK_OP(POP_JUMP_IF_FALSE),
|
||||
OK_OP(POP_JUMP_IF_TRUE),
|
||||
OK_OP(LOAD_GLOBAL),
|
||||
OK_OP(LOAD_FAST),
|
||||
OK_OP(STORE_FAST),
|
||||
OK_OP(DELETE_FAST),
|
||||
OK_OP(LOAD_DEREF),
|
||||
OK_OP(STORE_DEREF),
|
||||
OK_OP(POP_TOP),
|
||||
OK_OP(ROT_TWO),
|
||||
OK_OP(ROT_THREE),
|
||||
OK_OP(DUP_TOP),
|
||||
OK_OP(DUP_TOP_TWO),
|
||||
OK_OP(NOP),
|
||||
OK_OP(UNARY_POSITIVE),
|
||||
OK_OP(UNARY_NEGATIVE),
|
||||
OK_OP(UNARY_NOT),
|
||||
OK_OP(UNARY_INVERT),
|
||||
OK_OP(BINARY_MATRIX_MULTIPLY),
|
||||
OK_OP(INPLACE_MATRIX_MULTIPLY),
|
||||
OK_OP(BINARY_POWER),
|
||||
OK_OP(BINARY_MULTIPLY),
|
||||
OK_OP(BINARY_MODULO),
|
||||
OK_OP(BINARY_ADD),
|
||||
OK_OP(BINARY_SUBTRACT),
|
||||
OK_OP(BINARY_SUBSCR),
|
||||
OK_OP(BINARY_FLOOR_DIVIDE),
|
||||
OK_OP(BINARY_TRUE_DIVIDE),
|
||||
OK_OP(INPLACE_FLOOR_DIVIDE),
|
||||
OK_OP(INPLACE_TRUE_DIVIDE),
|
||||
OK_OP(INPLACE_ADD),
|
||||
OK_OP(INPLACE_SUBTRACT),
|
||||
OK_OP(INPLACE_MULTIPLY),
|
||||
OK_OP(INPLACE_MODULO),
|
||||
OK_OP(BINARY_LSHIFT),
|
||||
OK_OP(BINARY_RSHIFT),
|
||||
OK_OP(BINARY_AND),
|
||||
OK_OP(BINARY_XOR),
|
||||
OK_OP(BINARY_OR),
|
||||
OK_OP(INPLACE_POWER),
|
||||
OK_OP(INPLACE_LSHIFT),
|
||||
OK_OP(INPLACE_RSHIFT),
|
||||
OK_OP(INPLACE_AND),
|
||||
OK_OP(INPLACE_XOR),
|
||||
OK_OP(INPLACE_OR),
|
||||
OK_OP(RETURN_VALUE),
|
||||
OK_OP(BUILD_TUPLE),
|
||||
OK_OP(BUILD_LIST),
|
||||
OK_OP(BUILD_SET),
|
||||
OK_OP(BUILD_MAP),
|
||||
OK_OP(COMPARE_OP),
|
||||
OK_OP(JUMP_FORWARD),
|
||||
OK_OP(JUMP_IF_FALSE_OR_POP),
|
||||
OK_OP(JUMP_IF_TRUE_OR_POP),
|
||||
OK_OP(JUMP_ABSOLUTE),
|
||||
OK_OP(POP_JUMP_IF_FALSE),
|
||||
OK_OP(POP_JUMP_IF_TRUE),
|
||||
OK_OP(LOAD_GLOBAL),
|
||||
OK_OP(LOAD_FAST),
|
||||
OK_OP(STORE_FAST),
|
||||
OK_OP(DELETE_FAST),
|
||||
OK_OP(LOAD_DEREF),
|
||||
OK_OP(STORE_DEREF),
|
||||
|
||||
/* special cases */
|
||||
OK_OP(LOAD_CONST), /* ok because constants are accepted */
|
||||
OK_OP(LOAD_NAME), /* ok, because PyCodeObject.names is checked */
|
||||
OK_OP(CALL_FUNCTION), /* ok, because we check its 'name' before calling */
|
||||
OK_OP(CALL_FUNCTION_KW),
|
||||
OK_OP(CALL_FUNCTION_EX),
|
||||
/* special cases */
|
||||
OK_OP(LOAD_CONST), /* ok because constants are accepted */
|
||||
OK_OP(LOAD_NAME), /* ok, because PyCodeObject.names is checked */
|
||||
OK_OP(CALL_FUNCTION), /* ok, because we check its 'name' before calling */
|
||||
OK_OP(CALL_FUNCTION_KW),
|
||||
OK_OP(CALL_FUNCTION_EX),
|
||||
};
|
||||
|
||||
#undef OK_OP
|
||||
# undef OK_OP
|
||||
|
||||
static bool bpy_driver_secure_bytecode_validate(PyObject *expr_code, PyObject *dict_arr[])
|
||||
{
|
||||
PyCodeObject *py_code = (PyCodeObject *)expr_code;
|
||||
PyCodeObject *py_code = (PyCodeObject *)expr_code;
|
||||
|
||||
/* Check names. */
|
||||
{
|
||||
for (int i = 0; i < PyTuple_GET_SIZE(py_code->co_names); i++) {
|
||||
PyObject *name = PyTuple_GET_ITEM(py_code->co_names, i);
|
||||
/* Check names. */
|
||||
{
|
||||
for (int i = 0; i < PyTuple_GET_SIZE(py_code->co_names); i++) {
|
||||
PyObject *name = PyTuple_GET_ITEM(py_code->co_names, i);
|
||||
|
||||
bool contains_name = false;
|
||||
for (int j = 0; dict_arr[j]; j++) {
|
||||
if (PyDict_Contains(dict_arr[j], name)) {
|
||||
contains_name = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool contains_name = false;
|
||||
for (int j = 0; dict_arr[j]; j++) {
|
||||
if (PyDict_Contains(dict_arr[j], name)) {
|
||||
contains_name = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (contains_name == false) {
|
||||
fprintf(stderr, "\tBPY_driver_eval() - restricted access disallows name '%s', "
|
||||
"enable auto-execution to support\n", _PyUnicode_AsString(name));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (contains_name == false) {
|
||||
fprintf(stderr,
|
||||
"\tBPY_driver_eval() - restricted access disallows name '%s', "
|
||||
"enable auto-execution to support\n",
|
||||
_PyUnicode_AsString(name));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check opcodes. */
|
||||
{
|
||||
const _Py_CODEUNIT *codestr;
|
||||
Py_ssize_t code_len;
|
||||
/* Check opcodes. */
|
||||
{
|
||||
const _Py_CODEUNIT *codestr;
|
||||
Py_ssize_t code_len;
|
||||
|
||||
PyBytes_AsStringAndSize(py_code->co_code, (char **)&codestr, &code_len);
|
||||
code_len /= sizeof(*codestr);
|
||||
PyBytes_AsStringAndSize(py_code->co_code, (char **)&codestr, &code_len);
|
||||
code_len /= sizeof(*codestr);
|
||||
|
||||
for (Py_ssize_t i = 0; i < code_len; i++) {
|
||||
const int opcode = _Py_OPCODE(codestr[i]);
|
||||
if (secure_opcodes[opcode] == 0) {
|
||||
fprintf(stderr, "\tBPY_driver_eval() - restricted access disallows opcode '%d', "
|
||||
"enable auto-execution to support\n", opcode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (Py_ssize_t i = 0; i < code_len; i++) {
|
||||
const int opcode = _Py_OPCODE(codestr[i]);
|
||||
if (secure_opcodes[opcode] == 0) {
|
||||
fprintf(stderr,
|
||||
"\tBPY_driver_eval() - restricted access disallows opcode '%d', "
|
||||
"enable auto-execution to support\n",
|
||||
opcode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#undef CODESIZE
|
||||
}
|
||||
# undef CODESIZE
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* USE_BYTECODE_WHITELIST */
|
||||
|
||||
#endif /* USE_BYTECODE_WHITELIST */
|
||||
|
||||
/* This evals py driver expressions, 'expr' is a Python expression that
|
||||
* should evaluate to a float number, which is returned.
|
||||
@@ -388,231 +392,239 @@ static bool bpy_driver_secure_bytecode_validate(PyObject *expr_code, PyObject *d
|
||||
* original driver, otherwise these would get freed while editing. Due to
|
||||
* the GIL this is thread-safe.
|
||||
*/
|
||||
float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, const float evaltime)
|
||||
float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
|
||||
ChannelDriver *driver,
|
||||
ChannelDriver *driver_orig,
|
||||
const float evaltime)
|
||||
{
|
||||
PyObject *driver_vars = NULL;
|
||||
PyObject *retval = NULL;
|
||||
PyObject *expr_vars; /* speed up by pre-hashing string & avoids re-converting unicode strings for every execution */
|
||||
PyObject *expr_code;
|
||||
PyGILState_STATE gilstate;
|
||||
bool use_gil;
|
||||
PyObject *driver_vars = NULL;
|
||||
PyObject *retval = NULL;
|
||||
PyObject *
|
||||
expr_vars; /* speed up by pre-hashing string & avoids re-converting unicode strings for every execution */
|
||||
PyObject *expr_code;
|
||||
PyGILState_STATE gilstate;
|
||||
bool use_gil;
|
||||
|
||||
DriverVar *dvar;
|
||||
double result = 0.0; /* default return */
|
||||
const char *expr;
|
||||
short targets_ok = 1;
|
||||
int i;
|
||||
DriverVar *dvar;
|
||||
double result = 0.0; /* default return */
|
||||
const char *expr;
|
||||
short targets_ok = 1;
|
||||
int i;
|
||||
|
||||
/* get the py expression to be evaluated */
|
||||
expr = driver_orig->expression;
|
||||
if (expr[0] == '\0') {
|
||||
return 0.0f;
|
||||
}
|
||||
/* get the py expression to be evaluated */
|
||||
expr = driver_orig->expression;
|
||||
if (expr[0] == '\0') {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
#ifndef USE_BYTECODE_WHITELIST
|
||||
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC)) {
|
||||
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET)) {
|
||||
G.f |= G_FLAG_SCRIPT_AUTOEXEC_FAIL;
|
||||
BLI_snprintf(G.autoexec_fail, sizeof(G.autoexec_fail), "Driver '%s'", expr);
|
||||
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC)) {
|
||||
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET)) {
|
||||
G.f |= G_FLAG_SCRIPT_AUTOEXEC_FAIL;
|
||||
BLI_snprintf(G.autoexec_fail, sizeof(G.autoexec_fail), "Driver '%s'", expr);
|
||||
|
||||
printf("skipping driver '%s', automatic scripts are disabled\n", expr);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
printf("skipping driver '%s', automatic scripts are disabled\n", expr);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
#else
|
||||
bool is_recompile = false;
|
||||
bool is_recompile = false;
|
||||
#endif
|
||||
|
||||
use_gil = true; /* !PyC_IsInterpreterActive(); */
|
||||
use_gil = true; /* !PyC_IsInterpreterActive(); */
|
||||
|
||||
if (use_gil) {
|
||||
gilstate = PyGILState_Ensure();
|
||||
}
|
||||
if (use_gil) {
|
||||
gilstate = PyGILState_Ensure();
|
||||
}
|
||||
|
||||
/* needed since drivers are updated directly after undo where 'main' is
|
||||
* re-allocated [#28807] */
|
||||
BPY_update_rna_module();
|
||||
/* needed since drivers are updated directly after undo where 'main' is
|
||||
* re-allocated [#28807] */
|
||||
BPY_update_rna_module();
|
||||
|
||||
/* init global dictionary for py-driver evaluation settings */
|
||||
if (!bpy_pydriver_Dict) {
|
||||
if (bpy_pydriver_create_dict() != 0) {
|
||||
fprintf(stderr, "PyDriver error: couldn't create Python dictionary\n");
|
||||
if (use_gil) {
|
||||
PyGILState_Release(gilstate);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
/* init global dictionary for py-driver evaluation settings */
|
||||
if (!bpy_pydriver_Dict) {
|
||||
if (bpy_pydriver_create_dict() != 0) {
|
||||
fprintf(stderr, "PyDriver error: couldn't create Python dictionary\n");
|
||||
if (use_gil) {
|
||||
PyGILState_Release(gilstate);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* update global namespace */
|
||||
bpy_pydriver_namespace_update_frame(evaltime);
|
||||
/* update global namespace */
|
||||
bpy_pydriver_namespace_update_frame(evaltime);
|
||||
|
||||
if (driver_orig->flag & DRIVER_FLAG_USE_SELF) {
|
||||
bpy_pydriver_namespace_update_self(anim_rna);
|
||||
}
|
||||
else {
|
||||
bpy_pydriver_namespace_clear_self();
|
||||
}
|
||||
if (driver_orig->flag & DRIVER_FLAG_USE_SELF) {
|
||||
bpy_pydriver_namespace_update_self(anim_rna);
|
||||
}
|
||||
else {
|
||||
bpy_pydriver_namespace_clear_self();
|
||||
}
|
||||
|
||||
if (driver_orig->expr_comp == NULL) {
|
||||
driver_orig->flag |= DRIVER_FLAG_RECOMPILE;
|
||||
}
|
||||
if (driver_orig->expr_comp == NULL) {
|
||||
driver_orig->flag |= DRIVER_FLAG_RECOMPILE;
|
||||
}
|
||||
|
||||
/* compile the expression first if it hasn't been compiled or needs to be rebuilt */
|
||||
if (driver_orig->flag & DRIVER_FLAG_RECOMPILE) {
|
||||
Py_XDECREF(driver_orig->expr_comp);
|
||||
driver_orig->expr_comp = PyTuple_New(2);
|
||||
/* compile the expression first if it hasn't been compiled or needs to be rebuilt */
|
||||
if (driver_orig->flag & DRIVER_FLAG_RECOMPILE) {
|
||||
Py_XDECREF(driver_orig->expr_comp);
|
||||
driver_orig->expr_comp = PyTuple_New(2);
|
||||
|
||||
expr_code = Py_CompileString(expr, "<bpy driver>", Py_eval_input);
|
||||
PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 0, expr_code);
|
||||
expr_code = Py_CompileString(expr, "<bpy driver>", Py_eval_input);
|
||||
PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 0, expr_code);
|
||||
|
||||
driver_orig->flag &= ~DRIVER_FLAG_RECOMPILE;
|
||||
driver_orig->flag |= DRIVER_FLAG_RENAMEVAR; /* maybe this can be removed but for now best keep until were sure */
|
||||
driver_orig->flag &= ~DRIVER_FLAG_RECOMPILE;
|
||||
driver_orig->flag |=
|
||||
DRIVER_FLAG_RENAMEVAR; /* maybe this can be removed but for now best keep until were sure */
|
||||
#ifdef USE_BYTECODE_WHITELIST
|
||||
is_recompile = true;
|
||||
is_recompile = true;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
expr_code = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
expr_code = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 0);
|
||||
}
|
||||
|
||||
if (driver_orig->flag & DRIVER_FLAG_RENAMEVAR) {
|
||||
/* may not be set */
|
||||
expr_vars = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 1);
|
||||
Py_XDECREF(expr_vars);
|
||||
if (driver_orig->flag & DRIVER_FLAG_RENAMEVAR) {
|
||||
/* may not be set */
|
||||
expr_vars = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 1);
|
||||
Py_XDECREF(expr_vars);
|
||||
|
||||
expr_vars = PyTuple_New(BLI_listbase_count(&driver_orig->variables));
|
||||
PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 1, expr_vars);
|
||||
expr_vars = PyTuple_New(BLI_listbase_count(&driver_orig->variables));
|
||||
PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 1, expr_vars);
|
||||
|
||||
for (dvar = driver_orig->variables.first, i = 0; dvar; dvar = dvar->next) {
|
||||
PyTuple_SET_ITEM(expr_vars, i++, PyUnicode_FromString(dvar->name));
|
||||
}
|
||||
for (dvar = driver_orig->variables.first, i = 0; dvar; dvar = dvar->next) {
|
||||
PyTuple_SET_ITEM(expr_vars, i++, PyUnicode_FromString(dvar->name));
|
||||
}
|
||||
|
||||
driver_orig->flag &= ~DRIVER_FLAG_RENAMEVAR;
|
||||
}
|
||||
else {
|
||||
expr_vars = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 1);
|
||||
}
|
||||
driver_orig->flag &= ~DRIVER_FLAG_RENAMEVAR;
|
||||
}
|
||||
else {
|
||||
expr_vars = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 1);
|
||||
}
|
||||
|
||||
/* add target values to a dict that will be used as '__locals__' dict */
|
||||
driver_vars = _PyDict_NewPresized(PyTuple_GET_SIZE(expr_vars));
|
||||
for (dvar = driver->variables.first, i = 0; dvar; dvar = dvar->next) {
|
||||
PyObject *driver_arg = NULL;
|
||||
/* add target values to a dict that will be used as '__locals__' dict */
|
||||
driver_vars = _PyDict_NewPresized(PyTuple_GET_SIZE(expr_vars));
|
||||
for (dvar = driver->variables.first, i = 0; dvar; dvar = dvar->next) {
|
||||
PyObject *driver_arg = NULL;
|
||||
|
||||
/* support for any RNA data */
|
||||
/* support for any RNA data */
|
||||
#ifdef USE_RNA_AS_PYOBJECT
|
||||
if (dvar->type == DVAR_TYPE_SINGLE_PROP) {
|
||||
driver_arg = pyrna_driver_get_variable_value(driver, &dvar->targets[0]);
|
||||
if (dvar->type == DVAR_TYPE_SINGLE_PROP) {
|
||||
driver_arg = pyrna_driver_get_variable_value(driver, &dvar->targets[0]);
|
||||
|
||||
if (driver_arg == NULL) {
|
||||
driver_arg = PyFloat_FromDouble(0.0);
|
||||
dvar->curval = 0.0f;
|
||||
}
|
||||
else {
|
||||
/* no need to worry about overflow here, values from RNA are within limits. */
|
||||
if (PyFloat_CheckExact(driver_arg)) {
|
||||
dvar->curval = (float)PyFloat_AsDouble(driver_arg);
|
||||
}
|
||||
else if (PyLong_CheckExact(driver_arg)) {
|
||||
dvar->curval = (float)PyLong_AsLong(driver_arg);
|
||||
}
|
||||
else if (PyBool_Check(driver_arg)) {
|
||||
dvar->curval = (driver_arg == Py_True);
|
||||
}
|
||||
else {
|
||||
dvar->curval = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (driver_arg == NULL) {
|
||||
driver_arg = PyFloat_FromDouble(0.0);
|
||||
dvar->curval = 0.0f;
|
||||
}
|
||||
else {
|
||||
/* no need to worry about overflow here, values from RNA are within limits. */
|
||||
if (PyFloat_CheckExact(driver_arg)) {
|
||||
dvar->curval = (float)PyFloat_AsDouble(driver_arg);
|
||||
}
|
||||
else if (PyLong_CheckExact(driver_arg)) {
|
||||
dvar->curval = (float)PyLong_AsLong(driver_arg);
|
||||
}
|
||||
else if (PyBool_Check(driver_arg)) {
|
||||
dvar->curval = (driver_arg == Py_True);
|
||||
}
|
||||
else {
|
||||
dvar->curval = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* try to get variable value */
|
||||
float tval = driver_get_variable_value(driver, dvar);
|
||||
driver_arg = PyFloat_FromDouble((double)tval);
|
||||
}
|
||||
{
|
||||
/* try to get variable value */
|
||||
float tval = driver_get_variable_value(driver, dvar);
|
||||
driver_arg = PyFloat_FromDouble((double)tval);
|
||||
}
|
||||
|
||||
/* try to add to dictionary */
|
||||
/* if (PyDict_SetItemString(driver_vars, dvar->name, driver_arg)) { */
|
||||
if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) != -1) {
|
||||
Py_DECREF(driver_arg);
|
||||
}
|
||||
else {
|
||||
/* this target failed - bad name */
|
||||
if (targets_ok) {
|
||||
/* first one - print some extra info for easier identification */
|
||||
fprintf(stderr, "\nBPY_driver_eval() - Error while evaluating PyDriver:\n");
|
||||
targets_ok = 0;
|
||||
}
|
||||
/* try to add to dictionary */
|
||||
/* if (PyDict_SetItemString(driver_vars, dvar->name, driver_arg)) { */
|
||||
if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) != -1) {
|
||||
Py_DECREF(driver_arg);
|
||||
}
|
||||
else {
|
||||
/* this target failed - bad name */
|
||||
if (targets_ok) {
|
||||
/* first one - print some extra info for easier identification */
|
||||
fprintf(stderr, "\nBPY_driver_eval() - Error while evaluating PyDriver:\n");
|
||||
targets_ok = 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "\tBPY_driver_eval() - couldn't add variable '%s' to namespace\n", dvar->name);
|
||||
// BPy_errors_to_report(NULL); // TODO - reports
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
fprintf(
|
||||
stderr, "\tBPY_driver_eval() - couldn't add variable '%s' to namespace\n", dvar->name);
|
||||
// BPy_errors_to_report(NULL); // TODO - reports
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_BYTECODE_WHITELIST
|
||||
if (is_recompile && expr_code) {
|
||||
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC)) {
|
||||
if (!bpy_driver_secure_bytecode_validate(
|
||||
expr_code, (PyObject *[]){
|
||||
bpy_pydriver_Dict,
|
||||
bpy_pydriver_Dict__whitelist,
|
||||
driver_vars,
|
||||
NULL,}
|
||||
))
|
||||
{
|
||||
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET)) {
|
||||
G.f |= G_FLAG_SCRIPT_AUTOEXEC_FAIL;
|
||||
BLI_snprintf(G.autoexec_fail, sizeof(G.autoexec_fail), "Driver '%s'", expr);
|
||||
}
|
||||
if (is_recompile && expr_code) {
|
||||
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC)) {
|
||||
if (!bpy_driver_secure_bytecode_validate(expr_code,
|
||||
(PyObject *[]){
|
||||
bpy_pydriver_Dict,
|
||||
bpy_pydriver_Dict__whitelist,
|
||||
driver_vars,
|
||||
NULL,
|
||||
})) {
|
||||
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET)) {
|
||||
G.f |= G_FLAG_SCRIPT_AUTOEXEC_FAIL;
|
||||
BLI_snprintf(G.autoexec_fail, sizeof(G.autoexec_fail), "Driver '%s'", expr);
|
||||
}
|
||||
|
||||
Py_DECREF(expr_code);
|
||||
expr_code = NULL;
|
||||
PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* USE_BYTECODE_WHITELIST */
|
||||
Py_DECREF(expr_code);
|
||||
expr_code = NULL;
|
||||
PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* USE_BYTECODE_WHITELIST */
|
||||
|
||||
#if 0 /* slow, with this can avoid all Py_CompileString above. */
|
||||
/* execute expression to get a value */
|
||||
retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, driver_vars);
|
||||
#if 0 /* slow, with this can avoid all Py_CompileString above. */
|
||||
/* execute expression to get a value */
|
||||
retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, driver_vars);
|
||||
#else
|
||||
/* evaluate the compiled expression */
|
||||
if (expr_code) {
|
||||
retval = PyEval_EvalCode((void *)expr_code, bpy_pydriver_Dict, driver_vars);
|
||||
}
|
||||
/* evaluate the compiled expression */
|
||||
if (expr_code) {
|
||||
retval = PyEval_EvalCode((void *)expr_code, bpy_pydriver_Dict, driver_vars);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* decref the driver vars first... */
|
||||
Py_DECREF(driver_vars);
|
||||
/* decref the driver vars first... */
|
||||
Py_DECREF(driver_vars);
|
||||
|
||||
/* process the result */
|
||||
if (retval == NULL) {
|
||||
pydriver_error(driver);
|
||||
}
|
||||
else if ((result = PyFloat_AsDouble(retval)) == -1.0 && PyErr_Occurred()) {
|
||||
pydriver_error(driver);
|
||||
Py_DECREF(retval);
|
||||
result = 0.0;
|
||||
}
|
||||
else {
|
||||
/* all fine, make sure the "invalid expression" flag is cleared */
|
||||
driver->flag &= ~DRIVER_FLAG_INVALID;
|
||||
Py_DECREF(retval);
|
||||
}
|
||||
/* process the result */
|
||||
if (retval == NULL) {
|
||||
pydriver_error(driver);
|
||||
}
|
||||
else if ((result = PyFloat_AsDouble(retval)) == -1.0 && PyErr_Occurred()) {
|
||||
pydriver_error(driver);
|
||||
Py_DECREF(retval);
|
||||
result = 0.0;
|
||||
}
|
||||
else {
|
||||
/* all fine, make sure the "invalid expression" flag is cleared */
|
||||
driver->flag &= ~DRIVER_FLAG_INVALID;
|
||||
Py_DECREF(retval);
|
||||
}
|
||||
|
||||
if (use_gil) {
|
||||
PyGILState_Release(gilstate);
|
||||
}
|
||||
if (use_gil) {
|
||||
PyGILState_Release(gilstate);
|
||||
}
|
||||
|
||||
if (isfinite(result)) {
|
||||
return (float)result;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "\tBPY_driver_eval() - driver '%s' evaluates to '%f'\n", driver->expression, result);
|
||||
return 0.0f;
|
||||
}
|
||||
if (isfinite(result)) {
|
||||
return (float)result;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,
|
||||
"\tBPY_driver_eval() - driver '%s' evaluates to '%f'\n",
|
||||
driver->expression,
|
||||
result);
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user