Use a separate connection instance for each pid, since
it is not safe to use a connection created in a parent
process.

See: https://www.sqlite.org/howtocorrupt.html
Bug: https://bugs.gentoo.org/736334
Signed-off-by: Zac Medico <zmed...@gentoo.org>
---
 lib/portage/cache/sqlite.py           |  9 +++++----
 lib/portage/tests/dbapi/test_auxdb.py | 13 +++++++++++--
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/lib/portage/cache/sqlite.py b/lib/portage/cache/sqlite.py
index 0395dd516..36a4f049e 100644
--- a/lib/portage/cache/sqlite.py
+++ b/lib/portage/cache/sqlite.py
@@ -4,6 +4,7 @@
 import collections
 import re
 
+import portage
 from portage.cache import fs_template
 from portage.cache import cache_errors
 from portage import os
@@ -25,7 +26,7 @@ class database(fs_template.FsBased):
        cache_bytes = 1024 * 1024 * 10
 
        _connection_info_entry = 
collections.namedtuple('_connection_info_entry',
-               ('connection', 'cursor'))
+               ('connection', 'cursor', 'pid'))
 
        def __init__(self, *args, **config):
                super(database, self).__init__(*args, **config)
@@ -71,13 +72,13 @@ class database(fs_template.FsBased):
 
        @property
        def _db_cursor(self):
-               if self._db_connection_info is None:
+               if self._db_connection_info is None or 
self._db_connection_info.pid != portage.getpid():
                        self._db_init_connection()
                return self._db_connection_info.cursor
 
        @property
        def _db_connection(self):
-               if self._db_connection_info is None:
+               if self._db_connection_info is None or 
self._db_connection_info.pid != portage.getpid():
                        self._db_init_connection()
                return self._db_connection_info.connection
 
@@ -94,7 +95,7 @@ class database(fs_template.FsBased):
                        connection = self._db_module.connect(
                                database=_unicode_decode(self._dbpath), 
**connection_kwargs)
                        cursor = connection.cursor()
-                       self._db_connection_info = 
self._connection_info_entry(connection, cursor)
+                       self._db_connection_info = 
self._connection_info_entry(connection, cursor, portage.getpid())
                        self._db_cursor.execute("PRAGMA encoding = %s" % 
self._db_escape_string("UTF-8"))
                        if not self.readonly and not 
self._ensure_access(self._dbpath):
                                raise 
cache_errors.InitializationError(self.__class__, "can't ensure perms on %s" % 
self._dbpath)
diff --git a/lib/portage/tests/dbapi/test_auxdb.py 
b/lib/portage/tests/dbapi/test_auxdb.py
index 5c79357d7..7865c3564 100644
--- a/lib/portage/tests/dbapi/test_auxdb.py
+++ b/lib/portage/tests/dbapi/test_auxdb.py
@@ -4,7 +4,8 @@
 from portage.tests import TestCase
 from portage.tests.resolver.ResolverPlayground import ResolverPlayground
 from portage.util.futures import asyncio
-from portage.util.futures.compat_coroutine import coroutine
+from portage.util.futures.compat_coroutine import coroutine, coroutine_return
+from portage.util.futures.executor.fork import ForkExecutor
 
 
 class AuxdbTestCase(TestCase):
@@ -61,8 +62,14 @@ class AuxdbTestCase(TestCase):
 
                portdb = playground.trees[playground.eroot]["porttree"].dbapi
 
+               def test_func():
+                       return 
asyncio._wrap_loop().run_until_complete(self._test_mod_async(
+                               ebuilds, ebuild_inherited, 
eclass_defined_phases, eclass_depend, portdb))
+
+               self.assertTrue(test_func())
+
                loop = asyncio._wrap_loop()
-               loop.run_until_complete(self._test_mod_async(ebuilds, 
ebuild_inherited, eclass_defined_phases, eclass_depend, portdb))
+               
self.assertTrue(loop.run_until_complete(loop.run_in_executor(ForkExecutor(), 
test_func)))
 
        @coroutine
        def _test_mod_async(self, ebuilds, ebuild_inherited, 
eclass_defined_phases, eclass_depend, portdb):
@@ -73,3 +80,5 @@ class AuxdbTestCase(TestCase):
                        self.assertEqual(depend, eclass_depend)
                        self.assertEqual(eapi, metadata['EAPI'])
                        self.assertEqual(frozenset(inherited.split()), 
ebuild_inherited)
+
+               coroutine_return(True)
-- 
2.25.3


Reply via email to