Perl File::Temp, имя файла не случайно

У меня странная проблема с использованием File::Temp:

Я запускаю свой perl-скрипт под mod_perl в Apache в Linux, Apache работает с рабочим mpm.

my ($fh_error, $error)
    = tempfile("error_XXXXXXXXXXXXXXXX",DIR => "/home/tmp", UNLINK => 1);
my ($fh_src, $src) 
    = tempfile("src_XXXXXXXXXXXXXXXX",DIR => "/home/tmp", UNLINK => 1, SUFFIX => ".html");          
my ($fh_dst, $dst) 
    = tempfile("dst_XXXXXXXXXXXXXXXX",DIR => "/home/tmp", UNLINK => 1, SUFFIX => ".html");

Большую часть времени все вроде бы в порядке, но время от времени я получаю неправильные имена файлов. Вместо того, чтобы получить истинное случайное имя файла, я получаю одну и ту же букву для всей длины шаблона.

Например

error_AAAAAAAAAAAAAAAA
src_AAAAAAAAAAAAAAAA
dst_AAAAAAAAAAAAAAAA

Все 3 файла получают одинаковое имя. За исключением того, что это просто странно (и вы никогда не хотите, чтобы ваш код был странным), я боюсь, что это может привести к чтению/записи в один и тот же файл для разных запросов.


person Daniel Miron    schedule 10.07.2013    source источник
comment
Догадка: может быть, у вас закончилась энтропия? У вас в системе работает munin (или что-то подобное) и вы видите что-то подозрительное на доступном графике энтропии?   -  person Slaven Rezic    schedule 10.07.2013
comment
блин даже не думал об этом, сейчас маловато 100-200   -  person Daniel Miron    schedule 10.07.2013
comment
Да, но даже при нулевой энтропии /dev/urandom все равно должен давать хорошие псевдослучайные числа. Они просто не будут криптографически стойкими (т. е. с N последовательными случайными числами вы теоретически могли бы определить лучшие шансы на то, что может быть N + 1, для достаточно большого N).   -  person Joe Z    schedule 10.07.2013


Ответы (1)


Я посмотрел на источник для File::Temp. Он заменяет крестики в шаблоне этим кратким фрагментом Perl:

    $path =~ s/X(?=X*$end)/$CHARS[ int( rand( @CHARS ) ) ]/ge;

Это использует встроенный в Perl rand, который является просто традиционным генератором случайных чисел на основе начального числа. Эта функция rand не является криптографически защищенной. Его семя также является «глобальным состоянием», что может привести к проблемам при разветвлении, как описано здесь:

http://blogs.perl.org/users/brian_phillips/2010/06/when-rand-isnt-random.html

Суть в следующем: если вы разветвляете два интерпретатора perl, и исходный интерпретатор уже был заполнен одним вызовом rand, оба наследуют одно и то же начальное число после fork, поэтому оба будут генерировать одну и ту же последовательность случайных чисел из этой точки. Упс. Таким образом, вы можете вызвать srand one в своем модуле перед вызовом tempfile или чем-то еще, что вызывает rand.

Тем не менее, похоже, что File::Temp прилагает большие усилия для обнаружения и предотвращения столкновений, но в какой-то момент он сдастся. Следующее предупреждение скрыто в документах File::Temp:

    If you are forking many processes in parallel that are all creating 
    temporary files, you may need to reset the random number seed using 
    srand(EXPR) in each child else all the children will attempt to walk 
    through the same set of random file names and may well cause themselves 
    to give up if they exceed the number of retry attempts.
person Joe Z    schedule 10.07.2013
comment
Я немного покопался и узнал об этой проблеме, я также нашел предложение добавить PerlChildInitHandler sub { srand } в apache conf, но это, похоже, не сработало. - person Daniel Miron; 10.07.2013