diff --git a/extmod/modbtree.c b/extmod/modbtree.c index 55c13ac911a73..f48645a8270dc 100644 --- a/extmod/modbtree.c +++ b/extmod/modbtree.c @@ -89,6 +89,12 @@ void __dbpanic(DB *db) { mp_printf(&mp_plat_print, "__dbpanic(%p)\n", db); } +static void check_btree_is_open(mp_obj_btree_t *self) { + if (!self->db) { + mp_raise_ValueError(MP_ERROR_TEXT("database closed")); + } +} + static mp_obj_btree_t *btree_new(DB *db, mp_obj_t stream) { mp_obj_btree_t *o = mp_obj_malloc(mp_obj_btree_t, (mp_obj_type_t *)&btree_type); o->stream = stream; @@ -114,19 +120,28 @@ static void btree_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind static mp_obj_t btree_flush(mp_obj_t self_in) { mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + check_btree_is_open(self); return MP_OBJ_NEW_SMALL_INT(__bt_sync(self->db, 0)); } static MP_DEFINE_CONST_FUN_OBJ_1(btree_flush_obj, btree_flush); static mp_obj_t btree_close(mp_obj_t self_in) { mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT(__bt_close(self->db)); + int res; + if (self->db) { + res = __bt_close(self->db); + self->db = NULL; + } else { + res = RET_SUCCESS; // Closing an already-closed DB always succeeds. + } + return MP_OBJ_NEW_SMALL_INT(res); } static MP_DEFINE_CONST_FUN_OBJ_1(btree_close_obj, btree_close); static mp_obj_t btree_put(size_t n_args, const mp_obj_t *args) { (void)n_args; mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); + check_btree_is_open(self); DBT key, val; buf_to_dbt(args[1], &key); buf_to_dbt(args[2], &val); @@ -136,6 +151,7 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_put_obj, 3, 4, btree_put); static mp_obj_t btree_get(size_t n_args, const mp_obj_t *args) { mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); + check_btree_is_open(self); DBT key, val; buf_to_dbt(args[1], &key); int res = __bt_get(self->db, &key, &val, 0); @@ -153,6 +169,7 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_get_obj, 2, 3, btree_get); static mp_obj_t btree_seq(size_t n_args, const mp_obj_t *args) { mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); + check_btree_is_open(self); int flags = MP_OBJ_SMALL_INT_VALUE(args[1]); DBT key, val; if (n_args > 2) { @@ -225,6 +242,7 @@ static mp_obj_t btree_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { static mp_obj_t btree_iternext(mp_obj_t self_in) { mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + check_btree_is_open(self); DBT key, val; int res; bool desc = self->flags & FLAG_DESC; @@ -281,6 +299,7 @@ static mp_obj_t btree_iternext(mp_obj_t self_in) { static mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + check_btree_is_open(self); if (value == MP_OBJ_NULL) { // delete DBT key; @@ -314,6 +333,7 @@ static mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { static mp_obj_t btree_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_btree_t *self = MP_OBJ_TO_PTR(lhs_in); + check_btree_is_open(self); switch (op) { case MP_BINARY_OP_CONTAINS: { DBT key, val; diff --git a/tests/extmod/btree_closed.py b/tests/extmod/btree_closed.py new file mode 100644 index 0000000000000..ae61cd00836d2 --- /dev/null +++ b/tests/extmod/btree_closed.py @@ -0,0 +1,39 @@ +try: + import btree + import io +except ImportError: + print("SKIP") + raise SystemExit + +f = io.BytesIO() +db = btree.open(f) + +db[b"foo"] = b"42" + +db.close() + +# Accessing an already-closed database should fail. +try: + print(db[b"foo"]) +except ValueError: + print("ValueError") + +try: + db[b"bar"] = b"43" +except ValueError: + print("ValueError") + +try: + db.flush() +except ValueError: + print("ValueError") + +try: + for k, v in db.items(): + pass +except ValueError: + print("ValueError") + +# Closing and printing an already-closed database should not fail. +db.close() +print(db) diff --git a/tests/extmod/btree_closed.py.exp b/tests/extmod/btree_closed.py.exp new file mode 100644 index 0000000000000..312edfd13dba6 --- /dev/null +++ b/tests/extmod/btree_closed.py.exp @@ -0,0 +1,5 @@ +ValueError +ValueError +ValueError +ValueError + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy