summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/using/cmdline.rst5
-rw-r--r--Include/pylifecycle.h8
-rw-r--r--Lib/test/test_cmd_line.py12
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2017-12-15-00-13-04.bpo-32329.q47IN2.rst5
-rw-r--r--Modules/main.c35
-rw-r--r--Python/bootstrap_hash.c37
6 files changed, 63 insertions, 39 deletions
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
index 5cb9071..598eb25 100644
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -277,8 +277,9 @@ Miscellaneous options
.. cmdoption:: -R
- Kept for compatibility. On Python 3.3 and greater, hash randomization is
- turned on by default.
+ Turn on hash randomization. This option only has an effect if the
+ :envvar:`PYTHONHASHSEED` environment variable is set to ``0``, since hash
+ randomization is enabled by default.
On previous versions of Python, this option turns on hash randomization,
so that the :meth:`__hash__` values of str, bytes and datetime
diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h
index 61ed6cc..0416bfa 100644
--- a/Include/pylifecycle.h
+++ b/Include/pylifecycle.h
@@ -136,7 +136,13 @@ PyAPI_FUNC(_PyInitError) _PyImportHooks_Init(void);
PyAPI_FUNC(int) _PyFrame_Init(void);
PyAPI_FUNC(int) _PyFloat_Init(void);
PyAPI_FUNC(int) PyByteArray_Init(void);
-PyAPI_FUNC(_PyInitError) _Py_HashRandomization_Init(_PyCoreConfig *core_config);
+PyAPI_FUNC(_PyInitError) _Py_HashRandomization_Init(const _PyCoreConfig *);
+#endif
+#ifdef Py_BUILD_CORE
+PyAPI_FUNC(int) _Py_ReadHashSeed(
+ const char *seed_text,
+ int *use_hash_seed,
+ unsigned long *hash_seed);
#endif
/* Various internal finalizers */
diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py
index 2aff51b..2b14c30 100644
--- a/Lib/test/test_cmd_line.py
+++ b/Lib/test/test_cmd_line.py
@@ -432,8 +432,16 @@ class CmdLineTest(unittest.TestCase):
# Verify that sys.flags contains hash_randomization
code = 'import sys; print("random is", sys.flags.hash_randomization)'
- rc, out, err = assert_python_ok('-c', code)
- self.assertEqual(rc, 0)
+ rc, out, err = assert_python_ok('-c', code, PYTHONHASHSEED='')
+ self.assertIn(b'random is 1', out)
+
+ rc, out, err = assert_python_ok('-c', code, PYTHONHASHSEED='random')
+ self.assertIn(b'random is 1', out)
+
+ rc, out, err = assert_python_ok('-c', code, PYTHONHASHSEED='0')
+ self.assertIn(b'random is 0', out)
+
+ rc, out, err = assert_python_ok('-R', '-c', code, PYTHONHASHSEED='0')
self.assertIn(b'random is 1', out)
def test_del___main__(self):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-12-15-00-13-04.bpo-32329.q47IN2.rst b/Misc/NEWS.d/next/Core and Builtins/2017-12-15-00-13-04.bpo-32329.q47IN2.rst
new file mode 100644
index 0000000..86bcf23
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2017-12-15-00-13-04.bpo-32329.q47IN2.rst
@@ -0,0 +1,5 @@
+The :option:`-R` option now turns on hash randomization when the
+:envvar:`PYTHONHASHSEED` environment variable is set to ``0``. Previously,
+the option was ignored. Moreover, ``sys.flags.hash_randomization`` is now
+properly set to 0 when hash randomization is turned off by
+``PYTHONHASHSEED=0``.
diff --git a/Modules/main.c b/Modules/main.c
index 6db7e5f..e1a2f98 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -726,7 +726,7 @@ pymain_parse_cmdline_impl(_PyMain *pymain)
break;
case 'R':
- /* Ignored */
+ pymain->core_config.use_hash_seed = 0;
break;
/* This space reserved for other options */
@@ -1293,6 +1293,10 @@ pymain_set_global_config(_PyMain *pymain)
Py_IgnoreEnvironmentFlag = pymain->core_config.ignore_environment;
Py_UTF8Mode = pymain->core_config.utf8_mode;
+
+ /* Random or non-zero hash seed */
+ Py_HashRandomizationFlag = (pymain->core_config.use_hash_seed == 0 ||
+ pymain->core_config.hash_seed != 0);
}
@@ -1694,6 +1698,24 @@ config_init_home(_PyCoreConfig *config)
}
+static _PyInitError
+config_init_hash_seed(_PyCoreConfig *config)
+{
+ if (config->use_hash_seed < 0) {
+ const char *seed_text = pymain_get_env_var("PYTHONHASHSEED");
+ int use_hash_seed;
+ unsigned long hash_seed;
+ if (_Py_ReadHashSeed(seed_text, &use_hash_seed, &hash_seed) < 0) {
+ return _Py_INIT_USER_ERR("PYTHONHASHSEED must be \"random\" "
+ "or an integer in range [0; 4294967295]");
+ }
+ config->use_hash_seed = use_hash_seed;
+ config->hash_seed = hash_seed;
+ }
+ return _Py_INIT_OK();
+}
+
+
_PyInitError
_PyCoreConfig_ReadEnv(_PyCoreConfig *config)
{
@@ -1712,6 +1734,11 @@ _PyCoreConfig_ReadEnv(_PyCoreConfig *config)
return err;
}
+ err = config_init_hash_seed(config);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+
return _Py_INIT_OK();
}
@@ -1777,12 +1804,6 @@ pymain_parse_envvars(_PyMain *pymain)
/* Get environment variables */
pymain_set_flags_from_env(pymain);
- /* The variable is only tested for existence here;
- _Py_HashRandomization_Init will check its value further. */
- if (pymain_get_env_var("PYTHONHASHSEED")) {
- Py_HashRandomizationFlag = 1;
- }
-
if (pymain_warnings_envvar(pymain) < 0) {
return -1;
}
diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c
index 2762f46..9fd5cfb 100644
--- a/Python/bootstrap_hash.c
+++ b/Python/bootstrap_hash.c
@@ -533,9 +533,10 @@ _PyOS_URandomNonblock(void *buffer, Py_ssize_t size)
return pyurandom(buffer, size, 0, 1);
}
-int Py_ReadHashSeed(const char *seed_text,
- int *use_hash_seed,
- unsigned long *hash_seed)
+int
+_Py_ReadHashSeed(const char *seed_text,
+ int *use_hash_seed,
+ unsigned long *hash_seed)
{
Py_BUILD_ASSERT(sizeof(_Py_HashSecret_t) == sizeof(_Py_HashSecret.uc));
/* Convert a text seed to a numeric one */
@@ -561,9 +562,9 @@ int Py_ReadHashSeed(const char *seed_text,
return 0;
}
-static _PyInitError
-init_hash_secret(int use_hash_seed,
- unsigned long hash_seed)
+
+_PyInitError
+_Py_HashRandomization_Init(const _PyCoreConfig *config)
{
void *secret = &_Py_HashSecret;
Py_ssize_t secret_size = sizeof(_Py_HashSecret_t);
@@ -573,14 +574,14 @@ init_hash_secret(int use_hash_seed,
}
_Py_HashSecret_Initialized = 1;
- if (use_hash_seed) {
- if (hash_seed == 0) {
+ if (config->use_hash_seed) {
+ if (config->hash_seed == 0) {
/* disable the randomized hash */
memset(secret, 0, secret_size);
}
else {
/* use the specified hash seed */
- lcg_urandom(hash_seed, secret, secret_size);
+ lcg_urandom(config->hash_seed, secret, secret_size);
}
}
else {
@@ -601,24 +602,6 @@ init_hash_secret(int use_hash_seed,
return _Py_INIT_OK();
}
-_PyInitError
-_Py_HashRandomization_Init(_PyCoreConfig *core_config)
-{
- const char *seed_text;
- int use_hash_seed = core_config->use_hash_seed;
- unsigned long hash_seed = core_config->hash_seed;
-
- if (use_hash_seed < 0) {
- seed_text = Py_GETENV("PYTHONHASHSEED");
- if (Py_ReadHashSeed(seed_text, &use_hash_seed, &hash_seed) < 0) {
- return _Py_INIT_USER_ERR("PYTHONHASHSEED must be \"random\" "
- "or an integer in range [0; 4294967295]");
- }
- core_config->use_hash_seed = use_hash_seed;
- core_config->hash_seed = hash_seed;
- }
- return init_hash_secret(use_hash_seed, hash_seed);
-}
void
_Py_HashRandomization_Fini(void)