mirror of
https://github.com/python/cpython.git
synced 2025-08-09 11:29:45 +00:00

The behavior of fileno() after fclose() is undefined, but it is the only
practical way to check whether the file was closed.
Only test this on the known platforms (Linux, Windows, macOS), where we
already tested that it works.
(cherry picked from commit 546cbcfa0e
)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
115 lines
3 KiB
C
115 lines
3 KiB
C
#define PY_SSIZE_T_CLEAN
|
|
#include "parts.h"
|
|
#include "util.h"
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
|
|
static PyObject *
|
|
run_stringflags(PyObject *mod, PyObject *pos_args)
|
|
{
|
|
const char *str;
|
|
Py_ssize_t size;
|
|
int start;
|
|
PyObject *globals = NULL;
|
|
PyObject *locals = NULL;
|
|
PyCompilerFlags flags = _PyCompilerFlags_INIT;
|
|
PyCompilerFlags *pflags = NULL;
|
|
int cf_flags = 0;
|
|
int cf_feature_version = 0;
|
|
|
|
if (!PyArg_ParseTuple(pos_args, "z#iO|Oii",
|
|
&str, &size, &start, &globals, &locals,
|
|
&cf_flags, &cf_feature_version)) {
|
|
return NULL;
|
|
}
|
|
|
|
NULLABLE(globals);
|
|
NULLABLE(locals);
|
|
if (cf_flags || cf_feature_version) {
|
|
flags.cf_flags = cf_flags;
|
|
flags.cf_feature_version = cf_feature_version;
|
|
pflags = &flags;
|
|
}
|
|
|
|
return PyRun_StringFlags(str, start, globals, locals, pflags);
|
|
}
|
|
|
|
static PyObject *
|
|
run_fileexflags(PyObject *mod, PyObject *pos_args)
|
|
{
|
|
PyObject *result = NULL;
|
|
const char *filename = NULL;
|
|
Py_ssize_t filename_size;
|
|
int start;
|
|
PyObject *globals = NULL;
|
|
PyObject *locals = NULL;
|
|
int closeit = 0;
|
|
PyCompilerFlags flags = _PyCompilerFlags_INIT;
|
|
PyCompilerFlags *pflags = NULL;
|
|
int cf_flags = 0;
|
|
int cf_feature_version = 0;
|
|
|
|
FILE *fp = NULL;
|
|
|
|
if (!PyArg_ParseTuple(pos_args, "z#iO|Oiii",
|
|
&filename, &filename_size, &start, &globals, &locals,
|
|
&closeit, &cf_flags, &cf_feature_version)) {
|
|
return NULL;
|
|
}
|
|
|
|
NULLABLE(globals);
|
|
NULLABLE(locals);
|
|
if (cf_flags || cf_feature_version) {
|
|
flags.cf_flags = cf_flags;
|
|
flags.cf_feature_version = cf_feature_version;
|
|
pflags = &flags;
|
|
}
|
|
|
|
fp = fopen(filename, "r");
|
|
if (fp == NULL) {
|
|
PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
|
|
return NULL;
|
|
}
|
|
|
|
result = PyRun_FileExFlags(fp, filename, start, globals, locals, closeit, pflags);
|
|
|
|
#if defined(__linux__) || defined(MS_WINDOWS) || defined(__APPLE__)
|
|
/* The behavior of fileno() after fclose() is undefined, but it is
|
|
* the only practical way to check whether the file was closed.
|
|
* Only test this on the known platforms. */
|
|
if (closeit && result && fileno(fp) >= 0) {
|
|
PyErr_SetString(PyExc_AssertionError, "File was not closed after excution");
|
|
Py_DECREF(result);
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
#endif
|
|
if (!closeit && fileno(fp) < 0) {
|
|
PyErr_SetString(PyExc_AssertionError, "Bad file descriptor after excution");
|
|
Py_XDECREF(result);
|
|
return NULL;
|
|
}
|
|
|
|
if (!closeit) {
|
|
fclose(fp); /* don't need open file any more*/
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static PyMethodDef test_methods[] = {
|
|
{"run_stringflags", run_stringflags, METH_VARARGS},
|
|
{"run_fileexflags", run_fileexflags, METH_VARARGS},
|
|
{NULL},
|
|
};
|
|
|
|
int
|
|
_PyTestCapi_Init_Run(PyObject *mod)
|
|
{
|
|
if (PyModule_AddFunctions(mod, test_methods) < 0) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|