diff options
author | Christian Grothoff <christian@grothoff.org> | 2018-04-05 10:51:21 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2018-04-05 10:51:21 +0200 |
commit | b46239b12f00e64888d4a8d35c019c850e740840 (patch) | |
tree | 0b234000846892d2216fbf433c2c650e8add8de4 | |
parent | e248e97cbf0bf0d2f2f1870515de54c574f4b175 (diff) |
use GNUNET_NZL instead of crazy hacks to ensure non-zero vararg array lengths
-rw-r--r-- | src/backenddb/plugin_merchantdb_postgres.c | 363 | ||||
-rw-r--r-- | src/lib/merchant_api_pay.c | 20 |
2 files changed, 185 insertions, 198 deletions
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c index b6277183..c7427d77 100644 --- a/src/backenddb/plugin_merchantdb_postgres.c +++ b/src/backenddb/plugin_merchantdb_postgres.c @@ -2506,218 +2506,207 @@ process_deposits_for_refund_cb (void *cls, unsigned int num_results) { struct InsertRefundContext *ctx = cls; + struct TALER_Amount current_refund; + struct TALER_Amount deposit_refund[GNUNET_NZL(num_results)]; + struct TALER_CoinSpendPublicKeyP deposit_coin_pubs[GNUNET_NZL(num_results)]; + struct TALER_Amount deposit_amount_with_fee[GNUNET_NZL(num_results)]; + struct TALER_Amount deposit_refund_fee[GNUNET_NZL(num_results)]; - if (0 == num_results) - { - ctx->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; - /* We must return early here, or the zero-length variable size arrays below - will be undefined behavior */ - return; - } + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (ctx->refund->currency, + ¤t_refund)); + /* Pass 1: Collect amount of existing refunds into current_refund. + * Also store existing refunded amount for each deposit in deposit_refund. */ + + for (unsigned int i=0; i<num_results; i++) { - struct TALER_Amount current_refund; - struct TALER_Amount deposit_refund[num_results]; - struct TALER_CoinSpendPublicKeyP deposit_coin_pubs[num_results]; - struct TALER_Amount deposit_amount_with_fee[num_results]; - struct TALER_Amount deposit_refund_fee[num_results]; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_Amount amount_with_fee; + struct TALER_Amount refund_fee; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("coin_pub", + &coin_pub), + TALER_PQ_result_spec_amount ("amount_with_fee", + &amount_with_fee), + TALER_PQ_result_spec_amount ("refund_fee", + &refund_fee), + GNUNET_PQ_result_spec_end + }; - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (ctx->refund->currency, - ¤t_refund)); + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; + return; + } - /* Pass 1: Collect amount of existing refunds into current_refund. - * Also store existing refunded amount for each deposit in deposit_refund. */ + struct FindRefundContext ictx; + enum GNUNET_DB_QueryStatus ires; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (&coin_pub), + GNUNET_PQ_query_param_end + }; - for (unsigned int i=0; i<num_results; i++) + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (ctx->refund->currency, + &ictx.refunded_amount)); + ictx.err = GNUNET_OK; /* no error so far */ + ires = GNUNET_PQ_eval_prepared_multi_select (ctx->pg->conn, + "find_refunds", + params, + &process_refund_cb, + &ictx); + if ( (GNUNET_OK != ictx.err) || + (GNUNET_DB_STATUS_HARD_ERROR == ires) ) { - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_Amount amount_with_fee; - struct TALER_Amount refund_fee; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("coin_pub", - &coin_pub), - TALER_PQ_result_spec_amount ("amount_with_fee", - &amount_with_fee), - TALER_PQ_result_spec_amount ("refund_fee", - &refund_fee), - GNUNET_PQ_result_spec_end - }; + GNUNET_break (0); + ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; + return; + } + if (GNUNET_DB_STATUS_SOFT_ERROR == ires) + { + ctx->qs = GNUNET_DB_STATUS_SOFT_ERROR; + return; + } + deposit_refund[i] = ictx.refunded_amount; + deposit_amount_with_fee[i] = amount_with_fee; + deposit_coin_pubs[i] = coin_pub; + deposit_refund_fee[i] = refund_fee; + if (GNUNET_SYSERR == + TALER_amount_add (¤t_refund, + ¤t_refund, + &ictx.refunded_amount)) + { + GNUNET_break (0); + ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Existing refund for coin %s is %s\n", + TALER_B2S (&coin_pub), + TALER_amount2s (&ictx.refunded_amount)); + } - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - i)) - { - GNUNET_break (0); - ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; - return; - } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Total existing refund is %s\n", + TALER_amount2s (¤t_refund)); - struct FindRefundContext ictx; - enum GNUNET_DB_QueryStatus ires; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&coin_pub), - GNUNET_PQ_query_param_end - }; + /* stop immediately if we are done */ + if (0 >= TALER_amount_cmp (ctx->refund, + ¤t_refund)) + { + ctx->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; + return; + } - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (ctx->refund->currency, - &ictx.refunded_amount)); - ictx.err = GNUNET_OK; /* no error so far */ - ires = GNUNET_PQ_eval_prepared_multi_select (ctx->pg->conn, - "find_refunds", - params, - &process_refund_cb, - &ictx); - if ( (GNUNET_OK != ictx.err) || - (GNUNET_DB_STATUS_HARD_ERROR == ires) ) - { - GNUNET_break (0); - ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; - return; - } - if (GNUNET_DB_STATUS_SOFT_ERROR == ires) - { - ctx->qs = GNUNET_DB_STATUS_SOFT_ERROR; - return; - } - deposit_refund[i] = ictx.refunded_amount; - deposit_amount_with_fee[i] = amount_with_fee; - deposit_coin_pubs[i] = coin_pub; - deposit_refund_fee[i] = refund_fee; - if (GNUNET_SYSERR == - TALER_amount_add (¤t_refund, - ¤t_refund, - &ictx.refunded_amount)) - { - GNUNET_break (0); - ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Existing refund for coin %s is %s\n", - TALER_B2S (&coin_pub), - TALER_amount2s (&ictx.refunded_amount)); - } + /* Phase 2: Try to increase current refund until it matches desired refund */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Total existing refund is %s\n", - TALER_amount2s (¤t_refund)); + for (unsigned int i=0;i<num_results; i++) + { + const struct TALER_Amount *increment; + struct TALER_Amount left; + struct TALER_Amount remaining_refund; - /* stop immediately if we are done */ - if (0 >= TALER_amount_cmp (ctx->refund, - ¤t_refund)) + /* How much of the coin is left after the existing refunds? */ + if (GNUNET_SYSERR == + TALER_amount_subtract (&left, + &deposit_amount_with_fee[i], + &deposit_refund[i])) { - ctx->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; + GNUNET_break (0); + ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; return; } - /* Phase 2: Try to increase current refund until it matches desired refund */ - - for (unsigned int i=0;i<num_results; i++) + if ( (0 == left.value) && + (0 == left.fraction) ) { - const struct TALER_Amount *increment; - struct TALER_Amount left; - struct TALER_Amount remaining_refund; - - /* How much of the coin is left after the existing refunds? */ - if (GNUNET_SYSERR == - TALER_amount_subtract (&left, - &deposit_amount_with_fee[i], - &deposit_refund[i])) - { - GNUNET_break (0); - ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; - return; - } - - if ( (0 == left.value) && - (0 == left.fraction) ) - { - /* coin was fully refunded, move to next coin */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Coin %s fully refunded, moving to next coin\n", - TALER_B2S (&deposit_coin_pubs[i])); - continue; - } + /* coin was fully refunded, move to next coin */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Coin %s fully refunded, moving to next coin\n", + TALER_B2S (&deposit_coin_pubs[i])); + continue; + } - /* How much of the refund is left? */ - if (GNUNET_SYSERR == - TALER_amount_subtract (&remaining_refund, - ctx->refund, - ¤t_refund)) - { - GNUNET_break (0); - ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; - return; - } + /* How much of the refund is left? */ + if (GNUNET_SYSERR == + TALER_amount_subtract (&remaining_refund, + ctx->refund, + ¤t_refund)) + { + GNUNET_break (0); + ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; + return; + } - /* By how much will we increase the refund for this coin? */ - if (0 >= TALER_amount_cmp (&remaining_refund, - &left)) - { - /* remaining_refund <= left */ - increment = &remaining_refund; - } - else - { - increment = &left; - } + /* By how much will we increase the refund for this coin? */ + if (0 >= TALER_amount_cmp (&remaining_refund, + &left)) + { + /* remaining_refund <= left */ + increment = &remaining_refund; + } + else + { + increment = &left; + } - if (GNUNET_SYSERR == - TALER_amount_add (¤t_refund, - ¤t_refund, - increment)) - { - GNUNET_break (0); - ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; - return; - } + if (GNUNET_SYSERR == + TALER_amount_add (¤t_refund, + ¤t_refund, + increment)) + { + GNUNET_break (0); + ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; + return; + } - /* actually run the refund */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Coin %s deposit amount is %s\n", - TALER_B2S (&deposit_coin_pubs[i]), - TALER_amount2s (&deposit_amount_with_fee[i])); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Coin %s refund will be incremented by %s\n", - TALER_B2S (&deposit_coin_pubs[i]), - TALER_amount2s (increment)); + /* actually run the refund */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Coin %s deposit amount is %s\n", + TALER_B2S (&deposit_coin_pubs[i]), + TALER_amount2s (&deposit_amount_with_fee[i])); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Coin %s refund will be incremented by %s\n", + TALER_B2S (&deposit_coin_pubs[i]), + TALER_amount2s (increment)); + { + enum GNUNET_DB_QueryStatus qs; + + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + (qs = insert_refund (ctx->pg, + ctx->merchant_pub, + ctx->h_contract_terms, + &deposit_coin_pubs[i], + ctx->reason, + increment, + &deposit_refund_fee[i]))) { - enum GNUNET_DB_QueryStatus qs; - - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - (qs = insert_refund (ctx->pg, - ctx->merchant_pub, - ctx->h_contract_terms, - &deposit_coin_pubs[i], - ctx->reason, - increment, - &deposit_refund_fee[i]))) - { - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); - ctx->qs = qs; - return; - } + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + ctx->qs = qs; + return; } - /* stop immediately if we are done */ - if (0 == TALER_amount_cmp (ctx->refund, - ¤t_refund)) - return; } - - /** - * We end up here if nto all of the refund has been covered. - * Although this should be checked as the business should never - * issue a refund bigger than the contract's actual price, we cannot - * rely upon the frontend being correct. - */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "The refund of %s is bigger than the order's value\n", - TALER_amount2s (ctx->refund)); - ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; + /* stop immediately if we are done */ + if (0 == TALER_amount_cmp (ctx->refund, + ¤t_refund)) + return; } + + /** + * We end up here if nto all of the refund has been covered. + * Although this should be checked as the business should never + * issue a refund bigger than the contract's actual price, we cannot + * rely upon the frontend being correct. + */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "The refund of %s is bigger than the order's value\n", + TALER_amount2s (ctx->refund)); + ctx->qs = GNUNET_DB_STATUS_HARD_ERROR; } diff --git a/src/lib/merchant_api_pay.c b/src/lib/merchant_api_pay.c index b0a2f0e0..973a9b5e 100644 --- a/src/lib/merchant_api_pay.c +++ b/src/lib/merchant_api_pay.c @@ -76,7 +76,7 @@ struct TALER_MERCHANT_Pay * Operational mode, either "pay" or "abort-refund". */ const char *mode; - + /** * Reference to the execution context. */ @@ -96,7 +96,7 @@ struct TALER_MERCHANT_Pay * Hash of the contract, only available in "abort-refund" mode. */ struct GNUNET_HashCode h_contract_terms; - + }; @@ -132,9 +132,7 @@ check_abort_refund (struct TALER_MERCHANT_Pay *ph, } num_refunds = json_array_size (refunds); { - /* The "+ 1" is necessary since num_refunds might be 0, and variable size arrays must - * be >0, or it's undefined behavior */ - struct TALER_MERCHANT_RefundEntry res[num_refunds + 1]; + struct TALER_MERCHANT_RefundEntry res[GNUNET_NZL(num_refunds)]; for (unsigned int i=0;i<num_refunds;i++) { @@ -166,7 +164,7 @@ check_abort_refund (struct TALER_MERCHANT_Pay *ph, rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS)); rr.h_contract_terms = ph->h_contract_terms; rr.coin_pub = res[i].coin_pub; - rr.merchant = merchant_pub; + rr.merchant = merchant_pub; rr.rtransaction_id = GNUNET_htonll (res[i].rtransaction_id); found = -1; for (unsigned int j=0;j<ph->num_coins;j++) @@ -373,7 +371,7 @@ handle_pay_finished (void *cls, GNUNET_break (0); response_code = 0; break; - } + } ph->pay_cb (ph->pay_cb_cls, response_code, TALER_JSON_get_error_code (json), @@ -383,7 +381,7 @@ handle_pay_finished (void *cls, { GNUNET_assert (0 == strcasecmp (ph->mode, "abort-refund")); - + switch (response_code) { case 0: @@ -425,7 +423,7 @@ handle_pay_finished (void *cls, GNUNET_break (0); response_code = 0; break; - } + } ph->abort_cb (ph->abort_cb_cls, response_code, TALER_JSON_get_error_code (json), @@ -435,7 +433,7 @@ handle_pay_finished (void *cls, NULL, json); } - + TALER_MERCHANT_pay_cancel (ph); } @@ -660,7 +658,7 @@ prepare_pay_generic (struct GNUNET_CURL_Context *ctx, GNUNET_break (0); return NULL; } - + dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); dr.h_contract_terms = *h_contract_terms; |