interrogate: fix refcount trouble assigning PyObject* properties

In particular, this fixes accessing PythonTask.__dict__
This commit is contained in:
rdb 2019-03-04 16:46:28 +01:00
parent 45778b9e9f
commit 8e4add0326
4 changed files with 36 additions and 4 deletions

View File

@ -397,17 +397,25 @@ get_call_str(const string &container, const vector_string &pexprs) const {
} }
// It's not possible to assign arrays in C++, we have to copy them. // It's not possible to assign arrays in C++, we have to copy them.
CPPArrayType *array_type = _parameters[_first_true_parameter]._remap->get_orig_type()->as_array_type(); bool paren_close = false;
CPPType *param_type = _parameters[_first_true_parameter]._remap->get_orig_type();
CPPArrayType *array_type = param_type->as_array_type();
if (array_type != nullptr) { if (array_type != nullptr) {
call << "std::copy(" << expr << ", " << expr << " + " << *array_type->_bounds << ", "; call << "std::copy(" << expr << ", " << expr << " + " << *array_type->_bounds << ", ";
} else { paren_close = true;
}
else if (TypeManager::is_pointer_to_PyObject(param_type)) {
call << "Dtool_Assign_PyObject(" << expr << ", ";
paren_close = true;
}
else {
call << expr << " = "; call << expr << " = ";
} }
_parameters[_first_true_parameter]._remap->pass_parameter(call, _parameters[_first_true_parameter]._remap->pass_parameter(call,
get_parameter_expr(_first_true_parameter, pexprs)); get_parameter_expr(_first_true_parameter, pexprs));
if (array_type != nullptr) { if (paren_close) {
call << ')'; call << ')';
} }
@ -772,6 +780,11 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
_return_value_destructor = builder.get_destructor_for(return_meat_type); _return_value_destructor = builder.get_destructor_for(return_meat_type);
} }
if (_type == T_getter && TypeManager::is_pointer_to_PyObject(return_type)) {
_manage_reference_count = true;
_return_value_needs_management = true;
}
// Check for a special meaning by name and signature. // Check for a special meaning by name and signature.
size_t first_param = 0; size_t first_param = 0;
if (_has_this) { if (_has_this) {

View File

@ -5979,7 +5979,11 @@ write_function_instance(ostream &out, FunctionRemap *remap,
indent(out, indent_level) << "}\n"; indent(out, indent_level) << "}\n";
} }
if (TypeManager::is_pointer_to_PyObject(remap->_return_type->get_orig_type())) {
indent(out, indent_level) << "Py_XINCREF(return_value);\n";
} else {
return_expr = manage_return_value(out, indent_level, remap, "return_value"); return_expr = manage_return_value(out, indent_level, remap, "return_value");
}
return_expr = remap->_return_type->temporary_to_return(return_expr); return_expr = remap->_return_type->temporary_to_return(return_expr);
} }

View File

@ -90,6 +90,19 @@ INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, i
Py_RETURN_RICHCOMPARE(cmpval, 0, op); Py_RETURN_RICHCOMPARE(cmpval, 0, op);
} }
/**
* Utility function for assigning a PyObject pointer while managing refcounts.
*/
ALWAYS_INLINE void
Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value) {
PyObject *prev_value = ptr;
if (prev_value != value) {
Py_XINCREF(value);
ptr = value;
Py_XDECREF(prev_value);
}
}
/** /**
* Converts the enum value to a C long. * Converts the enum value to a C long.
*/ */

View File

@ -238,6 +238,8 @@ EXPCL_PYPANDA PyObject *_Dtool_Return(PyObject *value);
#define Dtool_Return(value) _Dtool_Return(value) #define Dtool_Return(value) _Dtool_Return(value)
#endif #endif
ALWAYS_INLINE void Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value);
/** /**
* Wrapper around Python 3.4's enum library, which does not have a C API. * Wrapper around Python 3.4's enum library, which does not have a C API.
*/ */