ETOOBUSY 🚀 minimal blogging for the impatient
PWC108 - Locate Memory
TL;DR
Here we are with TASK #1 from the Perl Weekly Challenge #108. Enjoy!
The challenge
Write a script to declare a variable or constant and print its location in the memory.
The questions
I like Perl and I’ll take this to be a Perl-only question, but this might not be the case, so a few questions might be:
- is this about Perl?
- should the program be written in Perl, but based on some executable that is not the program itself?
I can only guess that the second can be done by someone, not by me. If you’re looking for that person… goodbye, it’s been a pleasure and thanks for the coffee.
Another question is how constrained the environment is. I mean, we all tend to give CORE modules for granted, but:
perl
in some Linux distributions might break this assumption;- some modules entered CORE only at a certain point in time (e.g.
Scalar::Util was first released with perl v5.7.3
).
So a question might be *can we assume a sane perl
released in the
latest 10 years?.
Last questions relate to the linguistic aspect of the challenge:
- are we allowed to declare more than one variable or constant?
- I guess so, because declaring two variables still cover the requirement of declaring a variable;
- can we declare both variables and constants?
- I guess so, because the or can be interpreted as being
inclusive rather than exclusive (this is also consistent with
the usual meaning of
||
andor
in most programming languages).
- I guess so, because the or can be interpreted as being
inclusive rather than exclusive (this is also consistent with
the usual meaning of
The solution
This will be boring but still… the most robust thing I can think of:
#!/usr/bin/env perl
use 5.024;
use warnings;
use Scalar::Util 'refaddr';
sub locate_memory { refaddr(ref($_[0]) ? $_[0] : \$_[0]) }
my $whatever = 42;
say locate_memory($whatever);
say locate_memory(\$whatever);
say locate_memory(\\$whatever);
say locate_memory(42);
say locate_memory(42);
say locate_memory(bless {}, 'Whatever');
Yes, the refaddr
function in Scalar::Util is actually all that we
need here. There’s a couple of twists that might use some explanation:
- no signatures this time, we’re operating directly over
$_[0]
. This is important, because$_[0]
is an alias to the original variable/constant, not a copy. This means that we will be operating exactly on the thingie we have declared; - we take a reference to the variable/constant unless we’re passed one
as input. This is why we expect the first two
say
lines to actually print out the same value. This is under the assumption that if you pass a reference you’re generally interested into the referenced thing, not the reference itself; you can still grab information on the reference by passing… a reference to it (e.g. see the thirdsay
for an example).
A couple of example runs:
$ perl perl/ch-1.pl
94760002921544
94760002921544
94760002921568
94760002920680
94760002752880
$ perl perl/ch-1.pl
94304258147400
94304258147400
94304257978736
94304258147424
94304258146536
94304257978736
As expected, the first two lines in both runs show the same value; all other ones are different. It’s also worth noting that two different runs yield different values: this, I suppose, is thanks to some randomization in the placement of stuff in memory to make it harder some kind of attack. Or maybe it’s just random randomness.
Stay safe!