@@ -205,10 +205,29 @@ class BerkeleyDatabase
205205 bool IsDummy () { return env == nullptr ; }
206206};
207207
208-
209208/* * RAII class that provides access to a Berkeley database */
210209class BerkeleyBatch
211210{
211+ /* * RAII class that automatically cleanses its data on destruction */
212+ class SafeDbt final
213+ {
214+ Dbt m_dbt;
215+
216+ public:
217+ // construct Dbt with internally-managed data
218+ SafeDbt ();
219+ // construct Dbt with provided data
220+ SafeDbt (void * data, size_t size);
221+ ~SafeDbt ();
222+
223+ // delegate to Dbt
224+ const void * get_data () const ;
225+ u_int32_t get_size () const ;
226+
227+ // conversion operator to access the underlying Dbt
228+ operator Dbt*();
229+ };
230+
212231protected:
213232 Db* pdb;
214233 std::string strFile;
@@ -236,7 +255,6 @@ class BerkeleyBatch
236255 /* verifies the database file */
237256 static bool VerifyDatabaseFile (const fs::path& file_path, std::string& warningStr, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc);
238257
239- public:
240258 template <typename K, typename T>
241259 bool Read (const K& key, T& value)
242260 {
@@ -247,13 +265,11 @@ class BerkeleyBatch
247265 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
248266 ssKey.reserve (1000 );
249267 ssKey << key;
250- Dbt datKey (ssKey.data (), ssKey.size ());
268+ SafeDbt datKey (ssKey.data (), ssKey.size ());
251269
252270 // Read
253- Dbt datValue;
254- datValue.set_flags (DB_DBT_MALLOC);
255- int ret = pdb->get (activeTxn, &datKey, &datValue, 0 );
256- memory_cleanse (datKey.get_data (), datKey.get_size ());
271+ SafeDbt datValue;
272+ int ret = pdb->get (activeTxn, datKey, datValue, 0 );
257273 bool success = false ;
258274 if (datValue.get_data () != nullptr ) {
259275 // Unserialize value
@@ -264,10 +280,6 @@ class BerkeleyBatch
264280 } catch (const std::exception&) {
265281 // In this case success remains 'false'
266282 }
267-
268- // Clear and free memory
269- memory_cleanse (datValue.get_data (), datValue.get_size ());
270- free (datValue.get_data ());
271283 }
272284 return ret == 0 && success;
273285 }
@@ -284,20 +296,16 @@ class BerkeleyBatch
284296 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
285297 ssKey.reserve (1000 );
286298 ssKey << key;
287- Dbt datKey (ssKey.data (), ssKey.size ());
299+ SafeDbt datKey (ssKey.data (), ssKey.size ());
288300
289301 // Value
290302 CDataStream ssValue (SER_DISK, CLIENT_VERSION);
291303 ssValue.reserve (10000 );
292304 ssValue << value;
293- Dbt datValue (ssValue.data (), ssValue.size ());
305+ SafeDbt datValue (ssValue.data (), ssValue.size ());
294306
295307 // Write
296- int ret = pdb->put (activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
297-
298- // Clear memory in case it was a private key
299- memory_cleanse (datKey.get_data (), datKey.get_size ());
300- memory_cleanse (datValue.get_data (), datValue.get_size ());
308+ int ret = pdb->put (activeTxn, datKey, datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
301309 return (ret == 0 );
302310 }
303311
@@ -313,13 +321,10 @@ class BerkeleyBatch
313321 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
314322 ssKey.reserve (1000 );
315323 ssKey << key;
316- Dbt datKey (ssKey.data (), ssKey.size ());
324+ SafeDbt datKey (ssKey.data (), ssKey.size ());
317325
318326 // Erase
319- int ret = pdb->del (activeTxn, &datKey, 0 );
320-
321- // Clear memory
322- memory_cleanse (datKey.get_data (), datKey.get_size ());
327+ int ret = pdb->del (activeTxn, datKey, 0 );
323328 return (ret == 0 || ret == DB_NOTFOUND);
324329 }
325330
@@ -333,13 +338,10 @@ class BerkeleyBatch
333338 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
334339 ssKey.reserve (1000 );
335340 ssKey << key;
336- Dbt datKey (ssKey.data (), ssKey.size ());
341+ SafeDbt datKey (ssKey.data (), ssKey.size ());
337342
338343 // Exists
339- int ret = pdb->exists (activeTxn, &datKey, 0 );
340-
341- // Clear memory
342- memory_cleanse (datKey.get_data (), datKey.get_size ());
344+ int ret = pdb->exists (activeTxn, datKey, 0 );
343345 return (ret == 0 );
344346 }
345347
@@ -354,20 +356,12 @@ class BerkeleyBatch
354356 return pcursor;
355357 }
356358
357- int ReadAtCursor (Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false )
359+ int ReadAtCursor (Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue)
358360 {
359361 // Read at cursor
360- Dbt datKey;
361- unsigned int fFlags = DB_NEXT;
362- if (setRange) {
363- datKey.set_data (ssKey.data ());
364- datKey.set_size (ssKey.size ());
365- fFlags = DB_SET_RANGE;
366- }
367- Dbt datValue;
368- datKey.set_flags (DB_DBT_MALLOC);
369- datValue.set_flags (DB_DBT_MALLOC);
370- int ret = pcursor->get (&datKey, &datValue, fFlags );
362+ SafeDbt datKey;
363+ SafeDbt datValue;
364+ int ret = pcursor->get (datKey, datValue, DB_NEXT);
371365 if (ret != 0 )
372366 return ret;
373367 else if (datKey.get_data () == nullptr || datValue.get_data () == nullptr )
@@ -380,16 +374,9 @@ class BerkeleyBatch
380374 ssValue.SetType (SER_DISK);
381375 ssValue.clear ();
382376 ssValue.write ((char *)datValue.get_data (), datValue.get_size ());
383-
384- // Clear and free memory
385- memory_cleanse (datKey.get_data (), datKey.get_size ());
386- memory_cleanse (datValue.get_data (), datValue.get_size ());
387- free (datKey.get_data ());
388- free (datValue.get_data ());
389377 return 0 ;
390378 }
391379
392- public:
393380 bool TxnBegin ()
394381 {
395382 if (!pdb || activeTxn)
0 commit comments