exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit 9c3c03f71ce0967207455e886f0eb20f845766bf
parent b39514da3cea55b72c6b3c7ede0859811c53e260
Author: Christian Grothoff <christian@grothoff.org>
Date:   Fri,  9 May 2025 17:27:06 +0200

-fix misc. memory leaks

Diffstat:
Msrc/exchange/taler-exchange-httpd_melt_v27.c | 4++--
Msrc/exchange/taler-exchange-httpd_withdraw.c | 6+++++-
Msrc/exchangedb/pg_get_withdraw.c | 6++++--
Msrc/include/taler_exchange_service.h | 14+++++++++++++-
Msrc/lib/exchange_api_reveal_melt.c | 19+++++++++++--------
Msrc/lib/exchange_api_withdraw.c | 66++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/testing/testing_api_cmd_coin_history.c | 10+++++++---
Msrc/testing/testing_api_cmd_get_auditor.c | 1+
Msrc/testing/testing_api_cmd_get_exchange.c | 2++
9 files changed, 85 insertions(+), 43 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_melt_v27.c b/src/exchange/taler-exchange-httpd_melt_v27.c @@ -208,7 +208,7 @@ struct MeltContext * Array @e withdraw.num_r_pubs of indices into @e denoms_h * of CS denominations. */ - uint32_t *cs_indices; + uint32_t *cs_indices; /** * Total (over all coins) amount (excluding fee) committed for the refresh @@ -366,6 +366,7 @@ clean_melt_rc (struct TEH_RequestContext *rc) { free_refresh (&mc->request.refresh_idem); } + GNUNET_free (mc->request.cs_indices); GNUNET_free (mc); } @@ -1670,7 +1671,6 @@ TEH_handler_melt_v27 ( const json_t *root, const char *const args[0]) { - struct MeltContext *mc = rc->rh_ctx; (void) args; diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c @@ -370,6 +370,8 @@ withdraw_is_idempotent ( enum GNUNET_DB_QueryStatus qs; uint8_t max_retries = 3; + /* We should at most be called once */ + GNUNET_assert (! wc->request.is_idempotent); while (0 < max_retries--) { qs = TEH_plugin->get_withdraw ( @@ -1159,9 +1161,11 @@ static void free_db_withdraw_data (struct TALER_EXCHANGEDB_Withdraw *wd) { if (NULL != wd->denom_sigs) + { for (unsigned int i = 0; i<wd->num_coins; i++) TALER_blinded_denom_sig_free (&wd->denom_sigs[i]); - GNUNET_free (wd->denom_sigs); + GNUNET_free (wd->denom_sigs); + } GNUNET_free (wd->denom_serials); GNUNET_free (wd->cs_r_values); } diff --git a/src/exchangedb/pg_get_withdraw.c b/src/exchangedb/pg_get_withdraw.c @@ -113,7 +113,6 @@ TEH_PG_get_withdraw ( ",denom_serials" " FROM withdraw" " WHERE planchets_h=$1;"); - ret = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "get_withdraw", params, @@ -131,18 +130,21 @@ TEH_PG_get_withdraw ( no_max_age ? "true" : "false", no_noreveal_index ? "true" : "false", no_selected_h ? "true" : "false"); + GNUNET_PQ_cleanup_result (rs); return GNUNET_DB_STATUS_HARD_ERROR; } if (no_blinding_seed != no_cs_r_values) { GNUNET_break (0); + GNUNET_PQ_cleanup_result (rs); return GNUNET_DB_STATUS_HARD_ERROR; } if (no_cs_r_choices != no_cs_r_values) { GNUNET_break (0); + GNUNET_PQ_cleanup_result (rs); return GNUNET_DB_STATUS_HARD_ERROR; } @@ -154,6 +156,7 @@ TEH_PG_get_withdraw ( "num_coins=%ld, num_sigs=%ld\n", wd->num_coins, num_sigs); + GNUNET_PQ_cleanup_result (rs); return GNUNET_DB_STATUS_HARD_ERROR; } @@ -164,6 +167,5 @@ TEH_PG_get_withdraw ( wd->num_cs_r_values = 0; wd->cs_r_choices = 0; } - return ret; } diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h @@ -3384,11 +3384,18 @@ struct TALER_EXCHANGE_RevealMeltResponse }; +/** + * Function called with the result of a reveal-melt operation. + * + * @param cls closure + * @param awr exchange response details + */ typedef void (*TALER_EXCHANGE_RevealMeltCallback)( void *cls, const struct TALER_EXCHANGE_RevealMeltResponse *awr); + /** * The tuple of #TALER_CNC_KAPPA - 1 signatures, that are disclosed * during the /reveal-melt step. From these signatures, signed with @@ -3397,6 +3404,9 @@ typedef void */ struct TALER_RevealPrivateRefreshNonceSignaturesP { + /** + * Array of disclosed signatures. + */ struct TALER_PrivateRefreshNonceSignatureP tuple[TALER_CNC_KAPPA - 1]; }; @@ -3469,7 +3479,9 @@ struct TALER_EXCHANGE_RevealMeltInput */ const struct TALER_RefreshMasterSecretP *rms; - /* The input data from the prior call to /melt */ + /** + * The input data from the prior call to /melt + */ const struct TALER_EXCHANGE_MeltInput *melt_input; /** diff --git a/src/lib/exchange_api_reveal_melt.c b/src/lib/exchange_api_reveal_melt.c @@ -183,7 +183,12 @@ reveal_melt_ok ( mrh->callback = NULL; /* Free resources */ for (size_t i = 0; i < mrh->num_expected_coins; i++) + { + struct TALER_EXCHANGE_RevealedCoinInfo *rci = &coins[i]; + + TALER_denom_sig_free (&rci->sig); TALER_blinded_denom_sig_free (&blind_sigs[i]); + } } return GNUNET_OK; @@ -321,7 +326,8 @@ perform_protocol ( json_t *j_age = GNUNET_JSON_PACK ( TALER_JSON_pack_age_commitment ( "age_commitment", - &mrh->reveal_input->melt_input->melt_age_commitment_proof->commitment)); + &mrh->reveal_input->melt_input->melt_age_commitment_proof->commitment) + ); GNUNET_assert (NULL != j_age); GNUNET_assert (0 == json_object_update_new (j_request_body, @@ -390,9 +396,8 @@ TALER_EXCHANGE_reveal_melt ( reveal_melt_input->blinding_seed, reveal_melt_input->blinding_values, &mrh->md); - - perform_protocol (curl_ctx, mrh); - + perform_protocol (curl_ctx, + mrh); return mrh; } @@ -407,9 +412,7 @@ TALER_EXCHANGE_reveal_melt_cancel ( mrh->job = NULL; } TALER_curl_easy_post_finished (&mrh->post_ctx); - - if (NULL != mrh->request_url) - GNUNET_free (mrh->request_url); - + TALER_EXCHANGE_free_melt_data_v27 (&mrh->md); + GNUNET_free (mrh->request_url); GNUNET_free (mrh); } diff --git a/src/lib/exchange_api_withdraw.c b/src/lib/exchange_api_withdraw.c @@ -19,7 +19,11 @@ * @brief Implementation of /withdraw requests * @author Özgür Kesim */ - +/** + * We want the "dangerous" exports here as these are OUR exports + * and we want to check that the prototypes match. + */ +#define TALER_TESTING_EXPORTS_DANGEROUS 1 #include "platform.h" #include <gnunet/gnunet_common.h> #include <jansson.h> @@ -968,8 +972,6 @@ copy_results ( struct TALER_EXCHANGE_WithdrawResponse resp = { .hr = wbr->hr, }; - struct TALER_EXCHANGE_WithdrawCoinPrivateDetails - details[GNUNET_NZL (wh->num_coins)]; wh->withdraw_blinded_handle = NULL; @@ -982,17 +984,18 @@ copy_results ( { case MHD_HTTP_OK: { + struct TALER_EXCHANGE_WithdrawCoinPrivateDetails + details[GNUNET_NZL (wh->num_coins)]; + bool ok = true; GNUNET_assert (wh->num_coins == wbr->details.ok.num_sigs); - - resp.details.ok.num_sigs = wbr->details.ok.num_sigs; - resp.details.ok.coin_details = details; - resp.details.ok.planchets_h = wbr->details.ok.planchets_h; memset (details, 0, sizeof(details)); - - for (size_t n = 0; n< wh->num_coins; n++) + resp.details.ok.num_sigs = wbr->details.ok.num_sigs; + resp.details.ok.coin_details = details; + resp.details.ok.planchets_h = wbr->details.ok.planchets_h; + for (size_t n = 0; n<wh->num_coins; n++) { const struct TALER_BlindedDenominationSignature *bsig = &wbr->details.ok.blinded_denom_sigs[n]; @@ -1019,13 +1022,26 @@ copy_results ( resp.hr.http_status = 0; resp.hr.ec = TALER_EC_EXCHANGE_WITHDRAW_UNBLIND_FAILURE; GNUNET_break_op (0); + ok = false; break; } coin->denom_sig = fresh_coin.sig; } + if (ok) + { + wh->callback ( + wh->callback_cls, + &resp); + wh->callback = NULL; + } + for (size_t n = 0; n<wh->num_coins; n++) + { + struct TALER_EXCHANGE_WithdrawCoinPrivateDetails *coin = &details[n]; + + TALER_denom_sig_free (&coin->denom_sig); + } break; } - case MHD_HTTP_CREATED: resp.details.created = wbr->details.created; break; @@ -1039,12 +1055,13 @@ copy_results ( /* nothing to do here, .hr.ec and .hr.hint are all set already from previous response */ break; } - - wh->callback ( - wh->callback_cls, - &resp); - - wh->callback = NULL; + if (NULL != wh->callback) + { + wh->callback ( + wh->callback_cls, + &resp); + wh->callback = NULL; + } TALER_EXCHANGE_withdraw_cancel (wh); } @@ -1199,11 +1216,7 @@ blinding_prepare_done ( const struct TALER_EXCHANGE_BlindingPrepareResponse *bpr) { struct BlindingPrepareClosure *bpcls = cls; - struct TALER_EXCHANGE_WithdrawHandle *wh; - - GNUNET_assert (NULL != bpcls); - wh = bpcls->withdraw_handle; - GNUNET_assert (NULL != wh); + struct TALER_EXCHANGE_WithdrawHandle *wh = bpcls->withdraw_handle; wh->blinding_prepare_handle = NULL; switch (bpr->hr.http_status) @@ -1212,9 +1225,9 @@ blinding_prepare_done ( { bool success = false; size_t num = bpr->details.ok.num_blinding_values; + GNUNET_assert (0 != num); GNUNET_assert (num == bpcls->num_nonces); - for (size_t i = 0; i < bpcls->num_prepare_coins; i++) { struct TALER_PlanchetDetail *planchet = bpcls->coins[i].planchet; @@ -1266,14 +1279,11 @@ blinding_prepare_done ( success = true; } - GNUNET_free (bpcls->coins); - GNUNET_free (bpcls->nonces); - /* /blinding-prepare is done, we can now perform the * actual withdraw operation */ if (success) call_withdraw_blinded (wh); - return; + goto cleanup; } default: { @@ -1291,6 +1301,10 @@ blinding_prepare_done ( } } TALER_EXCHANGE_withdraw_cancel (wh); +cleanup: + GNUNET_free (bpcls->coins); + GNUNET_free (bpcls->nonces); + GNUNET_free (bpcls); } diff --git a/src/testing/testing_api_cmd_coin_history.c b/src/testing/testing_api_cmd_coin_history.c @@ -237,6 +237,10 @@ analyze_command (void *cls, struct TALER_TESTING_Command *cur; struct TALER_TESTING_Command *bcmd; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Checking `%s' for history of coin `%s'\n", + cmd->label, + TALER_B2S (coin_pub)); cur = TALER_TESTING_cmd_batch_get_current (cmd); if (GNUNET_OK != TALER_TESTING_get_trait_batch_cmds (cmd, @@ -282,15 +286,15 @@ analyze_command (void *cls, j); break; /* command does nothing for coins */ } - if (0 != GNUNET_memcmp (rp, coin_pub)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Command `%s#%u' is about another coin\n", + "Command `%s#%u' is about another coin %s\n", cmd->label, - j); + j, + TALER_B2S (rp)); continue; /* command affects some _other_ coin */ } if (GNUNET_OK != diff --git a/src/testing/testing_api_cmd_get_auditor.c b/src/testing/testing_api_cmd_get_auditor.c @@ -133,6 +133,7 @@ get_auditor_priv_file ( GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_load (acfg, dfn)); + GNUNET_free (dfn); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (acfg, "auditor", diff --git a/src/testing/testing_api_cmd_get_exchange.c b/src/testing/testing_api_cmd_get_exchange.c @@ -99,6 +99,8 @@ cert_cb (void *cls, struct TALER_TESTING_Interpreter *is = ges->is; ges->exchange = NULL; + if (NULL != ges->keys) + TALER_EXCHANGE_keys_decref (ges->keys); ges->keys = keys; switch (hr->http_status) {