summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Wieser <wieser.eric@gmail.com>2020-01-27 22:52:48 +0000
committerGitHub <noreply@github.com>2020-01-27 22:52:48 +0000
commit6d889e7eca0f7ae6d640c380bd0b604e6530f049 (patch)
tree70909ea235d77703909f65fcb9da0775037e9745
parent7b7197517f31bdfdf6fb1d99944002c90568d705 (diff)
parentcf688edd6777881aae5af233aa538b7fd9b6c361 (diff)
downloadnumpy-6d889e7eca0f7ae6d640c380bd0b604e6530f049.tar.gz
Merge pull request #15446 from eric-wieser/reject-garbage-arguments
BUG: Reject nonsense arguments to scalar constructors
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c6
-rw-r--r--numpy/core/src/multiarray/scalartypes.c.src28
-rw-r--r--numpy/core/tests/test_scalar_ctors.py35
3 files changed, 53 insertions, 16 deletions
diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c
index 11e0bc44d..c2e597385 100644
--- a/numpy/core/src/multiarray/multiarraymodule.c
+++ b/numpy/core/src/multiarray/multiarraymodule.c
@@ -3287,12 +3287,14 @@ array_datetime_data(PyObject *NPY_UNUSED(dummy), PyObject *args)
}
meta = get_datetime_metadata_from_dtype(dtype);
- Py_DECREF(dtype);
if (meta == NULL) {
+ Py_DECREF(dtype);
return NULL;
}
- return convert_datetime_metadata_to_tuple(meta);
+ PyObject *res = convert_datetime_metadata_to_tuple(meta);
+ Py_DECREF(dtype);
+ return res;
}
/*
diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src
index 9b53fea6f..67c268a9b 100644
--- a/numpy/core/src/multiarray/scalartypes.c.src
+++ b/numpy/core/src/multiarray/scalartypes.c.src
@@ -2537,7 +2537,9 @@ object_arrtype_dealloc(PyObject *v)
PyTypeObject *sup = (PyTypeObject *)PyTuple_GET_ITEM(cls.tp_bases, num); \
robj = sup->tp_new(type, args, kwds); \
if (robj != NULL) goto finish; \
- if (PyTuple_GET_SIZE(args) != 1) return NULL; \
+ if (PyTuple_GET_SIZE(args) != 1 || (kwds && PyDict_Size(kwds) != 0)) { \
+ return NULL; \
+ } \
PyErr_Clear(); \
/* now do default conversion */
@@ -2558,17 +2560,12 @@ object_arrtype_dealloc(PyObject *v)
#if defined(_@TYPE@_IS_OBJECT)
#define _NPY_UNUSED_TYPE NPY_UNUSED
- #define _NPY_UNUSED_KWDS NPY_UNUSED
-#elif defined(_@TYPE@_IS_UNICODE) || defined(_@TYPE@_IS_STRING) || defined(_@TYPE@_IS_DOUBLE)
- #define _NPY_UNUSED_TYPE
- #define _NPY_UNUSED_KWDS
#else
#define _NPY_UNUSED_TYPE
- #define _NPY_UNUSED_KWDS NPY_UNUSED
#endif
static PyObject *
-@name@_arrtype_new(PyTypeObject *_NPY_UNUSED_TYPE(type), PyObject *args, PyObject *_NPY_UNUSED_KWDS(kwds))
+@name@_arrtype_new(PyTypeObject *_NPY_UNUSED_TYPE(type), PyObject *args, PyObject *kwds)
{
PyObject *obj = NULL;
PyObject *robj;
@@ -2586,7 +2583,8 @@ static PyObject *
#endif
/* TODO: include type name in error message, which is not @name@ */
- if (!PyArg_ParseTuple(args, "|O", &obj)) {
+ char *kwnames[] = {"", NULL}; /* positional-only */
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwnames, &obj)) {
return NULL;
}
typecode = PyArray_DescrFromType(NPY_@TYPE@);
@@ -2699,8 +2697,8 @@ static PyObject *
PyObject *obj = NULL, *meta_obj = NULL;
Py@Name@ScalarObject *ret;
- /* TODO: include type name in error message, which is not @name@ */
- if (!PyArg_ParseTuple(args, "|OO", &obj, &meta_obj)) {
+ char *kwnames[] = {"", "", NULL}; /* positional-only */
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwnames, &obj, &meta_obj)) {
return NULL;
}
@@ -2753,12 +2751,13 @@ static PyObject *
/* bool->tp_new only returns Py_True or Py_False */
static PyObject *
-bool_arrtype_new(PyTypeObject *NPY_UNUSED(type), PyObject *args, PyObject *NPY_UNUSED(kwds))
+bool_arrtype_new(PyTypeObject *NPY_UNUSED(type), PyObject *args, PyObject *kwds)
{
PyObject *obj = NULL;
PyArrayObject *arr;
- if (!PyArg_ParseTuple(args, "|O:bool_", &obj)) {
+ char *kwnames[] = {"", NULL}; /* positional-only */
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:bool_", kwnames, &obj)) {
return NULL;
}
if (obj == NULL) {
@@ -2897,12 +2896,13 @@ NPY_NO_EXPORT PyNumberMethods bool_arrtype_as_number = {
};
static PyObject *
-void_arrtype_new(PyTypeObject *type, PyObject *args, PyObject *NPY_UNUSED(kwds))
+void_arrtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *obj, *arr;
PyObject *new = NULL;
- if (!PyArg_ParseTuple(args, "O:void", &obj)) {
+ char *kwnames[] = {"", NULL}; /* positional-only */
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:void", kwnames, &obj)) {
return NULL;
}
/*
diff --git a/numpy/core/tests/test_scalar_ctors.py b/numpy/core/tests/test_scalar_ctors.py
index 2de5084b6..7645a0853 100644
--- a/numpy/core/tests/test_scalar_ctors.py
+++ b/numpy/core/tests/test_scalar_ctors.py
@@ -1,6 +1,8 @@
"""
Test the scalar constructors, which also do type-coercion
"""
+import pytest
+
import numpy as np
from numpy.testing import (
assert_equal, assert_almost_equal, assert_warns,
@@ -37,6 +39,39 @@ class TestFromString:
assert_equal(flongdouble, -np.inf)
+class TestExtraArgs:
+ def test_superclass(self):
+ # try both positional and keyword arguments
+ s = np.str_(b'\\x61', encoding='unicode-escape')
+ assert s == 'a'
+ s = np.str_(b'\\x61', 'unicode-escape')
+ assert s == 'a'
+
+ # previously this would return '\\xx'
+ with pytest.raises(UnicodeDecodeError):
+ np.str_(b'\\xx', encoding='unicode-escape')
+ with pytest.raises(UnicodeDecodeError):
+ np.str_(b'\\xx', 'unicode-escape')
+
+ # superclass fails, but numpy succeeds
+ assert np.bytes_(-2) == b'-2'
+
+ def test_datetime(self):
+ dt = np.datetime64('2000-01', ('M', 2))
+ assert np.datetime_data(dt) == ('M', 2)
+
+ with pytest.raises(TypeError):
+ np.datetime64('2000', garbage=True)
+
+ def test_bool(self):
+ with pytest.raises(TypeError):
+ np.bool(False, garbage=True)
+
+ def test_void(self):
+ with pytest.raises(TypeError):
+ np.void(b'test', garbage=True)
+
+
class TestFromInt:
def test_intp(self):
# Ticket #99