From 50ba8f0da90c7ef0151c8269fbffbda63e35a1db Mon Sep 17 00:00:00 2001 From: Paul Mooney Date: Thu, 10 Mar 2016 10:50:57 +0000 Subject: [PATCH 1/4] Avoid infinite loop if save point does not exist --- lib/DBIx/Class/Storage.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/DBIx/Class/Storage.pm b/lib/DBIx/Class/Storage.pm index 45839e105..4e9cdacc3 100644 --- a/lib/DBIx/Class/Storage.pm +++ b/lib/DBIx/Class/Storage.pm @@ -433,7 +433,9 @@ sub svp_release { my @stack = @{ $self->savepoints }; my $svp; - do { $svp = pop @stack } until $svp eq $name; + while (@stack and $stack[-1] ne $name) { + $svp = pop @stack + }; $self->throw_exception ("Savepoint '$name' does not exist") unless $svp; From 3498dc0ab7195759a38043cee3ef516f306e72a5 Mon Sep 17 00:00:00 2001 From: Paul Mooney Date: Thu, 10 Mar 2016 11:10:44 +0000 Subject: [PATCH 2/4] make sure we pop the savepoint off the stack --- lib/DBIx/Class/Storage.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/DBIx/Class/Storage.pm b/lib/DBIx/Class/Storage.pm index 4e9cdacc3..7a2ef132b 100644 --- a/lib/DBIx/Class/Storage.pm +++ b/lib/DBIx/Class/Storage.pm @@ -431,9 +431,9 @@ sub svp_release { if (defined $name) { my @stack = @{ $self->savepoints }; - my $svp; + my $svp = pop @stack; - while (@stack and $stack[-1] ne $name) { + while (@stack and $svp ne $name) { $svp = pop @stack }; From db85531f06b8f67a7af9ca3440e6038bb859c485 Mon Sep 17 00:00:00 2001 From: Paul Mooney Date: Thu, 10 Mar 2016 11:16:22 +0000 Subject: [PATCH 3/4] Really really fail if the savepoint is not on the stack --- lib/DBIx/Class/Storage.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/DBIx/Class/Storage.pm b/lib/DBIx/Class/Storage.pm index 7a2ef132b..893d0224a 100644 --- a/lib/DBIx/Class/Storage.pm +++ b/lib/DBIx/Class/Storage.pm @@ -438,7 +438,7 @@ sub svp_release { }; $self->throw_exception ("Savepoint '$name' does not exist") - unless $svp; + unless $svp and $svp eq $name; $self->savepoints(\@stack); # put back what's left } From 0cd00adecb85c73817c0beb0a750267b90d01072 Mon Sep 17 00:00:00 2001 From: Paul Mooney Date: Wed, 16 Mar 2016 11:50:33 +0000 Subject: [PATCH 4/4] Test we do not go into an infinite loop calling svp_release() --- t/storage/savepoints.t | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/t/storage/savepoints.t b/t/storage/savepoints.t index 66b7d71a4..4a11892ef 100644 --- a/t/storage/savepoints.t +++ b/t/storage/savepoints.t @@ -247,6 +247,19 @@ SKIP: { undef, 'rollback from inner transaction'; } + # Check we do not go into an infinite loop calling svp_release() with a + # savepoint that is not on the stack + eval { + local $SIG{ALRM} = sub { die "infinite loop\n" }; + alarm 3; + $schema->txn_do(sub { + $schema->svp_release('wibble'); + }); + alarm 0; + }; + my $error = $@; + like $error, qr/Savepoint 'wibble' does not exist/, + "Calling svp_release on a non-existant savepoint throws expected error"; ### cleanupz $schema->storage->dbh_do(sub { $_[1]->do("DROP TABLE artist") });