aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Objects
diff options
context:
space:
mode:
Diffstat (limited to 'Objects')
-rw-r--r--Objects/codeobject.c168
-rw-r--r--Objects/dictobject.c17
-rw-r--r--Objects/funcobject.c54
-rw-r--r--Objects/longobject.c4
-rw-r--r--Objects/unicodeobject.c33
5 files changed, 222 insertions, 54 deletions
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 92eaf5e00bc..4f06a36a130 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -1955,12 +1955,130 @@ finally:
}
+int
+_PyCode_CheckNoInternalState(PyCodeObject *co, const char **p_errmsg)
+{
+ const char *errmsg = NULL;
+ // We don't worry about co_executors, co_instrumentation,
+ // or co_monitoring. They are essentially ephemeral.
+ if (co->co_extra != NULL) {
+ errmsg = "only basic code objects are supported";
+ }
+
+ if (errmsg != NULL) {
+ if (p_errmsg != NULL) {
+ *p_errmsg = errmsg;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+int
+_PyCode_CheckNoExternalState(PyCodeObject *co, _PyCode_var_counts_t *counts,
+ const char **p_errmsg)
+{
+ const char *errmsg = NULL;
+ assert(counts->locals.hidden.total == 0);
+ if (counts->numfree > 0) { // It's a closure.
+ errmsg = "closures not supported";
+ }
+ else if (counts->unbound.globals.numglobal > 0) {
+ errmsg = "globals not supported";
+ }
+ else if (counts->unbound.globals.numbuiltin > 0
+ && counts->unbound.globals.numunknown > 0)
+ {
+ errmsg = "globals not supported";
+ }
+ // Otherwise we don't check counts.unbound.globals.numunknown since we can't
+ // distinguish beween globals and builtins here.
+
+ if (errmsg != NULL) {
+ if (p_errmsg != NULL) {
+ *p_errmsg = errmsg;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+int
+_PyCode_VerifyStateless(PyThreadState *tstate,
+ PyCodeObject *co, PyObject *globalnames,
+ PyObject *globalsns, PyObject *builtinsns)
+{
+ const char *errmsg;
+ _PyCode_var_counts_t counts = {0};
+ _PyCode_GetVarCounts(co, &counts);
+ if (_PyCode_SetUnboundVarCounts(
+ tstate, co, &counts, globalnames, NULL,
+ globalsns, builtinsns) < 0)
+ {
+ return -1;
+ }
+ // We may consider relaxing the internal state constraints
+ // if it becomes a problem.
+ if (!_PyCode_CheckNoInternalState(co, &errmsg)) {
+ _PyErr_SetString(tstate, PyExc_ValueError, errmsg);
+ return -1;
+ }
+ if (builtinsns != NULL) {
+ // Make sure the next check will fail for globals,
+ // even if there aren't any builtins.
+ counts.unbound.globals.numbuiltin += 1;
+ }
+ if (!_PyCode_CheckNoExternalState(co, &counts, &errmsg)) {
+ _PyErr_SetString(tstate, PyExc_ValueError, errmsg);
+ return -1;
+ }
+ // Note that we don't check co->co_flags & CO_NESTED for anything here.
+ return 0;
+}
+
+
+int
+_PyCode_CheckPureFunction(PyCodeObject *co, const char **p_errmsg)
+{
+ const char *errmsg = NULL;
+ if (co->co_flags & CO_GENERATOR) {
+ errmsg = "generators not supported";
+ }
+ else if (co->co_flags & CO_COROUTINE) {
+ errmsg = "coroutines not supported";
+ }
+ else if (co->co_flags & CO_ITERABLE_COROUTINE) {
+ errmsg = "coroutines not supported";
+ }
+ else if (co->co_flags & CO_ASYNC_GENERATOR) {
+ errmsg = "generators not supported";
+ }
+
+ if (errmsg != NULL) {
+ if (p_errmsg != NULL) {
+ *p_errmsg = errmsg;
+ }
+ return 0;
+ }
+ return 1;
+}
+
/* Here "value" means a non-None value, since a bare return is identical
* to returning None explicitly. Likewise a missing return statement
* at the end of the function is turned into "return None". */
static int
code_returns_only_none(PyCodeObject *co)
{
+ if (!_PyCode_CheckPureFunction(co, NULL)) {
+ return 0;
+ }
+ int len = (int)Py_SIZE(co);
+ assert(len > 0);
+
+ // The last instruction either returns or raises. We can take advantage
+ // of that for a quick exit.
+ _Py_CODEUNIT final = _Py_GetBaseCodeUnit(co, len-1);
+
// Look up None in co_consts.
Py_ssize_t nconsts = PyTuple_Size(co->co_consts);
int none_index = 0;
@@ -1971,26 +2089,42 @@ code_returns_only_none(PyCodeObject *co)
}
if (none_index == nconsts) {
// None wasn't there, which means there was no implicit return,
- // "return", or "return None". That means there must be
- // an explicit return (non-None).
- return 0;
- }
+ // "return", or "return None".
- // Walk the bytecode, looking for RETURN_VALUE.
- Py_ssize_t len = Py_SIZE(co);
- for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) {
- _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i);
- if (IS_RETURN_OPCODE(inst.op.code)) {
- assert(i != 0);
- // Ignore it if it returns None.
- _Py_CODEUNIT prev = _Py_GetBaseCodeUnit(co, i-1);
- if (prev.op.code == LOAD_CONST) {
- // We don't worry about EXTENDED_ARG for now.
- if (prev.op.arg == none_index) {
- continue;
+ // That means there must be
+ // an explicit return (non-None), or it only raises.
+ if (IS_RETURN_OPCODE(final.op.code)) {
+ // It was an explicit return (non-None).
+ return 0;
+ }
+ // It must end with a raise then. We still have to walk the
+ // bytecode to see if there's any explicit return (non-None).
+ assert(IS_RAISE_OPCODE(final.op.code));
+ for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) {
+ _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i);
+ if (IS_RETURN_OPCODE(inst.op.code)) {
+ // We alraedy know it isn't returning None.
+ return 0;
+ }
+ }
+ // It must only raise.
+ }
+ else {
+ // Walk the bytecode, looking for RETURN_VALUE.
+ for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) {
+ _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i);
+ if (IS_RETURN_OPCODE(inst.op.code)) {
+ assert(i != 0);
+ // Ignore it if it returns None.
+ _Py_CODEUNIT prev = _Py_GetBaseCodeUnit(co, i-1);
+ if (prev.op.code == LOAD_CONST) {
+ // We don't worry about EXTENDED_ARG for now.
+ if (prev.op.arg == none_index) {
+ continue;
+ }
}
+ return 0;
}
- return 0;
}
}
return 1;
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 59b0cf1ce7d..ce27e47dabf 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -547,13 +547,13 @@ static inline uint8_t
calculate_log2_keysize(Py_ssize_t minsize)
{
#if SIZEOF_LONG == SIZEOF_SIZE_T
- minsize = (minsize | PyDict_MINSIZE) - 1;
- return _Py_bit_length(minsize | (PyDict_MINSIZE-1));
+ minsize = Py_MAX(minsize, PyDict_MINSIZE);
+ return _Py_bit_length(minsize - 1);
#elif defined(_MSC_VER)
- // On 64bit Windows, sizeof(long) == 4.
- minsize = (minsize | PyDict_MINSIZE) - 1;
+ // On 64bit Windows, sizeof(long) == 4. We cannot use _Py_bit_length.
+ minsize = Py_MAX(minsize, PyDict_MINSIZE);
unsigned long msb;
- _BitScanReverse64(&msb, (uint64_t)minsize);
+ _BitScanReverse64(&msb, (uint64_t)minsize - 1);
return (uint8_t)(msb + 1);
#else
uint8_t log2_size;
@@ -3178,9 +3178,10 @@ dict_set_fromkeys(PyInterpreterState *interp, PyDictObject *mp,
Py_ssize_t pos = 0;
PyObject *key;
Py_hash_t hash;
-
- if (dictresize(interp, mp,
- estimate_log2_keysize(PySet_GET_SIZE(iterable)), 0)) {
+ uint8_t new_size = Py_MAX(
+ estimate_log2_keysize(PySet_GET_SIZE(iterable)),
+ DK_LOG_SIZE(mp->ma_keys));
+ if (dictresize(interp, mp, new_size, 0)) {
Py_DECREF(mp);
return NULL;
}
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index 56df5730db0..27214a129c2 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -1,12 +1,14 @@
/* Function object implementation */
#include "Python.h"
+#include "pycore_code.h" // _PyCode_VerifyStateless()
#include "pycore_dict.h" // _Py_INCREF_DICT()
#include "pycore_function.h" // _PyFunction_Vectorcall
#include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_Occurred()
+#include "pycore_setobject.h" // _PySet_NextEntry()
#include "pycore_stats.h"
@@ -1240,6 +1242,58 @@ PyTypeObject PyFunction_Type = {
};
+int
+_PyFunction_VerifyStateless(PyThreadState *tstate, PyObject *func)
+{
+ assert(!PyErr_Occurred());
+ assert(PyFunction_Check(func));
+
+ // Check the globals.
+ PyObject *globalsns = PyFunction_GET_GLOBALS(func);
+ if (globalsns != NULL && !PyDict_Check(globalsns)) {
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "unsupported globals %R", globalsns);
+ return -1;
+ }
+ // Check the builtins.
+ PyObject *builtinsns = PyFunction_GET_BUILTINS(func);
+ if (builtinsns != NULL && !PyDict_Check(builtinsns)) {
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "unsupported builtins %R", builtinsns);
+ return -1;
+ }
+ // Disallow __defaults__.
+ PyObject *defaults = PyFunction_GET_DEFAULTS(func);
+ if (defaults != NULL && defaults != Py_None && PyDict_Size(defaults) > 0)
+ {
+ _PyErr_SetString(tstate, PyExc_ValueError, "defaults not supported");
+ return -1;
+ }
+ // Disallow __kwdefaults__.
+ PyObject *kwdefaults = PyFunction_GET_KW_DEFAULTS(func);
+ if (kwdefaults != NULL && kwdefaults != Py_None
+ && PyDict_Size(kwdefaults) > 0)
+ {
+ _PyErr_SetString(tstate, PyExc_ValueError,
+ "keyword defaults not supported");
+ return -1;
+ }
+ // Disallow __closure__.
+ PyObject *closure = PyFunction_GET_CLOSURE(func);
+ if (closure != NULL && closure != Py_None && PyTuple_GET_SIZE(closure) > 0)
+ {
+ _PyErr_SetString(tstate, PyExc_ValueError, "closures not supported");
+ return -1;
+ }
+ // Check the code.
+ PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
+ if (_PyCode_VerifyStateless(tstate, co, NULL, globalsns, builtinsns) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+
static int
functools_copy_attr(PyObject *wrapper, PyObject *wrapped, PyObject *name)
{
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 40d90ecf4fa..0b2dfa003fa 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -1760,6 +1760,10 @@ UNSIGNED_INT_CONVERTER(UnsignedInt, unsigned int)
UNSIGNED_INT_CONVERTER(UnsignedLong, unsigned long)
UNSIGNED_INT_CONVERTER(UnsignedLongLong, unsigned long long)
UNSIGNED_INT_CONVERTER(Size_t, size_t)
+UNSIGNED_INT_CONVERTER(UInt8, uint8_t)
+UNSIGNED_INT_CONVERTER(UInt16, uint16_t)
+UNSIGNED_INT_CONVERTER(UInt32, uint32_t)
+UNSIGNED_INT_CONVERTER(UInt64, uint64_t)
#define CHECK_BINOP(v,w) \
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index eb3e1c48fd4..f3f0c9646a6 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -3730,7 +3730,7 @@ PyUnicode_Decode(const char *s,
return NULL;
}
-PyObject *
+PyAPI_FUNC(PyObject *)
PyUnicode_AsDecodedObject(PyObject *unicode,
const char *encoding,
const char *errors)
@@ -3740,12 +3740,6 @@ PyUnicode_AsDecodedObject(PyObject *unicode,
return NULL;
}
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "PyUnicode_AsDecodedObject() is deprecated "
- "and will be removed in 3.15; "
- "use PyCodec_Decode() to decode from str", 1) < 0)
- return NULL;
-
if (encoding == NULL)
encoding = PyUnicode_GetDefaultEncoding();
@@ -3753,7 +3747,7 @@ PyUnicode_AsDecodedObject(PyObject *unicode,
return PyCodec_Decode(unicode, encoding, errors);
}
-PyObject *
+PyAPI_FUNC(PyObject *)
PyUnicode_AsDecodedUnicode(PyObject *unicode,
const char *encoding,
const char *errors)
@@ -3765,12 +3759,6 @@ PyUnicode_AsDecodedUnicode(PyObject *unicode,
goto onError;
}
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "PyUnicode_AsDecodedUnicode() is deprecated "
- "and will be removed in 3.15; "
- "use PyCodec_Decode() to decode from str to str", 1) < 0)
- return NULL;
-
if (encoding == NULL)
encoding = PyUnicode_GetDefaultEncoding();
@@ -3793,7 +3781,7 @@ PyUnicode_AsDecodedUnicode(PyObject *unicode,
return NULL;
}
-PyObject *
+PyAPI_FUNC(PyObject *)
PyUnicode_AsEncodedObject(PyObject *unicode,
const char *encoding,
const char *errors)
@@ -3805,13 +3793,6 @@ PyUnicode_AsEncodedObject(PyObject *unicode,
goto onError;
}
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "PyUnicode_AsEncodedObject() is deprecated "
- "and will be removed in 3.15; "
- "use PyUnicode_AsEncodedString() to encode from str to bytes "
- "or PyCodec_Encode() for generic encoding", 1) < 0)
- return NULL;
-
if (encoding == NULL)
encoding = PyUnicode_GetDefaultEncoding();
@@ -4017,7 +3998,7 @@ PyUnicode_AsEncodedString(PyObject *unicode,
return NULL;
}
-PyObject *
+PyAPI_FUNC(PyObject *)
PyUnicode_AsEncodedUnicode(PyObject *unicode,
const char *encoding,
const char *errors)
@@ -4029,12 +4010,6 @@ PyUnicode_AsEncodedUnicode(PyObject *unicode,
goto onError;
}
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "PyUnicode_AsEncodedUnicode() is deprecated "
- "and will be removed in 3.15; "
- "use PyCodec_Encode() to encode from str to str", 1) < 0)
- return NULL;
-
if (encoding == NULL)
encoding = PyUnicode_GetDefaultEncoding();