@@ -191,10 +191,29 @@ class BerkeleyDatabase
191191 bool IsDummy () { return env == nullptr ; }
192192};
193193
194-
195194/* * RAII class that provides access to a Berkeley database */
196195class BerkeleyBatch
197196{
197+ /* * RAII class that automatically cleanses its data on destruction */
198+ class SafeDbt final
199+ {
200+ Dbt m_dbt;
201+
202+ public:
203+ // construct Dbt with internally-managed data
204+ SafeDbt ();
205+ // construct Dbt with provided data
206+ SafeDbt (void * data, size_t size);
207+ ~SafeDbt ();
208+
209+ // delegate to Dbt
210+ const void * get_data () const ;
211+ u_int32_t get_size () const ;
212+
213+ // conversion operator to access the underlying Dbt
214+ operator Dbt*();
215+ };
216+
198217protected:
199218 Db* pdb;
200219 std::string strFile;
@@ -222,7 +241,6 @@ class BerkeleyBatch
222241 /* verifies the database file */
223242 static bool VerifyDatabaseFile (const fs::path& file_path, std::string& warningStr, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc);
224243
225- public:
226244 template <typename K, typename T>
227245 bool Read (const K& key, T& value)
228246 {
@@ -233,13 +251,11 @@ class BerkeleyBatch
233251 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
234252 ssKey.reserve (1000 );
235253 ssKey << key;
236- Dbt datKey (ssKey.data (), ssKey.size ());
254+ SafeDbt datKey (ssKey.data (), ssKey.size ());
237255
238256 // Read
239- Dbt datValue;
240- datValue.set_flags (DB_DBT_MALLOC);
241- int ret = pdb->get (activeTxn, &datKey, &datValue, 0 );
242- memory_cleanse (datKey.get_data (), datKey.get_size ());
257+ SafeDbt datValue;
258+ int ret = pdb->get (activeTxn, datKey, datValue, 0 );
243259 bool success = false ;
244260 if (datValue.get_data () != nullptr ) {
245261 // Unserialize value
@@ -250,10 +266,6 @@ class BerkeleyBatch
250266 } catch (const std::exception&) {
251267 // In this case success remains 'false'
252268 }
253-
254- // Clear and free memory
255- memory_cleanse (datValue.get_data (), datValue.get_size ());
256- free (datValue.get_data ());
257269 }
258270 return ret == 0 && success;
259271 }
@@ -270,20 +282,16 @@ class BerkeleyBatch
270282 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
271283 ssKey.reserve (1000 );
272284 ssKey << key;
273- Dbt datKey (ssKey.data (), ssKey.size ());
285+ SafeDbt datKey (ssKey.data (), ssKey.size ());
274286
275287 // Value
276288 CDataStream ssValue (SER_DISK, CLIENT_VERSION);
277289 ssValue.reserve (10000 );
278290 ssValue << value;
279- Dbt datValue (ssValue.data (), ssValue.size ());
291+ SafeDbt datValue (ssValue.data (), ssValue.size ());
280292
281293 // Write
282- int ret = pdb->put (activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
283-
284- // Clear memory in case it was a private key
285- memory_cleanse (datKey.get_data (), datKey.get_size ());
286- memory_cleanse (datValue.get_data (), datValue.get_size ());
294+ int ret = pdb->put (activeTxn, datKey, datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
287295 return (ret == 0 );
288296 }
289297
@@ -299,13 +307,10 @@ class BerkeleyBatch
299307 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
300308 ssKey.reserve (1000 );
301309 ssKey << key;
302- Dbt datKey (ssKey.data (), ssKey.size ());
310+ SafeDbt datKey (ssKey.data (), ssKey.size ());
303311
304312 // Erase
305- int ret = pdb->del (activeTxn, &datKey, 0 );
306-
307- // Clear memory
308- memory_cleanse (datKey.get_data (), datKey.get_size ());
313+ int ret = pdb->del (activeTxn, datKey, 0 );
309314 return (ret == 0 || ret == DB_NOTFOUND);
310315 }
311316
@@ -319,13 +324,10 @@ class BerkeleyBatch
319324 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
320325 ssKey.reserve (1000 );
321326 ssKey << key;
322- Dbt datKey (ssKey.data (), ssKey.size ());
327+ SafeDbt datKey (ssKey.data (), ssKey.size ());
323328
324329 // Exists
325- int ret = pdb->exists (activeTxn, &datKey, 0 );
326-
327- // Clear memory
328- memory_cleanse (datKey.get_data (), datKey.get_size ());
330+ int ret = pdb->exists (activeTxn, datKey, 0 );
329331 return (ret == 0 );
330332 }
331333
@@ -340,20 +342,12 @@ class BerkeleyBatch
340342 return pcursor;
341343 }
342344
343- int ReadAtCursor (Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false )
345+ int ReadAtCursor (Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue)
344346 {
345347 // Read at cursor
346- Dbt datKey;
347- unsigned int fFlags = DB_NEXT;
348- if (setRange) {
349- datKey.set_data (ssKey.data ());
350- datKey.set_size (ssKey.size ());
351- fFlags = DB_SET_RANGE;
352- }
353- Dbt datValue;
354- datKey.set_flags (DB_DBT_MALLOC);
355- datValue.set_flags (DB_DBT_MALLOC);
356- int ret = pcursor->get (&datKey, &datValue, fFlags );
348+ SafeDbt datKey;
349+ SafeDbt datValue;
350+ int ret = pcursor->get (datKey, datValue, DB_NEXT);
357351 if (ret != 0 )
358352 return ret;
359353 else if (datKey.get_data () == nullptr || datValue.get_data () == nullptr )
@@ -366,16 +360,9 @@ class BerkeleyBatch
366360 ssValue.SetType (SER_DISK);
367361 ssValue.clear ();
368362 ssValue.write ((char *)datValue.get_data (), datValue.get_size ());
369-
370- // Clear and free memory
371- memory_cleanse (datKey.get_data (), datKey.get_size ());
372- memory_cleanse (datValue.get_data (), datValue.get_size ());
373- free (datKey.get_data ());
374- free (datValue.get_data ());
375363 return 0 ;
376364 }
377365
378- public:
379366 bool TxnBegin ()
380367 {
381368 if (!pdb || activeTxn)
0 commit comments