classification
Title: eval is needlessly limited
Type: enhancement Stage:
Components: Interpreter Core Versions: Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: bup, steven.daprano
Priority: normal Keywords:

Created on 2019-03-13 23:31 by bup, last changed 2019-03-14 03:37 by steven.daprano.

Messages (2)
msg337885 - (view) Author: Dan Snider (bup) * Date: 2019-03-13 23:31
The footnote about why eval/exec cannot be used for arbitrary code has been (for the most part) incorrect for quite some time as the signature for PyEval_EvalCodeEx demonstrates:

PyObject* PyEval_EvalCodeEx(PyObject *co, PyObject *globals, PyObject *locals, PyObject *const *args, int argcount, PyObject *const *kws, int kwcount, PyObject *const *defs, int defcount, PyObject *kwdefs, PyObject *closure)

Making eval a wrapper for PyEval_EvalCodeEx instead of PyEval_EvalCode would be a backwards compatible change since new parameters come after the current 3. A hypothetical signature for the new signature would be something like:
    eval(src, globals: abc.Mapping, locals: abc.Mapping, args: tuple, kwargs: dict, defaults: tuple, kwdefaults: dict, closure: tuple). 

In that case, `src` could be unicode, bytes, frames, tracebacks, code objects, and even updated to support stuff like parser.STType or ast.Module/ast.Interactive/ast.Expresion objects. 

The only objection I can think of is the same as the reason it's currently documented that globals must be a dictionary and that is that the LOAD_NAME opcode (seemingly) arbitrarily requires frame.f_globals be a dict subtype (even though LOAD_GLOBAL doesn't).

On that point, I still don't understand why PyObject_GetItem doesn't have a PyDict_CheckExact test for a dictionary fast-path when tp_as_mapping is found non-null. That operation - a pointer comparison - takes a fraction of a nanosecond on a modern CPU making it essentially free compared to the rest of the logic in there... Furthermore, this addition would greatly simplify both core and abstract apis and enable the possibility of fixing several longstanding bugs caused by using PyDict_GetItem/PyDict_SetItem on a dict subtype. Actually, the better solution may be to add PyDict_Check in PyObject_Getitem and PyDict_CheckExact in PyDict_GetItem.

After writing all that out this seems more like an issue with  PyObject_GetItem and how there is zero consistency throughout the entirety the abstract/core api as to whether some arbitrary procedure will try to use the core dictionary api as a fast path or head straight for the abstract api.
msg337893 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2019-03-14 03:37
> The footnote about why eval/exec cannot be used for arbitrary code

Which footnote? I see nothing here:

https://docs.python.org/3/library/functions.html#eval

> On that point, I still don't understand why PyObject_GetItem doesn't have a PyDict_CheckExact test ...
> After writing all that out this seems more like an issue with  PyObject_GetItem


One bug report per ticket please.
History
Date User Action Args
2019-03-14 03:37:04steven.dapranosetnosy: + steven.daprano
messages: + msg337893
2019-03-13 23:31:43bupcreate