From 3307496811236b9f522c1e198779f6d4dc89517a Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Tue, 24 Sep 2019 12:29:37 -0700 Subject: [PATCH 1/2] added parameter validation to PyObject methods --- src/embed_tests/TestPyObject.cs | 6 ++ src/runtime/pyint.cs | 6 +- src/runtime/pyobject.cs | 155 +++++++++++++++++++++++++++++--- 3 files changed, 152 insertions(+), 15 deletions(-) diff --git a/src/embed_tests/TestPyObject.cs b/src/embed_tests/TestPyObject.cs index 65ac20e9a..d4952d4a3 100644 --- a/src/embed_tests/TestPyObject.cs +++ b/src/embed_tests/TestPyObject.cs @@ -57,5 +57,11 @@ def add(self, x, y): Assert.IsTrue(memberNames.Contains(expectedName), "Could not find member '{0}'.", expectedName); } } + + [Test] + public void InvokeNull() { + var list = PythonEngine.Eval("list"); + Assert.Throws(() => list.Invoke(new PyObject[] {null})); + } } } diff --git a/src/runtime/pyint.cs b/src/runtime/pyint.cs index f6911d9d7..217cf7e20 100644 --- a/src/runtime/pyint.cs +++ b/src/runtime/pyint.cs @@ -62,7 +62,7 @@ public PyInt(int value) /// Creates a new Python int from a uint32 value. /// [CLSCompliant(false)] - public PyInt(uint value) : base(IntPtr.Zero) + public PyInt(uint value) { obj = Runtime.PyInt_FromInt64(value); Runtime.CheckExceptionOccurred(); @@ -75,7 +75,7 @@ public PyInt(uint value) : base(IntPtr.Zero) /// /// Creates a new Python int from an int64 value. /// - public PyInt(long value) : base(IntPtr.Zero) + public PyInt(long value) { obj = Runtime.PyInt_FromInt64(value); Runtime.CheckExceptionOccurred(); @@ -89,7 +89,7 @@ public PyInt(long value) : base(IntPtr.Zero) /// Creates a new Python int from a uint64 value. /// [CLSCompliant(false)] - public PyInt(ulong value) : base(IntPtr.Zero) + public PyInt(ulong value) { obj = Runtime.PyInt_FromInt64((long)value); Runtime.CheckExceptionOccurred(); diff --git a/src/runtime/pyobject.cs b/src/runtime/pyobject.cs index c86504802..53a9a512b 100644 --- a/src/runtime/pyobject.cs +++ b/src/runtime/pyobject.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Dynamic; +using System.Linq; using System.Linq.Expressions; namespace Python.Runtime @@ -43,6 +44,8 @@ public class PyObject : DynamicObject, IEnumerable, IPyDisposable /// public PyObject(IntPtr ptr) { + if (ptr == IntPtr.Zero) throw new ArgumentNullException(nameof(ptr)); + obj = ptr; #if TRACE_ALLOC Traceback = new StackTrace(1); @@ -51,7 +54,7 @@ public PyObject(IntPtr ptr) // Protected default constructor to allow subclasses to manage // initialization in different ways as appropriate. - + [Obsolete("Please, always use PyObject(IntPtr)")] protected PyObject() { #if TRACE_ALLOC @@ -209,6 +212,8 @@ public PyObject GetPythonType() /// public bool TypeCheck(PyObject typeOrClass) { + if (typeOrClass == null) throw new ArgumentNullException(nameof(typeOrClass)); + return Runtime.PyObject_TypeCheck(obj, typeOrClass.obj); } @@ -221,6 +226,8 @@ public bool TypeCheck(PyObject typeOrClass) /// public bool HasAttr(string name) { + if (name == null) throw new ArgumentNullException(nameof(name)); + return Runtime.PyObject_HasAttrString(obj, name) != 0; } @@ -234,6 +241,8 @@ public bool HasAttr(string name) /// public bool HasAttr(PyObject name) { + if (name == null) throw new ArgumentNullException(nameof(name)); + return Runtime.PyObject_HasAttr(obj, name.obj) != 0; } @@ -247,6 +256,8 @@ public bool HasAttr(PyObject name) /// public PyObject GetAttr(string name) { + if (name == null) throw new ArgumentNullException(nameof(name)); + IntPtr op = Runtime.PyObject_GetAttrString(obj, name); if (op == IntPtr.Zero) { @@ -257,17 +268,41 @@ public PyObject GetAttr(string name) /// - /// GetAttr Method + /// GetAttr Method. Returns fallback value if getting attribute fails for any reason. /// /// /// Returns the named attribute of the Python object, or the given /// default object if the attribute access fails. /// + [Obsolete("This method ignores any Python exceptions, and should not be used. Use GetAttrOrElse.")] public PyObject GetAttr(string name, PyObject _default) { + if (name == null) throw new ArgumentNullException(nameof(name)); + + IntPtr op = Runtime.PyObject_GetAttrString(obj, name); + if (op == IntPtr.Zero) + { + Runtime.PyErr_Clear(); + return _default; + } + return new PyObject(op); + } + + /// + /// Gets the specified attribute. If attribute is not found, returns the fallback value. + /// + public PyObject GetAttrOrElse(string name, PyObject _default) + { + if (name == null) throw new ArgumentNullException(nameof(name)); + IntPtr op = Runtime.PyObject_GetAttrString(obj, name); if (op == IntPtr.Zero) { + if (!Exceptions.ExceptionMatches(Exceptions.AttributeError)) + { + throw new PythonException(); + } + Runtime.PyErr_Clear(); return _default; } @@ -285,6 +320,8 @@ public PyObject GetAttr(string name, PyObject _default) /// public PyObject GetAttr(PyObject name) { + if (name == null) throw new ArgumentNullException(nameof(name)); + IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj); if (op == IntPtr.Zero) { @@ -304,6 +341,8 @@ public PyObject GetAttr(PyObject name) /// public PyObject GetAttr(PyObject name, PyObject _default) { + if (name == null) throw new ArgumentNullException(nameof(name)); + IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj); if (op == IntPtr.Zero) { @@ -323,6 +362,9 @@ public PyObject GetAttr(PyObject name, PyObject _default) /// public void SetAttr(string name, PyObject value) { + if (name == null) throw new ArgumentNullException(nameof(name)); + if (value == null) throw new ArgumentNullException(nameof(value)); + int r = Runtime.PyObject_SetAttrString(obj, name, value.obj); if (r < 0) { @@ -341,6 +383,9 @@ public void SetAttr(string name, PyObject value) /// public void SetAttr(PyObject name, PyObject value) { + if (name == null) throw new ArgumentNullException(nameof(name)); + if (value == null) throw new ArgumentNullException(nameof(value)); + int r = Runtime.PyObject_SetAttr(obj, name.obj, value.obj); if (r < 0) { @@ -358,6 +403,8 @@ public void SetAttr(PyObject name, PyObject value) /// public void DelAttr(string name) { + if (name == null) throw new ArgumentNullException(nameof(name)); + int r = Runtime.PyObject_SetAttrString(obj, name, IntPtr.Zero); if (r < 0) { @@ -376,6 +423,8 @@ public void DelAttr(string name) /// public void DelAttr(PyObject name) { + if (name == null) throw new ArgumentNullException(nameof(name)); + int r = Runtime.PyObject_SetAttr(obj, name.obj, IntPtr.Zero); if (r < 0) { @@ -394,6 +443,8 @@ public void DelAttr(PyObject name) /// public virtual PyObject GetItem(PyObject key) { + if (key == null) throw new ArgumentNullException(nameof(key)); + IntPtr op = Runtime.PyObject_GetItem(obj, key.obj); if (op == IntPtr.Zero) { @@ -413,6 +464,8 @@ public virtual PyObject GetItem(PyObject key) /// public virtual PyObject GetItem(string key) { + if (key == null) throw new ArgumentNullException(nameof(key)); + using (var pyKey = new PyString(key)) { return GetItem(pyKey); @@ -447,6 +500,9 @@ public virtual PyObject GetItem(int index) /// public virtual void SetItem(PyObject key, PyObject value) { + if (key == null) throw new ArgumentNullException(nameof(key)); + if (value == null) throw new ArgumentNullException(nameof(value)); + int r = Runtime.PyObject_SetItem(obj, key.obj, value.obj); if (r < 0) { @@ -465,6 +521,9 @@ public virtual void SetItem(PyObject key, PyObject value) /// public virtual void SetItem(string key, PyObject value) { + if (key == null) throw new ArgumentNullException(nameof(key)); + if (value == null) throw new ArgumentNullException(nameof(value)); + using (var pyKey = new PyString(key)) { SetItem(pyKey, value); @@ -482,6 +541,8 @@ public virtual void SetItem(string key, PyObject value) /// public virtual void SetItem(int index, PyObject value) { + if (value == null) throw new ArgumentNullException(nameof(value)); + using (var pyindex = new PyInt(index)) { SetItem(pyindex, value); @@ -499,6 +560,8 @@ public virtual void SetItem(int index, PyObject value) /// public virtual void DelItem(PyObject key) { + if (key == null) throw new ArgumentNullException(nameof(key)); + int r = Runtime.PyObject_DelItem(obj, key.obj); if (r < 0) { @@ -517,6 +580,8 @@ public virtual void DelItem(PyObject key) /// public virtual void DelItem(string key) { + if (key == null) throw new ArgumentNullException(nameof(key)); + using (var pyKey = new PyString(key)) { DelItem(pyKey); @@ -639,10 +704,13 @@ public IEnumerator GetEnumerator() /// /// /// Invoke the callable object with the given arguments, passed as a - /// PyObject[]. A PythonException is raised if the invokation fails. + /// PyObject[]. A PythonException is raised if the invocation fails. /// public PyObject Invoke(params PyObject[] args) { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (args.Contains(null)) throw new ArgumentNullException(); + var t = new PyTuple(args); IntPtr r = Runtime.PyObject_Call(obj, t.obj, IntPtr.Zero); t.Dispose(); @@ -659,10 +727,12 @@ public PyObject Invoke(params PyObject[] args) /// /// /// Invoke the callable object with the given arguments, passed as a - /// Python tuple. A PythonException is raised if the invokation fails. + /// Python tuple. A PythonException is raised if the invocation fails. /// public PyObject Invoke(PyTuple args) { + if (args == null) throw new ArgumentNullException(nameof(args)); + IntPtr r = Runtime.PyObject_Call(obj, args.obj, IntPtr.Zero); if (r == IntPtr.Zero) { @@ -677,12 +747,15 @@ public PyObject Invoke(PyTuple args) /// /// /// Invoke the callable object with the given positional and keyword - /// arguments. A PythonException is raised if the invokation fails. + /// arguments. A PythonException is raised if the invocation fails. /// public PyObject Invoke(PyObject[] args, PyDict kw) { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (args.Contains(null)) throw new ArgumentNullException(); + var t = new PyTuple(args); - IntPtr r = Runtime.PyObject_Call(obj, t.obj, kw != null ? kw.obj : IntPtr.Zero); + IntPtr r = Runtime.PyObject_Call(obj, t.obj, kw?.obj ?? IntPtr.Zero); t.Dispose(); if (r == IntPtr.Zero) { @@ -697,11 +770,13 @@ public PyObject Invoke(PyObject[] args, PyDict kw) /// /// /// Invoke the callable object with the given positional and keyword - /// arguments. A PythonException is raised if the invokation fails. + /// arguments. A PythonException is raised if the invocation fails. /// public PyObject Invoke(PyTuple args, PyDict kw) { - IntPtr r = Runtime.PyObject_Call(obj, args.obj, kw != null ? kw.obj : IntPtr.Zero); + if (args == null) throw new ArgumentNullException(nameof(args)); + + IntPtr r = Runtime.PyObject_Call(obj, args.obj, kw?.obj ?? IntPtr.Zero); if (r == IntPtr.Zero) { throw new PythonException(); @@ -715,10 +790,14 @@ public PyObject Invoke(PyTuple args, PyDict kw) /// /// /// Invoke the named method of the object with the given arguments. - /// A PythonException is raised if the invokation is unsuccessful. + /// A PythonException is raised if the invocation is unsuccessful. /// public PyObject InvokeMethod(string name, params PyObject[] args) { + if (name == null) throw new ArgumentNullException(nameof(name)); + if (args == null) throw new ArgumentNullException(nameof(args)); + if (args.Contains(null)) throw new ArgumentNullException(); + PyObject method = GetAttr(name); PyObject result = method.Invoke(args); method.Dispose(); @@ -731,10 +810,51 @@ public PyObject InvokeMethod(string name, params PyObject[] args) /// /// /// Invoke the named method of the object with the given arguments. - /// A PythonException is raised if the invokation is unsuccessful. + /// A PythonException is raised if the invocation is unsuccessful. /// public PyObject InvokeMethod(string name, PyTuple args) { + if (name == null) throw new ArgumentNullException(nameof(name)); + if (args == null) throw new ArgumentNullException(nameof(args)); + + PyObject method = GetAttr(name); + PyObject result = method.Invoke(args); + method.Dispose(); + return result; + } + + /// + /// InvokeMethod Method + /// + /// + /// Invoke the named method of the object with the given arguments. + /// A PythonException is raised if the invocation is unsuccessful. + /// + public PyObject InvokeMethod(PyObject name, params PyObject[] args) + { + if (name == null) throw new ArgumentNullException(nameof(name)); + if (args == null) throw new ArgumentNullException(nameof(args)); + if (args.Contains(null)) throw new ArgumentNullException(); + + PyObject method = GetAttr(name); + PyObject result = method.Invoke(args); + method.Dispose(); + return result; + } + + + /// + /// InvokeMethod Method + /// + /// + /// Invoke the named method of the object with the given arguments. + /// A PythonException is raised if the invocation is unsuccessful. + /// + public PyObject InvokeMethod(PyObject name, PyTuple args) + { + if (name == null) throw new ArgumentNullException(nameof(name)); + if (args == null) throw new ArgumentNullException(nameof(args)); + PyObject method = GetAttr(name); PyObject result = method.Invoke(args); method.Dispose(); @@ -748,10 +868,14 @@ public PyObject InvokeMethod(string name, PyTuple args) /// /// Invoke the named method of the object with the given arguments /// and keyword arguments. Keyword args are passed as a PyDict object. - /// A PythonException is raised if the invokation is unsuccessful. + /// A PythonException is raised if the invocation is unsuccessful. /// public PyObject InvokeMethod(string name, PyObject[] args, PyDict kw) { + if (name == null) throw new ArgumentNullException(nameof(name)); + if (args == null) throw new ArgumentNullException(nameof(args)); + if (args.Contains(null)) throw new ArgumentNullException(); + PyObject method = GetAttr(name); PyObject result = method.Invoke(args, kw); method.Dispose(); @@ -765,10 +889,13 @@ public PyObject InvokeMethod(string name, PyObject[] args, PyDict kw) /// /// Invoke the named method of the object with the given arguments /// and keyword arguments. Keyword args are passed as a PyDict object. - /// A PythonException is raised if the invokation is unsuccessful. + /// A PythonException is raised if the invocation is unsuccessful. /// public PyObject InvokeMethod(string name, PyTuple args, PyDict kw) { + if (name == null) throw new ArgumentNullException(nameof(name)); + if (args == null) throw new ArgumentNullException(nameof(args)); + PyObject method = GetAttr(name); PyObject result = method.Invoke(args, kw); method.Dispose(); @@ -785,6 +912,8 @@ public PyObject InvokeMethod(string name, PyTuple args, PyDict kw) /// public bool IsInstance(PyObject typeOrClass) { + if (typeOrClass == null) throw new ArgumentNullException(nameof(typeOrClass)); + int r = Runtime.PyObject_IsInstance(obj, typeOrClass.obj); if (r < 0) { @@ -804,6 +933,8 @@ public bool IsInstance(PyObject typeOrClass) /// public bool IsSubclass(PyObject typeOrClass) { + if (typeOrClass == null) throw new ArgumentNullException(nameof(typeOrClass)); + int r = Runtime.PyObject_IsSubclass(obj, typeOrClass.obj); if (r < 0) { From 91c701065641db5465850e142c8fbe0fa756ac13 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Fri, 31 Jan 2020 12:54:22 -0800 Subject: [PATCH 2/2] removed GetAttrOrElse from this PR --- src/runtime/pyobject.cs | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/runtime/pyobject.cs b/src/runtime/pyobject.cs index 53a9a512b..8ae99ecd0 100644 --- a/src/runtime/pyobject.cs +++ b/src/runtime/pyobject.cs @@ -274,7 +274,6 @@ public PyObject GetAttr(string name) /// Returns the named attribute of the Python object, or the given /// default object if the attribute access fails. /// - [Obsolete("This method ignores any Python exceptions, and should not be used. Use GetAttrOrElse.")] public PyObject GetAttr(string name, PyObject _default) { if (name == null) throw new ArgumentNullException(nameof(name)); @@ -288,27 +287,6 @@ public PyObject GetAttr(string name, PyObject _default) return new PyObject(op); } - /// - /// Gets the specified attribute. If attribute is not found, returns the fallback value. - /// - public PyObject GetAttrOrElse(string name, PyObject _default) - { - if (name == null) throw new ArgumentNullException(nameof(name)); - - IntPtr op = Runtime.PyObject_GetAttrString(obj, name); - if (op == IntPtr.Zero) - { - if (!Exceptions.ExceptionMatches(Exceptions.AttributeError)) - { - throw new PythonException(); - } - - Runtime.PyErr_Clear(); - return _default; - } - return new PyObject(op); - } - /// /// GetAttr Method