msg302208 - (view) |
Author: Oren Milman (Oren Milman) * |
Date: 2017-09-14 20:33 |
The following code causes an assertion failure: class BadInt(int): def __abs__(self): return None import random random.seed(BadInt()) this is because random_seed() (in Modules/_randommodule.c) assumes that PyNumber_Absolute() returned an int, and so it passes it to _PyLong_NumBits(), which asserts it received an int. what should we do in such a case? should we raise an exception? (the docs don't mention abs() in case the seed is an int - https://docs.python.org/3.7/library/random.html#random.seed) |
|
|
msg302228 - (view) |
Author: Raymond Hettinger (rhettinger) *  |
Date: 2017-09-15 02:01 |
It would make sense to verify that an actual int was returned and to raise a TypeError if it wasn't. Do you want to submit a PR (with a test case)? |
|
|
msg302232 - (view) |
Author: Oren Milman (Oren Milman) * |
Date: 2017-09-15 05:02 |
sure. but what about the TypeError message? should it complain about the return value of abs(seed)? (the docs of random.seed don't mention abs().) |
|
|
msg302234 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2017-09-15 06:08 |
There are several ways of solving this issue: 1. Verify that an actual int was returned and raise a TypeError if it wasn't. 2. Verify that an actual int was returned and fall back to the hash if it wasn't. 3. Use int.__abs__() instead of abs(), the result will be guaranteed int. The drawback is that this makes a copy of positive integers for int subclasses. 4. Check the sign of the seed and call int.__neg__() for negative values. |
|
|
msg302241 - (view) |
Author: Oren Milman (Oren Milman) * |
Date: 2017-09-15 09:35 |
i opened a PR that implements the first option, but of course I wouldn't mind if you decide another option is better. |
|
|
msg302317 - (view) |
Author: Vedran Čačić (veky) * |
Date: 2017-09-16 03:40 |
So floats (and complexes) cannot be seeds anymore? :-o Or this pertains only to ints? In this case, I think the easiest doc fix is to change If a is an int, it is used directly. to If a is an int, its absolute value is used. |
|
|
msg302740 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2017-09-22 08:43 |
The more I think about this the more I like the idea of using int.__abs__() directly (PyLong_Type.tp_as_number->nb_absolute() in C). The C code doesn't call potentially overridable methods bit_length() and to_bytes(), it uses concrete implementations directly. I don't see reasons why it should obey overriding the __abs__() method. This will save us from the problem with the wording of the error message. I mentioned a drawback, but the current implementation has the same drawback. We can avoid copying positive integer subtypes by using more complex code, but I think it isn't worth. |
|
|
msg302782 - (view) |
Author: Raymond Hettinger (rhettinger) *  |
Date: 2017-09-23 04:57 |
> I don't see reasons why it should obey overriding the __abs__() method. I concur. |
|
|
msg303196 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2017-09-28 07:50 |
New changeset d780b2d588e68bd7047ef5d1f04e36da38b7a350 by Serhiy Storchaka (Oren Milman) in branch 'master': bpo-31478: Fix an assertion failure in random.seed() in case a seed has a bad __abs__() method. (#3596) https://github.com/python/cpython/commit/d780b2d588e68bd7047ef5d1f04e36da38b7a350 |
|
|
msg303201 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2017-09-28 09:17 |
New changeset befc956acf8ddeb94f000ed081ddec51315429e5 by Serhiy Storchaka in branch '3.6': [3.6] bpo-31478: Fix an assertion failure in random.seed() in case a seed has a bad __abs__() method. (GH-3596) (#3794) https://github.com/python/cpython/commit/befc956acf8ddeb94f000ed081ddec51315429e5 |
|
|
msg303207 - (view) |
Author: Oren Milman (Oren Milman) * |
Date: 2017-09-28 10:22 |
With regard to backporting to 2.7: In 2.7 also, PyNumber_Absolute() is called, and its return value is stored in the variable n. However, there is no _PyLong_NumBits(n), so there is no assertion failure. If n isn't an integer: - if !PyObject_IsTrue(n), then the seed is zero (e.g. if n is None, [], () or {}) - otherwise, PyNumber_And() and PyNumber_Rshift() are used in a loop on n, so probably a TypeError would be raised. So I think a backport is still desirable, but i am not sure about the test. Maybe we should use @cpython_only, and make sure that no error is raised? We can also make sure that random() returns a different value than when the seed is zero. What do you think? |
|
|
msg303451 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2017-10-01 06:46 |
I agree that a backport is still desirable. Your plan LGTM. Implement __abs__ raising an exception (test both int ant long subclasses). Make sure that no error is raised. Make sure that random() returns the same value as when seeding with an exact int and long. |
|
|
msg303566 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2017-10-02 21:31 |
New changeset 13da1a60f13e173f65bb0da5ab325641d5bb99ec by Serhiy Storchaka (Oren Milman) in branch '2.7': [2.7] bpo-31478: Prevent unwanted behavior in _random.Random.seed() in case the arg has a bad __abs__() method (GH-3596) (#3845) https://github.com/python/cpython/commit/13da1a60f13e173f65bb0da5ab325641d5bb99ec |
|
|