Skip Menu |
Report information
Id: 117449
Status: resolved
Priority: 0/
Queue: perl5

Owner: Nobody
Requestors: dom <dom [at]>

Operating System: Linux
PatchStatus: (no value)
Severity: low
Type: library
Perl Version: 5.17.10
Fixed In: (no value)

Subject: GDBM tied hash weirdness; deletion ends 'each' loop
Date: Tue, 02 Apr 2013 16:48:35 +0100
To: perlbug [...]
From: dom [...]
Download (untitled) / with headers
text/plain 5.1k
This is a bug report for perl from, generated with the help of perlbug 1.39 running under perl 5.17.10. ----------------------------------------------------------------- [Please describe your issue here] The following bug was reported in Debian: <> The test program which follows demonstrates that, contrary to all available documentation (perlfunc and the minimal GDBM_File doc) the current entry cannot be deleted from a GDBM tied hash: #! /usr/bin/perl use GDBM_File; use warnings; %iddb = (); tie %iddb, 'GDBM_File', './weird', &GDBM_WRCREAT|&GDBM_NOLOCK, 0600; for (1..20) { $iddb{"$_"} = $_; } print "Before deletion:\n\n"; while (my ($k, $v) = each %iddb) { print "$k:$v\n"; } while (1) { sleep 1; $k = each %iddb; print "k is $k\n"; delete $iddb{$k} if $k > 15; } Immediately after the delete, each apparently returns undef. This behaviour appears to have been the case since roughly forever[1] but it does go against documentated behaviour, so does appear to be a genuine bug as far as I can see. From perlfunc: After "each" has returned all entries from the hash or array, the next call to "each" returns the empty list in list context and "undef" in scalar context; the next call following that one restarts iteration. Each hash or array has its own internal iterator, accessed by "each", "keys", and "values". The iterator is implicitly reset when "each" has reached the end as just described; it can be explicitly reset by calling "keys" or "values" on the hash or array. If you add or delete a hash's elements while iterating over it, entries may be skipped or duplicated--so don't do that. Exception: In the current implementation, it is always safe to delete the item most recently returned by "each()", so the following code works properly: while (($key, $value) = each %hash) { print $key, "\n"; delete $hash{$key}; # This is safe } [1] <> [Please do not change anything below this line] ----------------------------------------------------------------- --- Flags: category=library severity=low module=GDBM_File --- Site configuration information for perl 5.17.10: Configured by dom at Sun Mar 31 23:53:26 BST 2013. Summary of my perl5 (revision 5 version 17 subversion 10) configuration: Platform: osname=linux, osvers=3.2.0-4-686-pae, archname=i686-linux uname='linux callisto 3.2.0-4-686-pae #1 smp debian 3.2.39-2 i686 gnulinux ' config_args='-de -Dprefix=/home/dom/perl5/perlbrew/perls/perl-5.17.10 -Dusedevel' hint=recommended, useposix=true, d_sigaction=define useithreads=undef, usemultiplicity=undef useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef use64bitint=undef, use64bitall=undef, uselongdouble=undef usemymalloc=n, bincompat5005=undef Compiler: cc='cc', ccflags ='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64', optimize='-O2', cppflags='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include' ccversion='', gccversion='4.7.2', gccosandvers='' intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12 ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8 alignbytes=4, prototype=define Linker and Libraries: ld='cc', ldflags =' -fstack-protector -L/usr/local/lib' libpth=/usr/local/lib /lib/i386-linux-gnu /lib/../lib /usr/lib/i386-linux-gnu /usr/lib/../lib /lib /usr/lib libs=-lnsl -ldl -lm -lcrypt -lutil -lc perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc libc=, so=so, useshrplib=false, libperl=libperl.a gnulibc_version='2.13' Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E' cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector' Locally applied patches: --- @INC for perl 5.17.10: /home/dom/perl5/perlbrew/perls/perl-5.17.10/lib/site_perl/5.17.10/i686-linux /home/dom/perl5/perlbrew/perls/perl-5.17.10/lib/site_perl/5.17.10 /home/dom/perl5/perlbrew/perls/perl-5.17.10/lib/5.17.10/i686-linux /home/dom/perl5/perlbrew/perls/perl-5.17.10/lib/5.17.10 . --- Environment for perl 5.17.10: HOME=/home/dom LANG=en_GB.UTF-8 LANGUAGE (unset) LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/home/dom/perl5/perlbrew/bin:/home/dom/perl5/perlbrew/perls/perl-5.17.10/bin:~/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games PERLBREW_MANPATH=/home/dom/perl5/perlbrew/perls/perl-5.17.10/man PERLBREW_PATH=/home/dom/perl5/perlbrew/bin:/home/dom/perl5/perlbrew/perls/perl-5.17.10/bin PERLBREW_PERL=perl-5.17.10 PERLBREW_ROOT=/home/dom/perl5/perlbrew PERLBREW_SKIP_INIT=1 PERLBREW_VERSION=0.43 PERL_BADLANG (unset) SHELL=/bin/bash
Subject: Re: [perl #117449] GDBM tied hash weirdness; deletion ends 'each' loop
From: Zefram <zefram [...]>
Date: Fri, 15 Dec 2017 09:56:36 +0000
To: perl5-porters [...]
Download (untitled) / with headers
text/plain 509b
This weirdness arises because deleting from a gdbm hash can reorganise the hash. Unlike Perl's own hashes, gdbm has no exception for deleting the current entry. This is explained at some length in the gdbm documentation. It is therefore impossible to make such deletion work as desired, without making GDBM_File a far thicker layer over libgdbm than it is clearly intended to be. I have put a note about this issue in the GDBM_File documention in commit 3752113a3158d060bec97da2512b1549afb5b4c7. -zefram

This service is sponsored and maintained by Best Practical Solutions and runs on infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at