From 2e38cc39330bd7f3003652869b644110a97a78d8 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 29 Apr 2018 12:38:06 +0300 Subject: bpo-33383: Fix crash in get() of the dbm.ndbm database object. (#6630) --- Lib/test/test_dbm.py | 9 +++++++++ Lib/test/test_dbm_dumb.py | 9 +++++++++ Lib/test/test_dbm_gnu.py | 5 ++++- Lib/test/test_dbm_ndbm.py | 10 +++++++++- .../next/Library/2018-04-29-11-15-38.bpo-33383.g32YWn.rst | 2 ++ Modules/_dbmmodule.c | 4 ++-- Modules/clinic/_dbmmodule.c.h | 6 +++--- 7 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-04-29-11-15-38.bpo-33383.g32YWn.rst diff --git a/Lib/test/test_dbm.py b/Lib/test/test_dbm.py index f0a428d..fb89807 100644 --- a/Lib/test/test_dbm.py +++ b/Lib/test/test_dbm.py @@ -86,12 +86,21 @@ class AnyDBMTestCase: f = dbm.open(_fname, 'c') self._dict['g'] = f[b'g'] = b"indented" self.read_helper(f) + # setdefault() works as in the dict interface + self.assertEqual(f.setdefault(b'xxx', b'foo'), b'foo') + self.assertEqual(f[b'xxx'], b'foo') f.close() def test_anydbm_read(self): self.init_db() f = dbm.open(_fname, 'r') self.read_helper(f) + # get() works as in the dict interface + self.assertEqual(f.get(b'a'), self._dict['a']) + self.assertEqual(f.get(b'xxx', b'foo'), b'foo') + self.assertIsNone(f.get(b'xxx')) + with self.assertRaises(KeyError): + f[b'xxx'] f.close() def test_anydbm_keys(self): diff --git a/Lib/test/test_dbm_dumb.py b/Lib/test/test_dbm_dumb.py index 652a355..58b9d17 100644 --- a/Lib/test/test_dbm_dumb.py +++ b/Lib/test/test_dbm_dumb.py @@ -73,6 +73,9 @@ class DumbDBMTestCase(unittest.TestCase): f = dumbdbm.open(_fname, 'w') self._dict[b'g'] = f[b'g'] = b"indented" self.read_helper(f) + # setdefault() works as in the dict interface + self.assertEqual(f.setdefault(b'xxx', b'foo'), b'foo') + self.assertEqual(f[b'xxx'], b'foo') f.close() def test_dumbdbm_read(self): @@ -85,6 +88,12 @@ class DumbDBMTestCase(unittest.TestCase): with self.assertRaisesRegex(ValueError, 'The database is opened for reading only'): del f[b'a'] + # get() works as in the dict interface + self.assertEqual(f.get(b'a'), self._dict[b'a']) + self.assertEqual(f.get(b'xxx', b'foo'), b'foo') + self.assertIsNone(f.get(b'xxx')) + with self.assertRaises(KeyError): + f[b'xxx'] f.close() def test_dumbdbm_keys(self): diff --git a/Lib/test/test_dbm_gnu.py b/Lib/test/test_dbm_gnu.py index d96df92..463d343 100644 --- a/Lib/test/test_dbm_gnu.py +++ b/Lib/test/test_dbm_gnu.py @@ -32,9 +32,12 @@ class TestGdbm(unittest.TestCase): self.assertIn(key, key_set) key_set.remove(key) key = self.g.nextkey(key) - self.assertRaises(KeyError, lambda: self.g['xxx']) # get() and setdefault() work as in the dict interface + self.assertEqual(self.g.get(b'a'), b'b') + self.assertIsNone(self.g.get(b'xxx')) self.assertEqual(self.g.get(b'xxx', b'foo'), b'foo') + with self.assertRaises(KeyError): + self.g['xxx'] self.assertEqual(self.g.setdefault(b'xxx', b'foo'), b'foo') self.assertEqual(self.g[b'xxx'], b'foo') diff --git a/Lib/test/test_dbm_ndbm.py b/Lib/test/test_dbm_ndbm.py index fb7d0e8..f921167 100644 --- a/Lib/test/test_dbm_ndbm.py +++ b/Lib/test/test_dbm_ndbm.py @@ -18,7 +18,7 @@ class DbmTestCase(unittest.TestCase): def test_keys(self): self.d = dbm.ndbm.open(self.filename, 'c') - self.assertTrue(self.d.keys() == []) + self.assertEqual(self.d.keys(), []) self.d['a'] = 'b' self.d[b'bytes'] = b'data' self.d['12345678910'] = '019237410982340912840198242' @@ -26,6 +26,14 @@ class DbmTestCase(unittest.TestCase): self.assertIn('a', self.d) self.assertIn(b'a', self.d) self.assertEqual(self.d[b'bytes'], b'data') + # get() and setdefault() work as in the dict interface + self.assertEqual(self.d.get(b'a'), b'b') + self.assertIsNone(self.d.get(b'xxx')) + self.assertEqual(self.d.get(b'xxx', b'foo'), b'foo') + with self.assertRaises(KeyError): + self.d['xxx'] + self.assertEqual(self.d.setdefault(b'xxx', b'foo'), b'foo') + self.assertEqual(self.d[b'xxx'], b'foo') self.d.close() def test_modes(self): diff --git a/Misc/NEWS.d/next/Library/2018-04-29-11-15-38.bpo-33383.g32YWn.rst b/Misc/NEWS.d/next/Library/2018-04-29-11-15-38.bpo-33383.g32YWn.rst new file mode 100644 index 0000000..7b65baa --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-29-11-15-38.bpo-33383.g32YWn.rst @@ -0,0 +1,2 @@ +Fixed crash in the get() method of the :mod:`dbm.ndbm` database object when +it is called with a single argument. diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c index 8afd92c..65761d8 100644 --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -274,7 +274,7 @@ static PySequenceMethods dbm_as_sequence = { _dbm.dbm.get key: str(accept={str, robuffer}, zeroes=True) - default: object(c_default="NULL") = b'' + default: object = None / Return the value for key if present, otherwise default. @@ -283,7 +283,7 @@ Return the value for key if present, otherwise default. static PyObject * _dbm_dbm_get_impl(dbmobject *self, const char *key, Py_ssize_clean_t key_length, PyObject *default_value) -/*[clinic end generated code: output=b44f95eba8203d93 input=a3a279957f85eb6d]*/ +/*[clinic end generated code: output=b44f95eba8203d93 input=b788eba0ffad2e91]*/ /*[clinic end generated code: output=4f5c0e523eaf1251 input=9402c0af8582dc69]*/ { datum dbm_key, val; diff --git a/Modules/clinic/_dbmmodule.c.h b/Modules/clinic/_dbmmodule.c.h index 0f831c9..574cc5e 100644 --- a/Modules/clinic/_dbmmodule.c.h +++ b/Modules/clinic/_dbmmodule.c.h @@ -39,7 +39,7 @@ _dbm_dbm_keys(dbmobject *self, PyObject *Py_UNUSED(ignored)) } PyDoc_STRVAR(_dbm_dbm_get__doc__, -"get($self, key, default=b\'\', /)\n" +"get($self, key, default=None, /)\n" "--\n" "\n" "Return the value for key if present, otherwise default."); @@ -57,7 +57,7 @@ _dbm_dbm_get(dbmobject *self, PyObject *const *args, Py_ssize_t nargs) PyObject *return_value = NULL; const char *key; Py_ssize_clean_t key_length; - PyObject *default_value = NULL; + PyObject *default_value = Py_None; if (!_PyArg_ParseStack(args, nargs, "s#|O:get", &key, &key_length, &default_value)) { @@ -141,4 +141,4 @@ dbmopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=5c858b4080a011a4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1cba297bc8d7c2c2 input=a9049054013a1b77]*/ -- cgit v0.12