diff --git a/lib/DBIx/Class/Storage.pm b/lib/DBIx/Class/Storage.pm index 45839e105..893d0224a 100644 --- a/lib/DBIx/Class/Storage.pm +++ b/lib/DBIx/Class/Storage.pm @@ -431,12 +431,14 @@ sub svp_release { if (defined $name) { my @stack = @{ $self->savepoints }; - my $svp; + my $svp = pop @stack; - do { $svp = pop @stack } until $svp eq $name; + while (@stack and $svp ne $name) { + $svp = pop @stack + }; $self->throw_exception ("Savepoint '$name' does not exist") - unless $svp; + unless $svp and $svp eq $name; $self->savepoints(\@stack); # put back what's left } 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") });