@@ -166,10 +166,27 @@ class BerkeleyDatabase
166166 bool IsDummy () { return env == nullptr ; }
167167};
168168
169-
170169/* * RAII class that provides access to a Berkeley database */
171170class BerkeleyBatch
172171{
172+ /* * RAII class that automatically cleanses its data on destruction */
173+ class SafeDbt final {
174+ Dbt m_dbt;
175+
176+ public:
177+ // construct Dbt with data or flags
178+ SafeDbt (u_int32_t flags = 0 );
179+ SafeDbt (void *data, size_t size);
180+ ~SafeDbt ();
181+
182+ // delegate to Dbt
183+ const void * get_data () const ;
184+ u_int32_t get_size () const ;
185+
186+ // conversion operator to access the underlying Dbt
187+ operator Dbt*();
188+ };
189+
173190protected:
174191 Db* pdb;
175192 std::string strFile;
@@ -197,7 +214,6 @@ class BerkeleyBatch
197214 /* verifies the database file */
198215 static bool VerifyDatabaseFile (const fs::path& file_path, std::string& warningStr, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc);
199216
200- public:
201217 template <typename K, typename T>
202218 bool Read (const K& key, T& value)
203219 {
@@ -208,13 +224,11 @@ class BerkeleyBatch
208224 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
209225 ssKey.reserve (1000 );
210226 ssKey << key;
211- Dbt datKey (ssKey.data (), ssKey.size ());
227+ SafeDbt datKey (ssKey.data (), ssKey.size ());
212228
213229 // Read
214- Dbt datValue;
215- datValue.set_flags (DB_DBT_MALLOC);
216- int ret = pdb->get (activeTxn, &datKey, &datValue, 0 );
217- memory_cleanse (datKey.get_data (), datKey.get_size ());
230+ SafeDbt datValue (DB_DBT_MALLOC);
231+ int ret = pdb->get (activeTxn, datKey, datValue, 0 );
218232 bool success = false ;
219233 if (datValue.get_data () != nullptr ) {
220234 // Unserialize value
@@ -225,10 +239,6 @@ class BerkeleyBatch
225239 } catch (const std::exception&) {
226240 // In this case success remains 'false'
227241 }
228-
229- // Clear and free memory
230- memory_cleanse (datValue.get_data (), datValue.get_size ());
231- free (datValue.get_data ());
232242 }
233243 return ret == 0 && success;
234244 }
@@ -245,20 +255,16 @@ class BerkeleyBatch
245255 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
246256 ssKey.reserve (1000 );
247257 ssKey << key;
248- Dbt datKey (ssKey.data (), ssKey.size ());
258+ SafeDbt datKey (ssKey.data (), ssKey.size ());
249259
250260 // Value
251261 CDataStream ssValue (SER_DISK, CLIENT_VERSION);
252262 ssValue.reserve (10000 );
253263 ssValue << value;
254- Dbt datValue (ssValue.data (), ssValue.size ());
264+ SafeDbt datValue (ssValue.data (), ssValue.size ());
255265
256266 // Write
257- int ret = pdb->put (activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
258-
259- // Clear memory in case it was a private key
260- memory_cleanse (datKey.get_data (), datKey.get_size ());
261- memory_cleanse (datValue.get_data (), datValue.get_size ());
267+ int ret = pdb->put (activeTxn, datKey, datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
262268 return (ret == 0 );
263269 }
264270
@@ -274,13 +280,10 @@ class BerkeleyBatch
274280 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
275281 ssKey.reserve (1000 );
276282 ssKey << key;
277- Dbt datKey (ssKey.data (), ssKey.size ());
283+ SafeDbt datKey (ssKey.data (), ssKey.size ());
278284
279285 // Erase
280- int ret = pdb->del (activeTxn, &datKey, 0 );
281-
282- // Clear memory
283- memory_cleanse (datKey.get_data (), datKey.get_size ());
286+ int ret = pdb->del (activeTxn, datKey, 0 );
284287 return (ret == 0 || ret == DB_NOTFOUND);
285288 }
286289
@@ -294,13 +297,10 @@ class BerkeleyBatch
294297 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
295298 ssKey.reserve (1000 );
296299 ssKey << key;
297- Dbt datKey (ssKey.data (), ssKey.size ());
300+ SafeDbt datKey (ssKey.data (), ssKey.size ());
298301
299302 // Exists
300- int ret = pdb->exists (activeTxn, &datKey, 0 );
301-
302- // Clear memory
303- memory_cleanse (datKey.get_data (), datKey.get_size ());
303+ int ret = pdb->exists (activeTxn, datKey, 0 );
304304 return (ret == 0 );
305305 }
306306
@@ -318,11 +318,9 @@ class BerkeleyBatch
318318 int ReadAtCursor (Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue)
319319 {
320320 // Read at cursor
321- Dbt datKey;
322- Dbt datValue;
323- datKey.set_flags (DB_DBT_MALLOC);
324- datValue.set_flags (DB_DBT_MALLOC);
325- int ret = pcursor->get (&datKey, &datValue, DB_NEXT);
321+ SafeDbt datKey (DB_DBT_MALLOC);
322+ SafeDbt datValue (DB_DBT_MALLOC);
323+ int ret = pcursor->get (datKey, datValue, DB_NEXT);
326324 if (ret != 0 )
327325 return ret;
328326 else if (datKey.get_data () == nullptr || datValue.get_data () == nullptr )
@@ -335,16 +333,9 @@ class BerkeleyBatch
335333 ssValue.SetType (SER_DISK);
336334 ssValue.clear ();
337335 ssValue.write ((char *)datValue.get_data (), datValue.get_size ());
338-
339- // Clear and free memory
340- memory_cleanse (datKey.get_data (), datKey.get_size ());
341- memory_cleanse (datValue.get_data (), datValue.get_size ());
342- free (datKey.get_data ());
343- free (datValue.get_data ());
344336 return 0 ;
345337 }
346338
347- public:
348339 bool TxnBegin ()
349340 {
350341 if (!pdb || activeTxn)
0 commit comments