diff --git a/wallet/db.c b/wallet/db.c index f3383f833..b25b087b6 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -331,6 +331,71 @@ char *dbmigrations[] = { NULL, }; +/* Leak tracking. */ +#if DEVELOPER +/* We need a global here, since caller has no context. Yuck! */ +static struct list_head db_statements = LIST_HEAD_INIT(db_statements); + +struct db_statement { + struct list_node list; + sqlite3_stmt *stmt; + const char *origin; +}; + +static struct db_statement *find_statement(sqlite3_stmt *stmt) +{ + struct db_statement *i; + + list_for_each(&db_statements, i, list) { + if (i->stmt == stmt) + return i; + } + return NULL; +} + +void db_assert_no_outstanding_statements(void) +{ + struct db_statement *dbstat; + + dbstat = list_top(&db_statements, struct db_statement, list); + if (dbstat) + fatal("Unfinalized statement %s", dbstat->origin); +} + +static void dev_statement_start(sqlite3_stmt *stmt, const char *origin) +{ + struct db_statement *dbstat = tal(NULL, struct db_statement); + dbstat->stmt = stmt; + dbstat->origin = origin; + list_add(&db_statements, &dbstat->list); +} + +static void dev_statement_end(sqlite3_stmt *stmt) +{ + struct db_statement *dbstat = find_statement(stmt); + list_del_from(&db_statements, &dbstat->list); + tal_free(dbstat); +} +#else +static void dev_statement_start(sqlite3_stmt *stmt, const char *origin) +{ +} + +static void dev_statement_end(sqlite3_stmt *stmt) +{ +} + +void db_assert_no_outstanding_statements(void) +{ +} +#endif + +void db_stmt_done(sqlite3_stmt *stmt) +{ + dev_statement_end(stmt); + sqlite3_finalize(stmt); +} + sqlite3_stmt *db_prepare_(const char *caller, struct db *db, const char *query) { int err; @@ -343,6 +408,7 @@ sqlite3_stmt *db_prepare_(const char *caller, struct db *db, const char *query) if (err != SQLITE_OK) fatal("%s: %s: %s", caller, query, sqlite3_errmsg(db->sql)); + dev_statement_start(stmt, caller); return stmt; } @@ -353,7 +419,7 @@ void db_exec_prepared_(const char *caller, struct db *db, sqlite3_stmt *stmt) if (sqlite3_step(stmt) != SQLITE_DONE) fatal("%s: %s", caller, sqlite3_errmsg(db->sql)); - sqlite3_finalize(stmt); + db_stmt_done(stmt); } /* This one doesn't check if we're in a transaction. */ @@ -394,15 +460,15 @@ bool db_exec_prepared_mayfail_(const char *caller UNUSED, struct db *db, sqlite3 goto fail; } - sqlite3_finalize(stmt); + db_stmt_done(stmt); return true; fail: - sqlite3_finalize(stmt); + db_stmt_done(stmt); return false; } sqlite3_stmt *PRINTF_FMT(3, 4) - db_query(const char *caller UNUSED, struct db *db, const char *fmt, ...) + db_query(const char *caller, struct db *db, const char *fmt, ...) { va_list ap; char *query; @@ -417,11 +483,14 @@ sqlite3_stmt *PRINTF_FMT(3, 4) /* Sets stmt to NULL if not SQLITE_OK */ sqlite3_prepare_v2(db->sql, query, -1, &stmt, NULL); tal_free(query); + if (stmt) + dev_statement_start(stmt, caller); return stmt; } static void destroy_db(struct db *db) { + db_assert_no_outstanding_statements(); sqlite3_close(db->sql); } @@ -437,6 +506,7 @@ void db_begin_transaction_(struct db *db, const char *location) void db_commit_transaction(struct db *db) { assert(db->in_transaction); + db_assert_no_outstanding_statements(); db_exec(__func__, db, "COMMIT;"); db->in_transaction = NULL; } @@ -492,11 +562,11 @@ static int db_get_version(struct db *db) err = sqlite3_step(stmt); if (err != SQLITE_ROW) { - sqlite3_finalize(stmt); + db_stmt_done(stmt); return -1; } else { res = sqlite3_column_int64(stmt, 0); - sqlite3_finalize(stmt); + db_stmt_done(stmt); return res; } } @@ -599,7 +669,7 @@ s64 db_get_intvar(struct db *db, char *varname, s64 defval) const unsigned char *stringvar = sqlite3_column_text(stmt, 0); res = atol((const char *)stringvar); } - sqlite3_finalize(stmt); + db_stmt_done(stmt); return res; } diff --git a/wallet/db.h b/wallet/db.h index 5ce3c5a22..5c7efdccd 100644 --- a/wallet/db.h +++ b/wallet/db.h @@ -112,6 +112,12 @@ bool db_exec_prepared_mayfail_(const char *caller, struct db *db, sqlite3_stmt *stmt); +/* Wrapper around sqlite3_finalize(), for tracking statements. */ +void db_stmt_done(sqlite3_stmt *stmt); + +/* Call when you know there should be no outstanding db statements. */ +void db_assert_no_outstanding_statements(void); + /* Do not keep db open across a fork: needed for --daemon */ void db_close_for_fork(struct db *db); void db_reopen_after_fork(struct db *db); diff --git a/wallet/invoices.c b/wallet/invoices.c index c5bd36266..7eac6b786 100644 --- a/wallet/invoices.c +++ b/wallet/invoices.c @@ -183,7 +183,7 @@ static void trigger_expiration(struct invoices *invoices) list_add_tail(&idlist, &idn->list); idn->id = sqlite3_column_int64(stmt, 0); } - sqlite3_finalize(stmt); + db_stmt_done(stmt); /* Expire all those invoices */ update_db_expirations(invoices, now); @@ -220,11 +220,11 @@ static void install_expiration_timer(struct invoices *invoices) assert(res == SQLITE_ROW); if (sqlite3_column_type(stmt, 0) == SQLITE_NULL) { /* Nothing to install */ - sqlite3_finalize(stmt); + db_stmt_done(stmt); return; } else invoices->min_expiry_time = sqlite3_column_int64(stmt, 0); - sqlite3_finalize(stmt); + db_stmt_done(stmt); memset(&expiry, 0, sizeof(expiry)); expiry.ts.tv_sec = invoices->min_expiry_time; @@ -339,10 +339,10 @@ bool invoices_find_by_label(struct invoices *invoices, sqlite3_bind_json_escaped(stmt, 1, label); if (sqlite3_step(stmt) == SQLITE_ROW) { pinvoice->id = sqlite3_column_int64(stmt, 0); - sqlite3_finalize(stmt); + db_stmt_done(stmt); return true; } else { - sqlite3_finalize(stmt); + db_stmt_done(stmt); return false; } } @@ -360,10 +360,10 @@ bool invoices_find_by_rhash(struct invoices *invoices, sqlite3_bind_blob(stmt, 1, rhash, sizeof(*rhash), SQLITE_TRANSIENT); if (sqlite3_step(stmt) == SQLITE_ROW) { pinvoice->id = sqlite3_column_int64(stmt, 0); - sqlite3_finalize(stmt); + db_stmt_done(stmt); return true; } else { - sqlite3_finalize(stmt); + db_stmt_done(stmt); return false; } } @@ -383,10 +383,10 @@ bool invoices_find_unpaid(struct invoices *invoices, sqlite3_bind_int(stmt, 2, UNPAID); if (sqlite3_step(stmt) == SQLITE_ROW) { pinvoice->id = sqlite3_column_int64(stmt, 0); - sqlite3_finalize(stmt); + db_stmt_done(stmt); return true; } else { - sqlite3_finalize(stmt); + db_stmt_done(stmt); return false; } } @@ -476,7 +476,7 @@ bool invoices_iterate(struct invoices *invoices, res = sqlite3_step(stmt); if (res == SQLITE_DONE) { - sqlite3_finalize(stmt); + db_stmt_done(stmt); it->p = NULL; return false; } else { @@ -586,13 +586,13 @@ void invoices_waitany(const tal_t *ctx, res = sqlite3_step(stmt); if (res == SQLITE_ROW) { invoice.id = sqlite3_column_int64(stmt, 0); - sqlite3_finalize(stmt); + db_stmt_done(stmt); cb(&invoice, cbarg); return; } - sqlite3_finalize(stmt); + db_stmt_done(stmt); /* None found. */ add_invoice_waiter(ctx, &invoices->waiters, @@ -618,7 +618,7 @@ void invoices_waitone(const tal_t *ctx, res = sqlite3_step(stmt); assert(res == SQLITE_ROW); state = sqlite3_column_int(stmt, 0); - sqlite3_finalize(stmt); + db_stmt_done(stmt); if (state == PAID || state == EXPIRED) { cb(&invoice, cbarg); @@ -650,5 +650,5 @@ void invoices_get_details(const tal_t *ctx, wallet_stmt2invoice_details(ctx, stmt, dtl); - sqlite3_finalize(stmt); + db_stmt_done(stmt); } diff --git a/wallet/wallet.c b/wallet/wallet.c index f6b958a72..fcb303c0c 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -43,7 +43,7 @@ static void outpointfilters_init(struct wallet *w) outpointfilter_add(w->utxoset_outpoints, &txid, outnum); } - sqlite3_finalize(stmt); + db_stmt_done(stmt); } struct wallet *wallet_new(struct lightningd *ld, @@ -194,7 +194,7 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou results[i] = tal(results, struct utxo); wallet_stmt2output(stmt, results[i]); } - sqlite3_finalize(stmt); + db_stmt_done(stmt); return results; } @@ -466,13 +466,13 @@ bool wallet_shachain_load(struct wallet *wallet, u64 id, err = sqlite3_step(stmt); if (err != SQLITE_ROW) { - sqlite3_finalize(stmt); + db_stmt_done(stmt); return false; } chain->chain.min_index = sqlite3_column_int64(stmt, 0); chain->chain.num_valid = sqlite3_column_int64(stmt, 1); - sqlite3_finalize(stmt); + db_stmt_done(stmt); /* Load shachain known entries */ stmt = db_prepare(wallet->db, "SELECT idx, hash, pos FROM shachain_known WHERE shachain_id=?"); @@ -484,7 +484,7 @@ bool wallet_shachain_load(struct wallet *wallet, u64 id, memcpy(&chain->chain.known[pos].hash, sqlite3_column_blob(stmt, 1), sqlite3_column_bytes(stmt, 1)); } - sqlite3_finalize(stmt); + db_stmt_done(stmt); return true; } @@ -500,18 +500,18 @@ static struct peer *wallet_peer_load(struct wallet *w, const u64 dbid) "SELECT id, node_id, address FROM peers WHERE id=%"PRIu64";", dbid); if (!stmt || sqlite3_step(stmt) != SQLITE_ROW) { - sqlite3_finalize(stmt); + db_stmt_done(stmt); return NULL; } if (!sqlite3_column_pubkey(stmt, 1, &id)) { - sqlite3_finalize(stmt); + db_stmt_done(stmt); return NULL; } addrstr = sqlite3_column_text(stmt, 2); if (addrstr) { addrp = &addr; if (!parse_wireaddr((const char*)addrstr, addrp, DEFAULT_PORT, NULL)) { - sqlite3_finalize(stmt); + db_stmt_done(stmt); return NULL; } } else @@ -519,7 +519,7 @@ static struct peer *wallet_peer_load(struct wallet *w, const u64 dbid) peer = new_peer(w->ld, sqlite3_column_int64(stmt, 0), &id, addrp); - sqlite3_finalize(stmt); + db_stmt_done(stmt); return peer; } @@ -537,7 +537,7 @@ wallet_htlc_sigs_load(const tal_t *ctx, struct wallet *w, u64 channelid) sqlite3_column_signature(stmt, 0, &htlc_sigs[n]); n++; } - sqlite3_finalize(stmt); + db_stmt_done(stmt); log_debug(w->log, "Loaded %zu HTLC signatures from DB", n); return htlc_sigs; } @@ -703,7 +703,7 @@ bool wallet_channels_load_active(const tal_t *ctx, struct wallet *w) count++; } log_debug(w->log, "Loaded %d channels from DB", count); - sqlite3_finalize(stmt); + db_stmt_done(stmt); return ok; } @@ -777,7 +777,7 @@ u32 wallet_blocks_height(struct wallet *w, u32 def) /* If we ever processed a block we'll get the latest block in the chain */ if (sqlite3_step(stmt) == SQLITE_ROW && sqlite3_column_type(stmt, 0) != SQLITE_NULL) { blockheight = sqlite3_column_int(stmt, 0); - sqlite3_finalize(stmt); + db_stmt_done(stmt); return blockheight; } else return def; @@ -830,7 +830,7 @@ bool wallet_channel_config_load(struct wallet *w, const u64 id, "max_accepted_htlcs FROM channel_configs WHERE id=%" PRIu64 ";"; sqlite3_stmt *stmt = db_query(__func__, w->db, query, id); if (!stmt || sqlite3_step(stmt) != SQLITE_ROW) { - sqlite3_finalize(stmt); + db_stmt_done(stmt); return false; } cc->id = id; @@ -841,7 +841,7 @@ bool wallet_channel_config_load(struct wallet *w, const u64 id, cc->to_self_delay = sqlite3_column_int(stmt, col++); cc->max_accepted_htlcs = sqlite3_column_int(stmt, col++); assert(col == 7); - sqlite3_finalize(stmt); + db_stmt_done(stmt); return ok; } @@ -1012,7 +1012,7 @@ void wallet_peer_delete(struct wallet *w, u64 peer_dbid) "SELECT * FROM channels WHERE peer_id = %"PRIu64, peer_dbid); assert(sqlite3_step(stmt) == SQLITE_DONE); - sqlite3_finalize(stmt); + db_stmt_done(stmt); stmt = db_prepare(w->db, "DELETE FROM peers WHERE id=?"); sqlite3_bind_int64(stmt, 1, peer_dbid); @@ -1298,7 +1298,7 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet, ok &= htlc_in_check(in, "wallet_htlcs_load") != NULL; incount++; } - sqlite3_finalize(stmt); + db_stmt_done(stmt); stmt = db_query( __func__, wallet->db, @@ -1320,7 +1320,7 @@ bool wallet_htlcs_load_for_channel(struct wallet *wallet, * dependencies in yet */ outcount++; } - sqlite3_finalize(stmt); + db_stmt_done(stmt); log_debug(wallet->log, "Restored %d incoming and %d outgoing HTLCS", incount, outcount); return ok; @@ -1482,7 +1482,7 @@ struct htlc_stub *wallet_htlc_stubs(const tal_t *ctx, struct wallet *wallet, sqlite3_column_sha256(stmt, 3, &payment_hash); ripemd160(&stubs[n].ripemd, payment_hash.u.u8, sizeof(payment_hash.u)); } - sqlite3_finalize(stmt); + db_stmt_done(stmt); return stubs; } @@ -1549,7 +1549,7 @@ void wallet_payment_store(struct wallet *wallet, sqlite3_bind_sha256(stmt, 1, payment_hash); res = sqlite3_step(stmt); assert(res == SQLITE_ROW); - sqlite3_finalize(stmt); + db_stmt_done(stmt); #endif return; } @@ -1664,7 +1664,7 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet, if (sqlite3_step(stmt) == SQLITE_ROW) { payment = wallet_stmt2payment(ctx, stmt); } - sqlite3_finalize(stmt); + db_stmt_done(stmt); return payment; } @@ -1775,7 +1775,7 @@ void wallet_payment_get_failinfo(const tal_t *ctx, *faildetail = tal_strndup(ctx, sqlite3_column_blob(stmt, 7), sqlite3_column_bytes(stmt, 7)); - sqlite3_finalize(stmt); + db_stmt_done(stmt); } void wallet_payment_set_failinfo(struct wallet *wallet, @@ -1873,7 +1873,7 @@ wallet_payment_list(const tal_t *ctx, payments[i] = wallet_stmt2payment(payments, stmt); } - sqlite3_finalize(stmt); + db_stmt_done(stmt); /* Now attach payments not yet in db. */ list_for_each(&wallet->unstored_payments, p, list) { @@ -1913,7 +1913,7 @@ bool wallet_network_check(struct wallet *w, if (stmt && sqlite3_step(stmt) == SQLITE_ROW) { sqlite3_column_sha256_double(stmt, 0, &chainhash.shad); - sqlite3_finalize(stmt); + db_stmt_done(stmt); if (!structeq(&chainhash, &chainparams->genesis_blockhash)) { log_broken(w->log, "Wallet blockchain hash does not " "match network blockchain hash: %s " @@ -1927,7 +1927,7 @@ bool wallet_network_check(struct wallet *w, } else { /* Still a pristine wallet, claim it for the chain * that we are running */ - sqlite3_finalize(stmt); + db_stmt_done(stmt); stmt = db_prepare(w->db, "INSERT INTO vars (name, val) VALUES ('genesis_hash', ?);"); sqlite3_bind_sha256_double(stmt, 1, &chainparams->genesis_blockhash.shad); db_exec_prepared(w->db, stmt); @@ -1950,7 +1950,7 @@ static void wallet_utxoset_prune(struct wallet *w, const u32 blockheight) sqlite3_column_sha256_double(stmt, 0, &txid.shad); outpointfilter_remove(w->utxoset_outpoints, &txid, sqlite3_column_int(stmt, 1)); } - sqlite3_finalize(stmt); + db_stmt_done(stmt); stmt = db_prepare(w->db, "DELETE FROM utxoset WHERE spendheight < ?"); sqlite3_bind_int(stmt, 1, blockheight - UTXO_PRUNE_DEPTH); @@ -1986,7 +1986,7 @@ void wallet_block_remove(struct wallet *w, struct block *b) stmt = db_prepare(w->db, "SELECT * FROM blocks WHERE height >= ?;"); sqlite3_bind_int(stmt, 1, b->height); assert(sqlite3_step(stmt) == SQLITE_DONE); - sqlite3_finalize(stmt); + db_stmt_done(stmt); } void wallet_blocks_rollback(struct wallet *w, u32 height) @@ -2049,7 +2049,7 @@ wallet_outpoint_spend(struct wallet *w, const tal_t *ctx, const u32 blockheight, scid = tal(ctx, struct short_channel_id); mk_short_channel_id(scid, sqlite3_column_int(stmt, 0), sqlite3_column_int(stmt, 1), outnum); - sqlite3_finalize(stmt); + db_stmt_done(stmt); return scid; } return NULL; @@ -2130,7 +2130,7 @@ void wallet_transaction_add(struct wallet *w, const struct bitcoin_tx *tx, bitcoin_txid(tx, &txid); sqlite3_bind_sha256(stmt, 1, &txid.shad.sha); known = sqlite3_step(stmt) == SQLITE_ROW; - sqlite3_finalize(stmt); + db_stmt_done(stmt); if (!known) { /* This transaction is still unknown, insert */ @@ -2171,12 +2171,12 @@ u32 wallet_transaction_height(struct wallet *w, const struct bitcoin_txid *txid) sqlite3_bind_sha256(stmt, 1, &txid->shad.sha); if (sqlite3_step(stmt) != SQLITE_ROW) { - sqlite3_finalize(stmt); + db_stmt_done(stmt); return 0; } blockheight = sqlite3_column_int(stmt, 0); - sqlite3_finalize(stmt); + db_stmt_done(stmt); return blockheight; } @@ -2200,11 +2200,11 @@ struct txlocator *wallet_transaction_locate(const tal_t *ctx, struct wallet *w, loc = tal(ctx, struct txlocator); loc->blkheight = sqlite3_column_int(stmt, 0); loc->index = sqlite3_column_int(stmt, 1); - sqlite3_finalize(stmt); + db_stmt_done(stmt); return loc; fail: - sqlite3_finalize(stmt); + db_stmt_done(stmt); return NULL; } @@ -2224,7 +2224,7 @@ struct bitcoin_txid *wallet_transactions_by_height(const tal_t *ctx, tal_resize(&txids, count); sqlite3_column_sha256(stmt, 0, &txids[count-1].shad.sha); } - sqlite3_finalize(stmt); + db_stmt_done(stmt); return txids; } @@ -2264,7 +2264,7 @@ u32 *wallet_onchaind_channels(struct wallet *w, tal_resize(&channel_ids, count); channel_ids[count-1] = sqlite3_column_int64(stmt, 0); } - sqlite3_finalize(stmt); + db_stmt_done(stmt); return channel_ids; }