Unable to see or modify value of PYTHONHASHSEED th

2020-08-25 09:06发布

问题:

Trying to see the value of PYTHONHASHSEED by using:

# (this is inside module_1.py)
os.environ['PYTHONHASHSEED'] 

raises a KeyError:

Traceback (most recent call last):
  File "/home/black/Dev/Projects/module_1.py", line 2, in <module>
    os.environ['PYTHONHASHSEED']
  File "/usr/lib/python3.4/os.py", line 631, in __getitem__
    raise KeyError(key) from None
KeyError: 'PYTHONHASHSEED'

Printing the contents of os.environ by

for i in sorted(os.environ):
    print(i)

# prints:
# CLUTTER_IM_MODULE
# COMPIZ_BIN_PATH
# ...
# etc.

reveals that PYTHONHASHSEED is not inside, but I am pretty sure it should have a value since on Python 3.3 and greater, hash randomization is turned on by default.

Question:
Why can't I access its value this way and how can I access it through module_1.py?

回答1:

You can set PYTHONHASHSEED in a Python script, but it has no effect on the behavior of the hash() function - it needs to be set in the environment of the interpreter before the interpreter starts up.


How to set its value using pure Python

The trick is to pass the environment variable to the Python interpreter in a subprocess.

import random
from subprocess import call

random.seed(37)
cmd = ['python', '-c', 'print(hash("abc"))']

for i in range(5):
    hashseed = bytes(random.randint(0, 4294967295))
    print('\nhashseed', hashseed)
    call(cmd, env={'PYTHONHASHSEED': hashseed})

output

hashseed 2929187283
-972692480

hashseed 393430205
2066796829

hashseed 2653501013
1620854360

hashseed 3616018455
-599248233

hashseed 3584366196
-2103216293

You can change the cmd list so that it runs the hashtest.py script above:

cmd = ['python', 'hashtest.py']

or if hashtest.py is executable,

cmd = './hashtest.py'

By passing a dict as the env argument we replace the default environment that would be passed to the command. If you need access to those other environment variables, then instead you should modify os.environ in the calling script, with eg, os.environ['PYTHONHASHSEED'] = hashseed.

How to set its value using Bash

First, we have a short Bash script pyhashtest.bsh that uses the RANDOM environment variable as the seed for PYTHONHASHSEED. This variable must be exported so that the Python interpreter can see it. Then we run our Python script hashtest.py. We do this in a loop 5 times so we can see that using different seeds has an effect on the hash value.

The Python script hashtest.py reads PYTHONHASHSEED from the environment and prints it to show that it has the value we expect it to have. We then calculate & print the hash of a short string.

pyhashtest.bsh

#!/usr/bin/env bash

for((i=0; i<5; i++)); do
    n=$RANDOM
    echo "$i: Seed is $n"
    export PYTHONHASHSEED="$n"
    python hashtest.py
    echo
done

hashtest.py

#!/usr/bin/env python
import os

s = 'abc'
print('Hashseed is', os.environ['PYTHONHASHSEED'])
print('hash of s is', hash(s))

typical output

0: Seed is 9352
Hashseed is 9352
hash of s is 401719638

1: Seed is 24945
Hashseed is 24945
hash of s is -1250185385

2: Seed is 17661
Hashseed is 17661
hash of s is -571990551

3: Seed is 24313
Hashseed is 24313
hash of s is 99658978

4: Seed is 21142
Hashseed is 21142
hash of s is -662114263

To run these programs, save them both into the same directory, eg the usual directory you run Python scripts from. Then open a Bash shell and navigate to that directory using the cd command.

Eg, if you've saved the scripts to /mnt/sda2/fred/python then you'd do

cd /mnt/sda2/fred/python

Next, make pyhashtest.bsh executable using this command:

chmod a+x pyhashtest.bsh

Then run it with

./pyhashtest.bsh



回答2:

"hash randomization is turned on by default" means (among other things) that it is turned on even if there is no PYTHONHASHSEED environment variable - if the hash seed is not specified in the environment, one is chosen at random. This choice is done internally within python, and the os.environ array is not updated.