Perl: переназначает ли новое значение скаляру его текущее содержимое в ОЗУ? - PullRequest
7 голосов
/ 30 июля 2011

Я использую Perl для задач, связанных с безопасностью, и мне интересно, когда такое утверждение, как:

$test = "new value"

выполняется, старое значение, созданное $test, перезаписано в ОЗУ?

Если нет, есть ли способ заставить это произойти?

Ответы [ 3 ]

13 голосов
/ 30 июля 2011

Если скаляр не магический и имеет строковый буфер, и строка помещается в строковый буфер, то эта часть строкового буфера будет перезаписана.

Обратите внимание, что

$s = "abcdef";
$s =~ s/...//;
$s = "x" x length($s);

оставляет "xxx \ 0ef \ 0" в буфере скаляра. Требуется длина буфера, а не длина строки внутри буфера.

Я хотел сказать, что ни один из

$s = undef;
$s = 123;

повлияет на строковый буфер вообще. Это даже не будет освобождено. Аналогично, присвоение строки скаляру не повлияет на другие поля скаляра, такие как поля для хранения чисел.


Я забыл, что если строка, присваиваемая скаляру, имеет значение TEMP, буфер цели заменяется вместо перезаписи.

>perl -MDevel::Peek -e"my $s = 'abc'; Dump($s); $s = 'X' x length($s); Dump($s);"
SV = PV(0x348d54) at 0x1d3927c
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0x349fac "abc"\0
  CUR = 3
  LEN = 12
SV = PV(0x348d54) at 0x1d3927c
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0x349fac "XXX"\0     <-- same address
  CUR = 3
  LEN = 12

>perl -MDevel::Peek -e"my $s = 'abc'; Dump($s); $s = sub { 'X' x length($s); }->(); Dump($s);"
SV = PV(0x38d54) at 0x1c3930c
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0x39fac "abc"\0
  CUR = 3
  LEN = 12
SV = PV(0x38d54) at 0x1c3930c
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0x1c603fc "XXX"\0     <-- different address
  CUR = 3                        No overwriting.
  LEN = 12
9 голосов
/ 30 июля 2011

Вы можете использовать модуль Devel :: Peek , чтобы ответить на такие вопросы:

use Devel::Peek;

my $test = "value";
Dump($test);
$test = "new value";
Dump($test);

В этом случае вы получите:

SV = PV(0x297c04) at 0x187b9ac
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0x18751cc "value"\0
  CUR = 5
  LEN = 12
SV = PV(0x297c04) at 0x187b9ac
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0x18751cc "new value"\0
  CUR = 9
  LEN = 12

МожетЛегко видеть, что адрес в этом случае остался прежним.Как отмечали другие, если ваша строка длиннее, чем буферы LEN, данные будут перераспределены:

my $test = "value";
Dump($test);
$test = "new value that is much longer";
Dump($test);

выход (см., Что указатель рядом с PV изменен):

SV = PV(0x297c04) at 0x187b9ac
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0x18751cc "value"\0
  CUR = 5
  LEN = 12
SV = PV(0x297c04) at 0x187b9ac
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0x187cf74 "new value that is much longer"\0
  CUR = 29
  LEN = 32
3 голосов
/ 30 июля 2011

Я думаю, это зависит от того, какое было предыдущее значение $test.

Если, например, новое значение длиннее, perl придется вызвать realloc () (или что-то подобное), которое можетизмените, где хранится строка.

В общем случае операции строки perl, по-видимому, используют одну и ту же память, когда это возможно, хотя я не думаю, что это гарантировано.

Вы можете получить адресстрокового буфера скаляра unpack('J', pack('P', $s)).Это не работает, если скаляр не содержит строку (даже если он имеет строковый буфер).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...