Warnings on exit when DBI handle is global variable and there is assignment from subroutine
perl 5.40 prints warnings on exit when DBI handle is global variable and there is assignment from subroutine.
Module: DBI 1.647
Description The code below prints warnings on exit:
#!/usr/bin/env perl
use strict;
use warnings;
use DBI;
my $dbh = DBI->connect("dbi:Pg:dbname=db1", "user1", "password");
print "DONE\n";
exit 0;
sub sub1 {
$dbh = "";
}
Result:
DONE
DBI dr handle 0x35f181.6477a42be8 cleared whilst still active during global destruction.
DBI dr handle 0x35f187a42be8 has 1 uncleared child handles during global destruction.
dbih_clearcom (drh 0x35f187a42be8, com 0x35f1870ac000, imp DBD::Pg::dr):
FLAGS 0x100215: COMSET Active Warn PrintWarn AutoCommit
PARENT undef
KIDS 1 (1 Active)
The script completed without warnings with perl 5.36 and the same version of DBI. Not tested with 5.38. No warnings if remove $dbh assignment in sub1() which never called.
Steps to Reproduce Execute the script with perl 5.40.
Expected behavior No warnings.
Perl configuration
Summary of my perl5 (revision 5 version 40 subversion 2) configuration:
Platform:
osname=freebsd
osvers=14.2-release-p3
archname=amd64-freebsd-thread-multi
uname='freebsd 142amd64-default-job-01 14.2-release-p3 freebsd 14.2-release-p3 amd64 '
config_args='-Darchlib=/usr/local/lib/perl5/5.40/mach -Dcc=cc -Dcf_by=mat [email protected] -Dcf_time=Sun Apr 13 13:07:13 UTC 2025 -Dinc_version_list=none -Dlibperl=libperl.so.5.40.2 -Dman1dir=/usr/local/lib/perl5/5.40/perl/man/man1 -Dman3dir=/usr/local/lib/perl5/5.40/perl/man/man3 -Dprefix=/usr/local -Dprivlib=/usr/local/lib/perl5/5.40 -Dscriptdir=/usr/local/bin -Dsitearch=/usr/local/lib/perl5/site_perl/mach/5.40 -Dsitelib=/usr/local/lib/perl5/site_perl -Dsiteman1dir=/usr/local/lib/perl5/site_perl/man/man1 -Dsiteman3dir=/usr/local/lib/perl5/site_perl/man/man3 -Dusenm=n -Duseshrplib -sde -Ui_iconv -Ui_malloc -Uinstallusrbinperl -Alddlflags=-L/wrkdirs/usr/ports/lang/perl5.40/work/perl-5.40.2 -L/usr/local/lib/perl5/5.40/mach/CORE -lperl -Dshrpldflags=$(LDDLFLAGS:N-L/wrkdirs/usr/ports/lang/perl5.40/work/perl-5.40.2:N-L/usr/local/lib/perl5/5.40/mach/CORE:N-lperl) -Wl,-soname,$(LIBPERL:R) -Doptimize=-O2 -pipe -fstack-protector-strong -fno-strict-aliasing -Dusedtrace -Ui_gdbm -Dusemultiplicity=y -Duse64bitint -Dusemymalloc=n -Dusethreads=y'
hint=recommended
useposix=true
d_sigaction=define
useithreads=define
usemultiplicity=define
use64bitint=define
use64bitall=define
uselongdouble=undef
usemymalloc=n
default_inc_excludes_dot=define
Compiler:
cc='cc'
ccflags ='-DHAS_FPSETMASK -DHAS_FLOATINGPOINT_H -DNO_POSIX_2008_LOCALE -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
optimize='-O2 -pipe -fstack-protector-strong -fno-strict-aliasing '
cppflags='-DHAS_FPSETMASK -DHAS_FLOATINGPOINT_H -DNO_POSIX_2008_LOCALE -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
ccversion=''
gccversion='FreeBSD Clang 18.1.6 (https://github.com/llvm/llvm-project.git llvmorg-18.1.6-0-g1118c2e05e67)'
gccosandvers=''
intsize=4
longsize=8
ptrsize=8
doublesize=8
byteorder=12345678
doublekind=3
d_longlong=define
longlongsize=8
d_longdbl=define
longdblsize=16
longdblkind=3
ivtype='long'
ivsize=8
nvtype='double'
nvsize=8
Off_t='off_t'
lseeksize=8
alignbytes=8
prototype=define
Linker and Libraries:
ld='cc'
ldflags ='-pthread -Wl,-E -fstack-protector-strong -L/usr/local/lib'
libpth=/usr/lib /usr/local/lib /usr/lib/clang/18/lib
libs=-ldl -lm -lcrypt -lutil
perllibs=-ldl -lm -lcrypt -lutil
libc=
so=so
useshrplib=true
libperl=libperl.so.5.40.2
gnulibc_version=''
Dynamic Linking:
dlsrc=dl_dlopen.xs
dlext=so
d_dlsymun=undef
ccdlflags=' -Wl,-R/usr/local/lib/perl5/5.40/mach/CORE'
cccdlflags='-DPIC -fPIC'
lddlflags='-shared -L/usr/local/lib/perl5/5.40/mach/CORE -lperl -L/usr/local/lib -fstack-protector-strong'
Characteristics of this binary (from libperl):
Compile-time options:
HAS_LONG_DOUBLE
HAS_STRTOLD
HAS_TIMES
MULTIPLICITY
PERLIO_LAYERS
PERL_COPY_ON_WRITE
PERL_DONT_CREATE_GVSV
PERL_HASH_FUNC_SIPHASH13
PERL_HASH_USE_SBOX32
PERL_MALLOC_WRAP
PERL_OP_PARENT
PERL_PRESERVE_IVUV
PERL_USE_SAFE_PUTENV
USE_64_BIT_ALL
USE_64_BIT_INT
USE_ITHREADS
USE_LARGE_FILES
USE_LOCALE
USE_LOCALE_COLLATE
USE_LOCALE_CTYPE
USE_LOCALE_NUMERIC
USE_LOCALE_TIME
USE_PERLIO
USE_PERL_ATOF
USE_REENTRANT_API
Built under freebsd
@INC:
/usr/local/lib/perl5/site_perl/mach/5.40# perl -V output goes here
/usr/local/lib/perl5/site_perl
/usr/local/lib/perl5/5.40/mach
/usr/local/lib/perl5/5.40
This is a problem with DBI, which apparently needs to take more care to close down its connections in the right order during global destruction.
Why the same DBI version with perl 5.36 doesn't print the warning? Why sub1() that do nothing and has no references in code causes the warning?
@karenetheridge suggestions on improvement welcome! I know however from other DBD's that having structures that share connections are sometimes (very) hard to free. e.g. if freeing needs to wait for a database sync to disconnect
On Mon, May 19, 2025 at 05:06:56AM -0700, vvv2542 wrote:
The code below prints warnings on exit:
#!/usr/bin/env perl use strict; use warnings; use DBI; my $dbh = DBI->connect("dbi:Pg:dbname=db1", "user1", "password"); print "DONE\n"; exit 0; sub sub1 { $dbh = ""; }
Note that, by referring to $dbh within the sub, you're creating a closure. This can delay or alter the point at which $dbh is destroyed.
Whether this is then showing up an issue with DBI, or with perl, or is simply a "don't do this", I can't say off-hand.
-- This is a great day for France! -- Nixon at Charles De Gaulle's funeral
I've encountered a similar situation in my own code when moving from 5.38 to 5.40
What is interesting is that the errors are not reproducible. So far, I've been unable to reproduce the error by running the work load again. Not sure why yet.
Two nodes, running the same code, against similar databases, won't necessarily encounter the error when doing the same set of work. Again, not sure why. Given the data and work, if one node hits the error, everything running that same code should as well.
Why the same DBI version with perl 5.36 doesn't print the warning? Why sub1() that do nothing and has no references in code causes the warning?
My testing on FreeBSD 14.2 with PostgreSQL 16 gives the same error
[23:53 dev-ingress01 dvl ~/scripts] % perl perl5-issue-23306
DONE
DBI dr handle 0x13b121641a68 cleared whilst still active during global destruction.
dbih_clearcom (drh 0x13b121641a68, com 0x13b120cb12c0, imp DBD::Pg::dr):
FLAGS 0x100215: COMSET Active Warn PrintWarn AutoCommit
PARENT undef
KIDS 0 (1 Active)
[23:53 dev-ingress01 dvl ~/scripts] %
If I remove sub1 the error does not appear or comment out the $dbh = ""; line, the error does not appear.
During global destruction, the order in which resources are freed can be pretty random, so depending on the order in which things can happen, something can expect something to still exist which surprisingly does not.
Is there some graceful disconnecting or teardowns that you can do in an END{} block, or in the destructor for a particular object?
I my case adding END{} solves the problem. But I don't understand why in different scripts helps $dbh->disconnect, or $dbh=undef, or both. The solution for a particular script is unpredictable. But the problem is always reproducible.
What is this END{}? Am I doing it wrong?
[11:31 dev-ingress01 dvl ~/scripts] % perl perl5-issue-23306
DONE
DBI dr handle 0x3ab457c41ac8 cleared whilst still active during global destruction.
dbih_clearcom (drh 0x3ab457c41ac8, com 0x3ab4572b12c0, imp DBD::Pg::dr):
FLAGS 0x100215: COMSET Active Warn PrintWarn AutoCommit
PARENT undef
KIDS 0 (1 Active)
[11:31 dev-ingress01 dvl ~/scripts] % cat perl5-issue-23306
#!/usr/bin/env perl
use strict;
use warnings;
use DBI;
#require FreshPorts::config;
my $dbh = DBI->connect("dbi:Pg:dbname=freshports.dev;host=pg03.example.org", "redacted", 'redacted);
print "DONE\n";
exit 0;
sub sub1 {
$dbh = "";
}
END{}
Try
END {
$dbh->disconnect;
$dbh = undef;
}
That resolves my test issue. In my case, I think it's a race condition, since the same test does not fail on all hosts every time.
END { $dbh->disconnect; $dbh = undef; }
I would recommend changing that to $dbh->disconnect if $dbh, if you end the script before $dbh is connected you'll get a weird and confusing error otherwise.
I think it's a race condition, since the same test does not fail on all hosts every time.
No it's not a race condition, it's just unorderedness like @karenetheridge explained.
I created https://github.com/perl5-dbi/dbi/issues/171
I had a package like this:
#!/usr/local/bin/perl -w
#
# Copyright (c) 2014 DVL Software
#
package FreshPorts::Branches;
...
sub SetBranchInDB($$) {
my $dbh = shift();
my $branch = shift();
$sql = 'select freshports_branch_set(' . $dbh->quote($branch) . ')';
$sth = $dbh->prepare($sql);
if (!$sth->execute()) {
FreshPorts::Utilities::Report('warning', "SetBranchInDB: Could not set branch:" . $dbh->errstr);
}
$sth->finish();
undef $sth;
}
1;
Adding the undef $sth; removed this error for me:
DBI db handle 0x210727eb2090 has 1 uncleared child handles during global destruction.
dbih_clearcom (dbh 0x210727eb2090, com 0x210727ab6780, imp DBD::Pg::db):
FLAGS 0x500111: COMSET Warn PrintError PrintWarn
PARENT DBI::dr=HASH(0x210727eb3258)
KIDS 1 (0 Active)
This changes my approach to cleaning up this error under Perl 5.40 - previously, I was looking mostly at $sth->finish();
IMHO it is the DBD that should guarantee the correct order of destruction, not the DBI. If someone could point me at how the DBI should/could do that, I could steer towards a release.
See e.g.: https://github.com/perl5-dbi/DBD-Unify/blob/master/dbdimp.ic#L902
DBD::Pg hasn't had this problem with any version of Perl through Perl 5.38, but it's somehow DBI or the DBDs which are at fault here? Okaaaaaaayyy....
The same problem with DBD::mysql also starting from perl 5.40. I still think that the reason is the change in perl's behavior.
Has someone tried to bisect the change in behavior? Right now we don't even know which development release was involved.
FWIW: I couldn't reproduce this using the OP test script and following combination, all built from source:
- Perl 5.40.0
- DBI 1.647
- DBD:Pg 3.18.0
I'll do a 5.40.2 build, just in case it was something in a maint release.
I'll do a 5.40.2 build, just in case it was something in a maint release.
Nope, still can't reproduce with 5.40.2 built from source. Those were gcc builds, will try with clang, since that's what the OP's perl was built with.
# DBI Version 1.647
# DBD::Pg Version 3.18.0
# Perl Version 5.40.2
# OS linux
# PostgreSQL (compiled) 150013
# PostgreSQL (target) 150013
# PostgreSQL (reported) PostgreSQL 15.13 (Debian 15.13-0+deb12u1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14+deb12u1) 12.2.0, 64-bit
I couldn't reproduce with clang on this VM either. No warnings from threaded or non-threaded builds.
Not sure if it's a build environment difference or what.
Summary of my perl5 (revision 5 version 40 subversion 2) configuration:
Commit id: 2e0f6a60c12ff9b5fd18e5a18d350b4366ea12b7
Platform:
osname=linux
osvers=6.1.0-35-amd64
archname=x86_64-linux
uname='linux perlporting 6.1.0-35-amd64 #1 smp preempt_dynamic debian 6.1.137-1 (2025-05-07) x86_64 gnulinux '
config_args='-des -Dusethreds -Dcc=clang-14 -Dprefix=/home/rich/installs/5.40.2_clang'
hint=recommended
useposix=true
d_sigaction=define
useithreads=undef
usemultiplicity=undef
use64bitint=define
use64bitall=define
uselongdouble=undef
usemymalloc=n
default_inc_excludes_dot=define
Compiler:
cc='clang-14'
ccflags ='-fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'
optimize='-O2'
cppflags='-fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
ccversion=''
gccversion='Debian Clang 14.0.6'
gccosandvers=''
intsize=4
longsize=8
ptrsize=8
doublesize=8
byteorder=12345678
doublekind=3
d_longlong=define
longlongsize=8
d_longdbl=define
longdblsize=16
longdblkind=3
ivtype='long'
ivsize=8
nvtype='double'
nvsize=8
Off_t='off_t'
lseeksize=8
alignbytes=8
prototype=define
Linker and Libraries:
ld='clang-14'
ldflags =' -fstack-protector-strong -L/usr/local/lib'
libpth=/usr/lib/llvm-14/lib/clang/14.0.6/lib /usr/local/lib /usr/lib/x86_64-linux-gnu /usr/lib /usr/lib64
libs=-lpthread -ldl -lm -lcrypt -lutil -lc
perllibs=-lpthread -ldl -lm -lcrypt -lutil -lc
libc=/lib/x86_64-linux-gnu/libc.so.6
so=so
useshrplib=false
libperl=libperl.a
gnulibc_version='2.36'
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-strong'
Characteristics of this binary (from libperl):
Compile-time options:
HAS_LONG_DOUBLE
HAS_STRTOLD
HAS_TIMES
PERLIO_LAYERS
PERL_COPY_ON_WRITE
PERL_DONT_CREATE_GVSV
PERL_HASH_FUNC_SIPHASH13
PERL_HASH_USE_SBOX32
PERL_MALLOC_WRAP
PERL_OP_PARENT
PERL_PRESERVE_IVUV
PERL_USE_SAFE_PUTENV
USE_64_BIT_ALL
USE_64_BIT_INT
USE_LARGE_FILES
USE_LOCALE
USE_LOCALE_COLLATE
USE_LOCALE_CTYPE
USE_LOCALE_NUMERIC
USE_LOCALE_TIME
USE_PERLIO
USE_PERL_ATOF
Built under linux
Compiled at Jun 3 2025 20:52:54
@INC:
/home/rich/installs/5.40.2_clang/lib/perl5/site_perl/5.40.2/x86_64-linux
/home/rich/installs/5.40.2_clang/lib/perl5/site_perl/5.40.2
/home/rich/installs/5.40.2_clang/lib/perl5/5.40.2/x86_64-linux
/home/rich/installs/5.40.2_clang/lib/perl5/5.40.2
# DBI Version 1.647
# DBD::Pg Version 3.18.0
# Perl Version 5.40.2
# OS linux
# PostgreSQL (compiled) 150013
# PostgreSQL (target) 150013
# PostgreSQL (reported) PostgreSQL 15.13 (Debian 15.13-0+deb12u1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14+deb12u1) 12.2.0, 64-bit
@richardleach wrote:
I couldn't reproduce with clang on this VM either. No warnings from threaded or non-threaded builds.
Not sure if it's a build environment difference or what.
Very interesting! Thanks for doing all that testing, @richardleach.
@vvv2542 : Can you provide additional details on your builds and host configuration?
Can you reproduce this error in a Docker container and share the Dockerfile? That would be unimpeachable, I think.
I can reproduce it only on FreeBSD:
- Install FreeBSD 14.2-RELEASE.
- Replace "quarterly" to "latest" in /etc/pkg/FreeBSD.conf.
- Run "pkg install p5-DBD-Pg".
- Run script from the first message.
I also tried to rebuild perl, DBI, DBD from ports with gcc instead of default clang. But the problem was not solved.
I can reproduce it only on FreeBSD:
1. Install FreeBSD 14.2-RELEASE. 2. Replace "quarterly" to "latest" in /etc/pkg/FreeBSD.conf. 3. Run "pkg install p5-DBD-Pg". 4. Run script from the first message.
I'm trying to follow these instructions, but on the FreeBSD-14 server to which I have access, I don't normally have any databases running. I suspect that there's something missing between steps 3 and 4 above -- something along the lines of "turn a Postgresql server on". This is what I get when I run the program from the first post:
[perlmonger: perl-5.40.0] $ ./bin/perl -Ilib $P5P_DIR/gh-23306-dbi.pl
DBI connect('dbname=db1','user1',...) failed: connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory
Is the server running locally and accepting connections on that socket? at /home/jkeenan/learn/perl/p5p/gh-23306-dbi.pl line 7.
DONE
Please advise.
You can use any remote postgres database:
my $dbh = DBI->connect("dbi:Pg:dbname=db1;host=db.host.org", "user1", "password");
Or install local:
pkg install -y postgresql17-server
mkdir -p /usr/local/etc/rc.conf.d
echo "postgresql_enable=YES" >/usr/local/etc/rc.conf.d/postgresql
service postgresql initdb
service postgresql start
And connect with default credentials:
my $dbh = DBI->connect("dbi:Pg:dbname=template1", "postgres", "");
If requested, I can provide ssh-access to a FreeBSD resource where this problem can be reproduced.
If requested, I can provide ssh-access to a FreeBSD resource where this problem can be reproduced.
I have created a new environment from scratch following the instructions above. It can reproduce the problem:
[18:18 perl540 root ~] # perl perl5-issue-23306
DONE
DBI dr handle 0x1a8fa5e41a68 cleared whilst still active during global destruction.
dbih_clearcom (drh 0x1a8fa5e41a68, com 0x1a8fa54b12c0, imp DBD::Pg::dr):
FLAGS 0x100215: COMSET Active Warn PrintWarn AutoCommit
PARENT undef
KIDS 0 (1 Active)
[18:18 perl540 root ~] # cat perl5-issue-23306
#!/usr/bin/env perl
use strict;
use warnings;
use DBI;
#require FreshPorts::config;
my $dbh = DBI->connect("dbi:Pg:dbname=template1;", "postgres");
print "DONE\n";
exit 0;
sub sub1 {
$dbh = "";
}
[18:19 perl540 root ~] #
[18:19 perl540 root ~] # pkg info
gettext-runtime-0.23.1 GNU gettext runtime libraries and programs
icu-76.1,1 International Components for Unicode (from IBM)
indexinfo-0.3.1_1 Utility to regenerate the GNU info page index
joe-4.6_1,1 Joe's Own Editor
libedit-3.1.20250104,1 Command line editor library
libffi-3.4.8 Foreign Function Interface
liblz4-1.10.0,1 LZ4 compression library, lossless and very fast
libxml2-2.11.9 XML parser library for GNOME
llvm19-19.1.7_1 LLVM and Clang
lua53-5.3.6_1 Powerful, efficient, lightweight, embeddable scripting language
mpdecimal-4.0.1 C/C++ arbitrary precision decimal floating point libraries
p5-DBD-Pg-3.18.0 Provides access to PostgreSQL databases through the DBI
p5-DBI-1.647 Perl5 Database Interface, required for DBD::* modules
perl5-5.40.2_2 Practical Extraction and Report Language
pkg-2.1.4 Package manager
postgresql17-client-17.5 PostgreSQL database (client)
postgresql17-server-17.5 PostgreSQL is the most advanced open-source database available anywhere
python311-3.11.12_1 Interpreted object-oriented programming language
readline-8.2.13_2 Library for editing command lines as they are typed
zsh-5.9_5 The Z shell
zstd-1.5.7 Fast real-time compression algorithm
If requested, I can provide ssh-access to a FreeBSD resource where this problem can be reproduced.
I have created a new environment from scratch following the instructions above. It can reproduce the problem:
[18:18 perl540 root ~] # perl perl5-issue-23306 DONE
Do you have to be root in this (or any) environment to reproduce this problem?
If requested, I can provide ssh-access to a FreeBSD resource where this problem can be reproduced.
I have created a new environment from scratch following the instructions above. It can reproduce the problem:
[18:18 perl540 root ~] # perl perl5-issue-23306 DONEDo you have to be
rootin this (or any) environment to reproduce this problem?
No, my original tests were as non-root. I'll go back to this new environment and try again.
For the record, I just created a new user, enabled sshd and ssh-d into the 'host'.
perl540% cd /root
perl540% ls -l
total 5
-rw-r--r-- 1 root wheel 207 Jun 11 18:18 perl5-issue-23306
perl540% perl perl5-issue-23306
DONE
DBI dr handle 0x5f2b62419d8 cleared whilst still active during global destruction.
dbih_clearcom (drh 0x5f2b62419d8, com 0x5f2b58aa2c0, imp DBD::Pg::dr):
FLAGS 0x100215: COMSET Active Warn PrintWarn AutoCommit
PARENT undef
KIDS 0 (1 Active)
perl540% id
uid=1001(dvl) gid=1001(dvl) groups=1001(dvl),0(wheel)
perl540%