require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(lock_keys unlock_keys lock_value unlock_value
- lock_hash unlock_hash
+ lock_hash unlock_hash hash_seed
);
-our $VERSION = 0.04;
-
+our $VERSION = 0.05;
=head1 NAME
=head1 SYNOPSIS
- use Hash::Util qw(lock_keys unlock_keys
+ use Hash::Util qw(lock_keys unlock_keys
lock_value unlock_value
lock_hash unlock_hash
- );
+ hash_seed);
%hash = (foo => 42, bar => 23);
lock_keys(%hash);
lock_hash (%hash);
unlock_hash(%hash);
+ my $hashes_are_randomised = hash_seed() != 0;
=head1 DESCRIPTION
lock_keys(%hash);
lock_keys(%hash, @keys);
- unlock_keys(%hash;)
-
Restricts the given %hash's set of keys to @keys. If @keys is not
given it restricts it to its current keyset. No more keys can be
-added. delete() and exists() will still work, but it does not effect
-the set of allowed keys.
+added. delete() and exists() will still work, but will not alter
+the set of allowed keys. B<Note>: the current implementation prevents
+the hash from being bless()ed while it is in a locked state. Any attempt
+to do so will raise an exception. Of course you can still bless()
+the hash before you call lock_keys() so this shouldn't be a problem.
+
+ unlock_keys(%hash);
Removes the restriction on the %hash's keyset.
sub lock_keys (\%;@) {
my($hash, @keys) = @_;
+ Internals::hv_clear_placeholders %$hash;
if( @keys ) {
my %keys = map { ($_ => 1) } @keys;
my %original_keys = map { ($_ => 1) } keys %$hash;
Internals::SvREADONLY %$hash, 1;
}
- return undef;
+ return;
}
sub unlock_keys (\%) {
my($hash) = shift;
Internals::SvREADONLY %$hash, 0;
- return undef;
+ return;
}
=item lock_value
=item unlock_value
- lock_key (%hash, $key);
- unlock_key(%hash, $key);
+ lock_value (%hash, $key);
+ unlock_value(%hash, $key);
Locks and unlocks an individual key of a hash. The value of a locked
key cannot be changed.
=item B<unlock_hash>
lock_hash(%hash);
- unlock_hash(%hash);
lock_hash() locks an entire hash, making all keys and values readonly.
No value can be changed, no keys can be added or deleted.
-unlock_hash() does the opposite. All keys and values are made
-read/write. All values can be changed and keys can be added and
-deleted.
+ unlock_hash(%hash);
+
+unlock_hash() does the opposite of lock_hash(). All keys and values
+are made read/write. All values can be changed and keys can be added
+and deleted.
=cut
}
+=item B<hash_seed>
+
+ my $hash_seed = hash_seed();
+
+hash_seed() returns the seed number used to randomise hash ordering.
+Zero means the "traditional" random hash ordering, non-zero means the
+new even more random hash ordering introduced in Perl 5.8.1.
+
+B<Note that the hash seed is sensitive information>: by knowing it one
+can craft a denial-of-service attack against Perl code, even remotely,
+see L<perlsec/"Algorithmic Complexity Attacks"> for more information.
+B<Do not disclose the hash seed> to people who don't need to know it.
+See also L<perlrun/PERL_HASH_SEED_DEBUG>.
+
+=cut
+
+sub hash_seed () {
+ Internals::rehash_seed();
+}
+
=back
+=head1 CAVEATS
+
+Note that the trapping of the restricted operations is not atomic:
+for example
+
+ eval { %hash = (illegal_key => 1) }
+
+leaves the C<%hash> empty rather than with its original contents.
+
=head1 AUTHOR
Michael G Schwern <schwern@pobox.com> on top of code by Nick
=head1 SEE ALSO
-L<Scalar::Util>, L<List::Util>, L<Hash::Util>
+L<Scalar::Util>, L<List::Util>, L<Hash::Util>,
+and L<perlsec/"Algorithmic Complexity Attacks">.
=cut