Blame SOURCES/DB_File-1.838-Destroy-DB_File-objects-only-from-original-thread-co.patch

2e68c7
From bfb2cb3cddffa144b521bb5dff76af1e065288ad Mon Sep 17 00:00:00 2001
2e68c7
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
2e68c7
Date: Tue, 10 Jun 2014 14:28:09 +0200
2e68c7
Subject: [PATCH] Destroy DB_File objects only from original thread context
2e68c7
MIME-Version: 1.0
2e68c7
Content-Type: text/plain; charset=UTF-8
2e68c7
Content-Transfer-Encoding: 8bit
2e68c7
2e68c7
This patch fixes a crash when destroing a hash tied to a DB_File
2e68c7
database after spawning a thread:
2e68c7
2e68c7
use Fcntl;
2e68c7
use DB_File;
2e68c7
use threads;
2e68c7
tie(my %dbtest, 'DB_File', "test.db", O_RDWR|O_CREAT, 0666);
2e68c7
threads->new(sub {})->join;
2e68c7
2e68c7
This crashed or paniced depending on how perl was configured.
2e68c7
2e68c7
Closes RT#61912.
2e68c7
2e68c7
Signed-off-by: Petr Písař <ppisar@redhat.com>
2e68c7
---
2e68c7
 DB_File.xs     | 50 +++++++++++++++++++++++++++++++-------------------
2e68c7
 MANIFEST       |  1 +
2e68c7
 t/db-threads.t | 46 ++++++++++++++++++++++++++++++++++++++++++++++
2e68c7
 3 files changed, 78 insertions(+), 19 deletions(-)
2e68c7
 create mode 100644 t/db-threads.t
