Browse Source

interrogate: fix refcount trouble assigning PyObject* properties

In particular, this fixes accessing PythonTask.__dict__
rdb 6 years ago
parent
commit
8e4add0326

+ 16 - 3
dtool/src/interrogate/functionRemap.cxx

@@ -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) {

+ 5 - 1
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -5979,7 +5979,11 @@ write_function_instance(ostream &out, FunctionRemap *remap,
       indent(out, indent_level) << "}\n";
       indent(out, indent_level) << "}\n";
     }
     }
 
 
-    return_expr = manage_return_value(out, indent_level, remap, "return_value");
+    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 = remap->_return_type->temporary_to_return(return_expr);
     return_expr = remap->_return_type->temporary_to_return(return_expr);
   }
   }
 
 

+ 13 - 0
dtool/src/interrogatedb/py_panda.I

@@ -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.
  */
  */

+ 2 - 0
dtool/src/interrogatedb/py_panda.h

@@ -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.
  */
  */