diff -r e47e00723e5d Lib/test/test_dev.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/test/test_dev.py Wed Mar 30 10:19:44 2016 +0200 @@ -0,0 +1,36 @@ +import subprocess +import sys +import unittest + + +class DevModeTests(unittest.TestCase): + def check(self, strict, code, expected): + dev = "dev=strict" if strict else "dev" + args = [sys.executable, "-X", dev, "-c", code] + cmd = subprocess.run(args, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + check=True) + self.assertEqual(cmd.stdout.rstrip(), expected) + + def test_args(self): + code = ";".join(("import subprocess", + "args = subprocess._args_from_interpreter_flags()", + "print(' '.join(args))")) + self.check(False, code, b"-b -Wd") + self.check(True, code, b"-bb -Werror") + + def test_faulthandler(self): + code = "import faulthandler; print(faulthandler.is_enabled())" + cmd = self.check(False, code, b'True') + cmd = self.check(True, code, b'True') + + def test_malloc(self): + code = "import os; print(os.environ.get('PYTHONMALLOC'))" + cmd = self.check(False, code, b'debug') + cmd = self.check(True, code, b'debug') + + +if __name__ == "__main__": + unittest.main() + diff -r e47e00723e5d Modules/main.c --- a/Modules/main.c Wed Mar 30 08:51:15 2016 +0200 +++ b/Modules/main.c Wed Mar 30 10:19:44 2016 +0200 @@ -321,6 +321,92 @@ run_file(FILE *fp, const wchar_t *filena return run != 0; } +static const char* +exec_dev_mode(int strict, int argc, wchar_t **wargv) +{ + /* FIXME: copy code from posixmodule.c */ + extern char **environ; + + const char* errmsg; + char **argv, **parg; + int i; + + argv = PyMem_RawMalloc((4 + argc + 1) * sizeof(argv[0])); + if (argv == NULL) { + errmsg = "building argv failed (malloc error)"; + goto error; + } + + parg = argv; + *parg = Py_EncodeLocale(wargv[0], NULL); + if (*parg == NULL) { + errmsg = "building argv failed (encode error)"; + goto error; + } + parg++; + + *parg++ = strict ? "-bb" : "-b"; + *parg++ = strict ? "-Werror" : "-Wd"; + *parg++ = "-Xfaulthandler"; + *parg++ = "-X_devset"; + + for (i=1; i < argc; i++) { + *parg = Py_EncodeLocale(wargv[i], NULL); + if (*parg == NULL) { + errmsg = "building argv failed (encode error)"; + goto error; + } + parg++; + } + *parg++ = NULL; + + /* FIXME: use Py_GetProgramFullPath() */ + execve(argv[0], argv, environ); + + errmsg = "exec() failed"; + +error: + PyMem_RawFree(argv); + return errmsg; +} + +static void +setup_dev_mode(int argc, wchar_t **argv) +{ + PyObject *xoptions, *value; + const char* errmsg; + int strict = 0; + + xoptions = PySys_GetXOptions(); + if (xoptions == NULL) { + Py_FatalError("failed to get sys._xoptions"); + } + + /* FIXME: catch errors */ + if (PyDict_GetItemString(xoptions, "_devset") != NULL) { + return; + } + + /* FIXME: catch errors */ + value = PyDict_GetItemString(xoptions, "dev"); + if (value == NULL) { + return; + } + + if (PyUnicode_Check(value) && PyUnicode_CompareWithASCIIString(value, "strict") == 0) { + strict = 1; + } + + /* FIXME: don't override but add _malloc suffix for malloc/pymalloc */ + if (setenv("PYTHONMALLOC", "debug", 1)) { + Py_FatalError("failed to set PYTHONMALLOC env variable"); + } + + errmsg = exec_dev_mode(strict, argc, argv); + printf("setup_dev_mode() failed: %s\n", errmsg); + exit(1); +} + /* Main program */ @@ -590,6 +676,8 @@ Py_Main(int argc, wchar_t **argv) filename = argv[_PyOS_optind]; } + setup_dev_mode(orig_argc, orig_argv); + stdin_is_interactive = Py_FdIsInteractive(stdin, (char *)0); #if defined(MS_WINDOWS) || defined(__CYGWIN__)