2e68c7
2e68c7
diff --git a/DB_File.xs b/DB_File.xs
2e68c7
index f417b22..ed6a904 100755
2e68c7
--- a/DB_File.xs
2e68c7
+++ b/DB_File.xs
2e68c7
@@ -407,6 +407,7 @@ typedef union INFO {
2e68c7
 
2e68c7
 typedef struct {
2e68c7
 	DBTYPE	type ;
2e68c7
+	tTHX    owner ;
2e68c7
 	DB * 	dbp ;
2e68c7
 	SV *	compare ;
2e68c7
 	bool	in_compare ;
2e68c7
@@ -1006,6 +1007,7 @@ SV *   sv ;
2e68c7
 		    name, flags, mode, sv == NULL) ;  
2e68c7
 #endif
2e68c7
     Zero(RETVAL, 1, DB_File_type) ;
2e68c7
+    RETVAL->owner = aTHX;
2e68c7
 
2e68c7
     /* Default to HASH */
2e68c7
     RETVAL->filtering = 0 ;
2e68c7
@@ -1278,6 +1280,7 @@ SV *   sv ;
2e68c7
 
2e68c7
 /* printf("In ParseOpenInfo name=[%s] flags=[%d] mode = [%d]\n", name, flags, mode) ;  */
2e68c7
     Zero(RETVAL, 1, DB_File_type) ;
2e68c7
+    RETVAL->owner = aTHX;
2e68c7
 
2e68c7
     /* Default to HASH */
2e68c7
     RETVAL->filtering = 0 ;
2e68c7
@@ -1597,27 +1600,36 @@ db_DESTROY(db)
2e68c7
 	INIT:
2e68c7
 	  CurrentDB = db ;
2e68c7
 	  Trace(("DESTROY %p\n", db));
2e68c7
-	CLEANUP:
2e68c7
-	  Trace(("DESTROY %p done\n", db));
2e68c7
-	  if (db->hash)
2e68c7
-	    SvREFCNT_dec(db->hash) ;
2e68c7
-	  if (db->compare)
2e68c7
-	    SvREFCNT_dec(db->compare) ;
2e68c7
-	  if (db->prefix)
2e68c7
-	    SvREFCNT_dec(db->prefix) ;
2e68c7
-	  if (db->filter_fetch_key)
2e68c7
-	    SvREFCNT_dec(db->filter_fetch_key) ;
2e68c7
-	  if (db->filter_store_key)
2e68c7
-	    SvREFCNT_dec(db->filter_store_key) ;
2e68c7
-	  if (db->filter_fetch_value)
2e68c7
-	    SvREFCNT_dec(db->filter_fetch_value) ;
2e68c7
-	  if (db->filter_store_value)
2e68c7
-	    SvREFCNT_dec(db->filter_store_value) ;
2e68c7
-	  safefree(db) ;
2e68c7
+	CODE:
2e68c7
+	  RETVAL = 0;
2e68c7
+	  if (db && db->owner == aTHX) {
2e68c7
+	    RETVAL = db_DESTROY(db);
2e68c7
 #ifdef DB_VERSION_MAJOR
2e68c7
-	  if (RETVAL > 0)
2e68c7
-	    RETVAL = -1 ;
2e68c7
+	    if (RETVAL > 0)
2e68c7
+		RETVAL = -1 ;
2e68c7
 #endif
2e68c7
+	  }
2e68c7
+	OUTPUT:
2e68c7
+	  RETVAL
2e68c7
+	CLEANUP:
2e68c7
+	  Trace(("DESTROY %p done\n", db));
2e68c7
+	  if (db && db->owner == aTHX) {
2e68c7
+	    if (db->hash)
2e68c7
+		SvREFCNT_dec(db->hash) ;
2e68c7
+	    if (db->compare)
2e68c7
+		SvREFCNT_dec(db->compare) ;
2e68c7
+	    if (db->prefix)
2e68c7
+		SvREFCNT_dec(db->prefix) ;
2e68c7
+	    if (db->filter_fetch_key)
2e68c7
+		SvREFCNT_dec(db->filter_fetch_key) ;
2e68c7
+	    if (db->filter_store_key)
2e68c7
+		SvREFCNT_dec(db->filter_store_key) ;
2e68c7
+	    if (db->filter_fetch_value)
2e68c7
+		SvREFCNT_dec(db->filter_fetch_value) ;
2e68c7
+	    if (db->filter_store_value)
2e68c7
+		SvREFCNT_dec(db->filter_store_value) ;
2e68c7
+	    safefree(db) ;
2e68c7
+	  }
2e68c7
 
2e68c7
 
2e68c7
 int
2e68c7
diff --git a/MANIFEST b/MANIFEST
2e68c7
index e460e81..47f43f7 100644
2e68c7
--- a/MANIFEST
2e68c7
+++ b/MANIFEST
2e68c7
@@ -27,6 +27,7 @@ t/db-btree.t
2e68c7
 t/db-hash.t
2e68c7
 t/db-recno.t
2e68c7
 t/pod.t
2e68c7
+t/db-threads.t
2e68c7
 typemap
2e68c7
 version.c
2e68c7
 META.yml                                 Module meta-data (added by MakeMaker)
2e68c7
diff --git a/t/db-threads.t b/t/db-threads.t
2e68c7
new file mode 100644
2e68c7
index 0000000..b9f69b6
2e68c7
--- /dev/null
2e68c7
+++ b/t/db-threads.t
2e68c7
@@ -0,0 +1,46 @@
2e68c7
+#!./perl
2e68c7
+
2e68c7
+use warnings;
2e68c7
+use strict;
2e68c7
+use Config;
2e68c7
+use Fcntl;
2e68c7
+use Test::More;
2e68c7
+use DB_File;
2e68c7
+
2e68c7
+if (-d "lib" && -f "TEST") {
2e68c7
+    if ($Config{'extensions'} !~ /\bDB_File\b/ ) {
2e68c7
+        plan skip_all => 'DB_File was not built';
2e68c7
+    }
2e68c7
+}
2e68c7
+plan skip_all => 'Threads are disabled'
2e68c7
+    unless $Config{usethreads};
2e68c7
+
2e68c7
+plan tests => 7;
2e68c7
+
2e68c7
+# Check DBM back-ends do not destroy objects from then-spawned threads.
2e68c7
+# RT#61912.
2e68c7
+use_ok('threads');
2e68c7
+
2e68c7
+my %h;
2e68c7
+unlink <threads*>;
2e68c7
+
2e68c7
+my $db = tie %h, 'DB_File', 'threads', O_RDWR|O_CREAT, 0640;
2e68c7
+isa_ok($db, 'DB_File');
2e68c7
+
2e68c7
+for (1 .. 2) {
2e68c7
+    ok(threads->create(
2e68c7
+        sub {
2e68c7
+            $SIG{'__WARN__'} = sub { fail(shift) }; # debugging perl panics
2e68c7
+                # report it by spurious TAP line
2e68c7
+            1;
2e68c7
+        }), "Thread $_ created");
2e68c7
+}
2e68c7
+for (threads->list) {
2e68c7
+    is($_->join, 1, "A thread exited successfully");
2e68c7
+}
2e68c7
+
2e68c7
+pass("Tied object survived exiting threads");
2e68c7
+
2e68c7
+undef $db;
2e68c7
+untie %h;
2e68c7
+unlink <threads*>;
2e68c7
-- 
2e68c7
2.5.5
2e68c7