Skip to content

Commit

Permalink
avoid closing over values in string eval when comparing values
Browse files Browse the repository at this point in the history
When comparing values using Test::Builder::cmp_ok, a string eval is
used to match the caller location, and to inject an arbitrary comparison
op. When used with Devel::Cover, the string eval may close over any
variables used in it, and maintain them for the lifetime of the program.

Instead of comparing the values directly in the string eval, generate an
anonymous sub that will perform the comparison, and call it in a block
eval.

This is a reoccurrance of a previous problem that was fixed with
4fe707c. Some combination of perl or
module updates has brought back the issue. While there was a test
included with the bug, it only fails when run with Devel::Cover, which
isn't done during the automated or release testing.
  • Loading branch information
haarg committed Jan 18, 2025
1 parent 10d1204 commit a49f733
Showing 1 changed file with 12 additions and 2 deletions.
14 changes: 12 additions & 2 deletions lib/Test/Builder.pm
Original file line number Diff line number Diff line change
Expand Up @@ -963,13 +963,23 @@ sub cmp_ok {
# over it, which can lead to issues with Devel::Cover
my $bits_code = defined $warning_bits ? qq["\Q$warning_bits\E"] : 'undef';

# This is so that warnings come out at the caller's level
# Make sure warnings and location matches the caller. Can't do the
# comparison directly in the eval, as closing over variables can
# capture them forever when running with Devel::Cover.
my $check;
$succ = eval qq[
BEGIN {\${^WARNING_BITS} = $bits_code};
#line $line "(eval in cmp_ok) $file"
\$test = (\$got $type \$expect);
\$check = sub { \$_[0] $type \$_[1] };
1;
];

if ($succ) {
$succ = eval {
$test = $check->($got, $expect);
1;
};
}
$error = $@;
}
local $Level = $Level + 1;
Expand Down

0 comments on commit a49f733

Please sign in to comment.