Exemple #1
0
nsresult PyG_Base::HandleNativeGatewayError(const char *szMethodName)
{
	nsresult rc = NS_OK;
	if (PyErr_Occurred()) {
		// The error handling - fairly involved, but worth it as
		// good error reporting is critical for users to know WTF 
		// is going on - especially with TypeErrors etc in their
		// return values (ie, after the Python code has successfully
		// exited, but we encountered errors unpacking their
		// result values for the COM caller - there is literally no 
		// way to catch these exceptions from Python code, as their
		// is no Python function directly on the call-stack)

		// First line of attack in an error is to call-back on the policy.
		// If the callback of the error handler succeeds and returns an
		// integer (for the nsresult), we take no further action.

		// If this callback fails, we log _2_ exceptions - the error
		// handler error, and the original error.

		PRBool bProcessMainError = PR_TRUE; // set to false if our exception handler does its thing!
		PyObject *exc_typ, *exc_val, *exc_tb;
		PyErr_Fetch(&exc_typ, &exc_val, &exc_tb);

		PyObject *err_result = PyObject_CallMethod(m_pPyObject, 
	                                       (char*)"_GatewayException_",
					       (char*)"z(OOO)",
					       szMethodName,
		                               exc_typ ? exc_typ : Py_None, // should never be NULL, but defensive programming...
		                               exc_val ? exc_val : Py_None, // may well be NULL.
					       exc_tb ? exc_tb : Py_None); // may well be NULL.
		if (err_result == NULL) {
			PyXPCOM_LogError("The exception handler _CallMethodException_ failed!\n");
		} else if (err_result == Py_None) {
			// The exception handler has chosen not to do anything with
			// this error, so we still need to print it!
			;
		} else if (PyInt_Check(err_result)) {
			// The exception handler has given us the nresult.
			rc = PyInt_AsLong(err_result);
			bProcessMainError = PR_FALSE;
		} else {
			// The exception handler succeeded, but returned other than
			// int or None.
			PyXPCOM_LogError("The _CallMethodException_ handler returned object of type '%s' - None or an integer expected\n", err_result->ob_type->tp_name);
		}
		Py_XDECREF(err_result);
		PyErr_Restore(exc_typ, exc_val, exc_tb);
		if (bProcessMainError) {
			PyXPCOM_LogError("The function '%s' failed\n", szMethodName);
			rc = PyXPCOM_SetCOMErrorFromPyException();
		}
		PyErr_Clear();
	}
	return rc;
}
// Call back into the Python context
PyObject *
Py_DOMnsISupports::MakeDefaultWrapper(PyObject *pycontext,
                                      PyObject *pyis, 
                                      const nsIID &iid)
{
	NS_PRECONDITION(pyis, "NULL pyobject!");
	PyObject *obIID = NULL;
	PyObject *ret = NULL;

	obIID = Py_nsIID::PyObjectFromIID(iid);
	if (obIID==NULL)
		goto done;

	ret = PyObject_CallMethod(pycontext, "MakeInterfaceResult",
	                          "OO", pyis, obIID);
	if (ret==NULL) goto done;
done:
	if (PyErr_Occurred()) {
		NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!");
		PyXPCOM_LogError("Creating an interface object to be used as a result failed\n");
		PyErr_Clear();
	}
	Py_XDECREF(obIID);
	if (ret==NULL) // eek - error - return the original with no refcount mod.
		ret = pyis; 
	else
		// no error - decref the old object
		Py_DECREF(pyis);
	// return our obISupports.  If NULL, we are really hosed and nothing we can do.
	return ret;
}
Exemple #3
0
// See comments in PyXPCOM.h for why we need this!
void PyXPCOM_MakePendingCalls()
{
	while (1) {
		int rc = Py_MakePendingCalls();
		if (rc == 0)
			break;
		// An exception - just report it as normal.
		// Note that a traceback is very unlikely!
		PyXPCOM_LogError("Unhandled exception detected before entering Python.\n");
		PyErr_Clear();
		// And loop around again until we are told everything is done!
	}
}
// Call back into Python, passing a raw nsIInterface object, getting back
// the object to actually pass to Python.
PyObject *
Py_nsISupports::MakeDefaultWrapper(PyObject *pyis, 
			     const nsIID &iid)
{
	NS_PRECONDITION(pyis, "NULL pyobject!");
	PyObject *obIID = NULL;
	PyObject *args = NULL;
	PyObject *mod = NULL;
	PyObject *ret = NULL;

	obIID = Py_nsIID::PyObjectFromIID(iid);
	if (obIID==NULL)
		goto done;

	if (g_obFuncMakeInterfaceCount==NULL) {
		PyObject *mod = PyImport_ImportModule("xpcom.client");
		if (mod) 
			g_obFuncMakeInterfaceCount = PyObject_GetAttrString(mod, "MakeInterfaceResult");
		Py_XDECREF(mod);
	}
	if (g_obFuncMakeInterfaceCount==NULL) goto done;

	args = Py_BuildValue("OO", pyis, obIID);
	if (args==NULL) goto done;
	ret = PyEval_CallObject(g_obFuncMakeInterfaceCount, args);
done:
	if (PyErr_Occurred()) {
		NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!");
		PyXPCOM_LogError("Creating an interface object to be used as a result failed\n");
		PyErr_Clear();
	}
	Py_XDECREF(mod);
	Py_XDECREF(args);
	Py_XDECREF(obIID);
	if (ret==NULL) // eek - error - return the original with no refcount mod.
		ret = pyis; 
	else
		// no error - decref the old object
		Py_DECREF(pyis);
	// return our obISupports.  If NULL, we are really hosed and nothing we can do.
	return ret;
}
Exemple #5
0
PyG_Base::PyG_Base(PyObject *instance, const nsIID &iid)
{
	// Note that "instance" is the _policy_ instance!!
	PR_AtomicIncrement(&cGateways);
	m_pBaseObject = GetDefaultGateway(instance);
	// m_pWeakRef is an nsCOMPtr and needs no init.

	NS_ABORT_IF_FALSE(!(iid.Equals(NS_GET_IID(nsISupportsWeakReference)) || iid.Equals(NS_GET_IID(nsIWeakReference))),"Should not be creating gateways with weak-ref interfaces");
	m_iid = iid;
	m_pPyObject = instance;
	NS_PRECONDITION(instance, "NULL PyObject for PyXPCOM_XPTStub!");

#ifdef NS_BUILD_REFCNT_LOGGING
	// If XPCOM reference count logging is enabled, then allow us to give the Python class.
	PyObject *realInstance = PyObject_GetAttrString(instance, "_obj_");
	PyObject *r = PyObject_Repr(realInstance);
	const char *szRepr;
	if (r==NULL) {
		PyXPCOM_LogError("Getting the __repr__ of the object failed");
		PyErr_Clear();
		szRepr = "(repr failed!)";
	}
	else
		szRepr = PyString_AsString(r);
	if (szRepr==NULL) szRepr = "";
	int reprOffset = *szRepr=='<' ? 1 : 0;
	static const char *reprPrefix = "component:";
	if (strncmp(reprPrefix, szRepr+reprOffset, strlen(reprPrefix)) == 0)
		reprOffset += strlen(reprPrefix);
	strncpy(refcntLogRepr, szRepr + reprOffset, sizeof(refcntLogRepr)-1);
	refcntLogRepr[sizeof(refcntLogRepr)-1] = '\0';
	// See if we should get rid of the " at 0x12345" portion.
	char *lastPos = strstr(refcntLogRepr, " at ");
	if (lastPos) *lastPos = '\0';
	Py_XDECREF(realInstance);
	Py_XDECREF(r);
#endif // NS_BUILD_REFCNT_LOGGING

#ifdef DEBUG_LIFETIMES
	{
		char *iid_repr;
		nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
		if (iim!=nsnull)
			iim->GetNameForIID(&iid, &iid_repr);
		PyObject *real_instance = PyObject_GetAttrString(instance, "_obj_");
		PyObject *real_repr = PyObject_Repr(real_instance);

		PYXPCOM_LOG_DEBUG("PyG_Base created at %p\n  instance_repr=%s\n  IID=%s\n", this, PyString_AsString(real_repr), iid_repr);
		nsMemory::Free(iid_repr);
		Py_XDECREF(real_instance);
		Py_XDECREF(real_repr);
	}
#endif // DEBUG_LIFETIMES
	Py_XINCREF(instance); // instance should never be NULL - but whats an X between friends!

	PyXPCOM_DLLAddRef();

#ifdef DEBUG_FULL
	LogF("PyGatewayBase: created %s", m_pPyObject ? m_pPyObject->ob_type->tp_name : "<NULL>");
#endif
}
Exemple #6
0
NS_IMETHODIMP
PyG_Base::QueryInterface(REFNSIID iid, void** ppv)
{
#ifdef PYXPCOM_DEBUG_FULL
	{
		char *sziid = iid.ToString();
		LogF("PyGatewayBase::QueryInterface: %s", sziid);
		Allocator::Free(sziid);
	}
#endif
	NS_PRECONDITION(ppv, "NULL pointer");
	if (ppv==nsnull)
		return NS_ERROR_NULL_POINTER;
	*ppv = nsnull;
	// If one of our native interfaces (but NOT nsISupports if we have a base)
	// return this.
	// It is important is that nsISupports come from the base object
	// to ensure that we live by XPCOM identity rules (other interfaces need
	// not abide by this rule - only nsISupports.)
	if ( (m_pBaseObject==NULL || !iid.Equals(NS_GET_IID(nsISupports)))
	   && (*ppv=ThisAsIID(iid)) != NULL ) {
		AddRef();
		return NS_OK;
	}
	// If we have a "base object", then we need to delegate _every_ remaining 
	// QI to it.
	if (m_pBaseObject != NULL)
		return m_pBaseObject->QueryInterface(iid, ppv);

	// Call the Python policy to see if it (says it) supports the interface
	PRBool supports = PR_FALSE;
	{ // temp scope for Python lock
		CEnterLeavePython celp;

		PyObject * ob = Py_nsIID::PyObjectFromIID(iid);
		// must say this is an 'internal' call, else we recurse QI into
		// oblivion.
		PyObject * this_interface_ob = Py_nsISupports::PyObjectFromInterface(
		                                       (nsXPTCStubBase *)this,
		                                       iid, PR_FALSE, PR_TRUE);
		if ( !ob || !this_interface_ob) {
			Py_XDECREF(ob);
			Py_XDECREF(this_interface_ob);
			return NS_ERROR_OUT_OF_MEMORY;
		}

		PyObject *result = PyObject_CallMethod(m_pPyObject, (char*)"_QueryInterface_",
		                                                    (char*)"OO", 
		                                                    this_interface_ob, ob);
		Py_DECREF(ob);
		Py_DECREF(this_interface_ob);

		if ( result ) {
			if (Py_nsISupports::InterfaceFromPyObject(result, iid, (nsISupports **)ppv, PR_TRUE)) {
				// If OK, but NULL, _QI_ returned None, which simply means
				// "no such interface"
				supports = (*ppv!=NULL);
				// result has been QI'd and AddRef'd all ready for return.
			} else {
				// Dump this message and any Python exception before
				// reporting the fact that QI failed - this error
				// may provide clues!
				PyXPCOM_LogError("The _QueryInterface_ method returned an object of type '%s', but an interface was expected\n", result->ob_type->tp_name);
				// supports remains false
			}
			Py_DECREF(result);
		} else {
			NS_ABORT_IF_FALSE(PyErr_Occurred(), "Got NULL result, but no Python error flagged!");
			NS_WARN_IF_FALSE(!supports, "Have failure with success flag set!");
			PyXPCOM_LogError("The _QueryInterface_ processing failed.\n");
			// supports remains false.
			// We have reported the error, and are returning to COM,
			// so we should clear it.
			PyErr_Clear();
		}
	} // end of temp scope for Python lock - lock released here!
	if ( !supports )
		return NS_ERROR_NO_INTERFACE;
	return NS_OK;
}
Exemple #7
0
// Call back into Python, passing a raw nsIInterface object, getting back
// the object to actually use as the gateway parameter for this interface.
// For example, it is expected that the policy will wrap the interface
// object in one of the xpcom.client.Interface objects, allowing 
// natural usage of the interface from Python clients.
// Note that piid will usually be NULL - this is because the runtime
// reflection interfaces dont provide this information to me.
// In this case, the Python code may choose to lookup the complete
// interface info to obtain the IID.
// It is expected (but should not be assumed) that the method info
// or the IID will be NULL.
// Worst case, the code should provide a wrapper for the nsiSupports interface,
// so at least the user can simply QI the object.
PyObject *
PyG_Base::MakeInterfaceParam(nsISupports *pis, 
			     const nsIID *piid, 
			     int methodIndex /* = -1 */,
			     const XPTParamDescriptor *d /* = NULL */, 
			     int paramIndex /* = -1 */)
{
	if (pis==NULL) {
		Py_INCREF(Py_None);
		return Py_None;
	}
	// This condition is true today, but not necessarily so.
	// But if it ever triggers, the poor Python code has no real hope
	// of returning something useful, so we should at least do our
	// best to provide the useful data.
	NS_WARN_IF_FALSE( ((piid != NULL) ^ (d != NULL)) == 1, "No information on the interface available - Python's gunna have a hard time doing much with it!");
	PyObject *obIID = NULL;
	PyObject *obISupports = NULL;
	PyObject *obParamDesc = NULL;
	PyObject *result = NULL;

	// get the basic interface first, as if we fail, we can try and use this.
	// If we don't know the IID, we must explicitly query for nsISupports.
	nsCOMPtr<nsISupports> piswrap;
	nsIID iid_check;
	if (piid) {
		iid_check = *piid;
		piswrap = pis;
	} else {
		iid_check = NS_GET_IID(nsISupports);
		pis->QueryInterface(iid_check, getter_AddRefs(piswrap));
	}

	obISupports = Py_nsISupports::PyObjectFromInterface(piswrap, iid_check, PR_FALSE);
	if (!obISupports)
		goto done;
	if (piid==NULL) {
		obIID = Py_None;
		Py_INCREF(Py_None);
	} else
		obIID = Py_nsIID::PyObjectFromIID(*piid);
	if (obIID==NULL)
		goto done;
	obParamDesc = PyObject_FromXPTParamDescriptor(d);
	if (obParamDesc==NULL)
		goto done;

	result = PyObject_CallMethod(m_pPyObject, 
	                               (char*)"_MakeInterfaceParam_",
				       (char*)"OOiOi",
				       obISupports,
				       obIID,
				       methodIndex,
				       obParamDesc,
				       paramIndex);
done:
	if (PyErr_Occurred()) {
		NS_WARN_IF_FALSE(result==NULL, "Have an error, but also a result!");
		PyXPCOM_LogError("Wrapping an interface object for the gateway failed\n");
	}
	Py_XDECREF(obIID);
	Py_XDECREF(obParamDesc);
	if (result==NULL) { // we had an error.
		PyErr_Clear(); // but are not reporting it back to Python itself!
		// return our obISupports.  If NULL, we are really hosed and nothing we can do.
		return obISupports;
	}
	// Dont need to return this - we have a better result.
	Py_XDECREF(obISupports);
	return result;
}