backport: Merge bitcoin#26053, 28230, 28500#7256
backport: Merge bitcoin#26053, 28230, 28500#7256vijaydasmp wants to merge 3 commits intodashpay:developfrom
Conversation
✅ No Merge Conflicts DetectedThis PR currently has no conflicts with other open PRs. |
bacccf0 to
ad5b88e
Compare
7d1f6e8 to
cc8a5b2
Compare
…unless 'inputs' are provided b00fc44 test: add coverage for 'add_inputs' dynamic default value (furszy) ddbcfdf RPC: bugfix, 'add_inputs' default value is true unless 'inputs' are provided (furszy) Pull request description: This bugfix was meant to be in bitcoin#25685, but decoupled it to try to make it part of 24.0 release. It's a truly misleading functionality. This PR doesn't change behavior in any way. Just fixes two invalid RPC help messages and adds test coverage for the current behavior. #### Description In both RPC commands `send()` and `walletcreatefundedpsbt` the help message says that `add_inputs` default value is false when it's actually dynamically set by the following statement: ```c++ coin_control.m_allow_other_inputs = rawTx.vin.size() == 0; ``` Which means that, by default, `add_inputs` is true unless there is any pre-set input, in which case, the default is false. ACKs for top commit: achow101: ACK b00fc44 S3RK: ACK b00fc44 Tree-SHA512: 5c68a40d81c994e0ab6de0817db69c4d3dea3a9a64a60362531bf583b7a4c37d524b740905a3f3a89cdbf221913ff5b504746625adb8622788aea93a35bbcd40
c00000d rpc: Add MaybeArg() and Arg() default helper (MarcoFalke) Pull request description: Currently the RPC method implementations have many issues: * Default RPC argument values (and their optionality state) are duplicated in the documentation and the C++ code, with no checks to prevent them from going out of sync. * Getting an optional RPC argument is verbose, using a ternary operator, or worse, a multi-line `if`. Fix all issues by adding default helper that can be called via `self.Arg<int>(0)`. The helper needs a few lines of code in the `src/rpc/util.h` header file. Everything else will be implemented in the cpp file once and if an RPC method needs it. There is also an `self.MaybeArg<int>(0)` helper that works on any arg to return the argument, the default, or a falsy value. ACKs for top commit: ajtowns: reACK c00000d stickies-v: re-ACK c00000d TheCharlatan: re-ACK c00000d Tree-SHA512: e7ddcab3faa319bc53edbdf3f89ce83389d2c4e571d5db42401620ff105e522a4a0669dad08e08cde5fd05c790aec3b806f63261a9100c2778865a489e57381e
…ting secure memory 6ef405d key: don't allocate secure mem for null (invalid) key (Pieter Wuille) d9841a7 Add make_secure_unique helper (Anthony Towns) Pull request description: Bitcoin Core has `secure_allocator`, which allocates inside special "secure" (non-swappable) memory pages, which may be limited in availability. Currently, every `CKey` object uses 32 such secure bytes, even when the `CKey` object contains the (invalid) value zero. Change this to not use memory when the `CKey` is invalid. This is particularly relevant for `BIP324Cipher` which briefly holds a `CKey`, but after receiving the remote's public key and initializing the encryption ciphers, the key is wiped. In case secure memory usage is in high demand, it'd be silly to waste it on P2P encryption keys instead of wallet keys. ACKs for top commit: ajtowns: ACK 6ef405d john-moffett: ACK 6ef405d Tree-SHA512: 987f4376ed825daf034ea4d7c4b4952fe664b25b48f1c09fbcfa6257a40b06c4da7c2caaafa35c346c86bdf298ae21f16c68ea4b1039836990d1a205de2034fd
|
✅ Review complete (commit e6df404) |
WalkthroughThis pull request refactors key validity tracking and RPC parameter handling across multiple systems. The cryptographic key storage mechanism in Sequence DiagramssequenceDiagram
participant Handler as RPC Handler
participant HelpMan as RPCHelpMan
participant ArgValue as ArgValue Impl
participant Request as JSONRPCRequest
Handler->>HelpMan: self.Arg<T>(i) or self.MaybeArg<T>(i)
HelpMan->>HelpMan: store m_req = &request
HelpMan->>ArgValue: compute ArgValue<T>(i)
ArgValue->>Request: check param presence & type
alt Arg<T>: required or default present
ArgValue->>Request: extract and convert value
ArgValue-->>HelpMan: return T (by value/ref)
else MaybeArg<T>: optional without default
ArgValue-->>HelpMan: return empty optional or nullptr
end
HelpMan-->>Handler: return typed argument
Handler->>Handler: use typed parameter
sequenceDiagram
participant Code as Calling Code
participant CKey as CKey Instance
participant Keydata as secure_unique_ptr<KeyType>
participant Secp as libsecp256k1
Code->>CKey: MakeNewKey() or Load()
CKey->>CKey: MakeKeyData() - allocate if needed
CKey->>Keydata: allocate via make_secure_unique
CKey->>CKey: fill/copy key bytes into *keydata
Code->>CKey: Sign() or Negate()
CKey->>CKey: assert(keydata != nullptr)
alt keydata present
CKey->>Secp: pass keydata->data()
Secp-->>CKey: return result
else keydata absent (nullptr)
CKey->>CKey: abort via assert
end
Code->>CKey: Derive() or other operation
CKey->>CKey: on failure: ClearKeyData()
CKey->>Keydata: reset to nullptr
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/support/allocators/secure.h (1)
12-14:⚠️ Potential issue | 🔴 CriticalAdd
#include <utility>and fix thestd::forwardtemplate argument on line 79.Line 79 is ill-formed:
std::forwardrequires an explicit template argument. This header is also missing a direct include of<utility>, which declaresstd::forward, and should not rely on transitive includes.Proposed fix
`#include` <memory> `#include` <string> +#include <utility> `#include` <vector> @@ - return secure_unique_ptr<T>(new (p) T(std::forward(as)...)); + return secure_unique_ptr<T>(new (p) T(std::forward<Args>(as)...));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/support/allocators/secure.h` around lines 12 - 14, Add a direct include for <utility> at the top of secure.h and correct the ill-formed std::forward usage by supplying the proper template parameter; e.g., if the forwarding occurs inside a template<typename T> function or template<typename... Args> wrapper, replace std::forward(arg) with std::forward<T>(arg) or std::forward<Args>(arg) respectively so the template argument is explicit (update the forward call at the site currently using std::forward without a template argument).
🧹 Nitpick comments (1)
src/rpc/util.h (1)
399-422: Constrain theArg()/MaybeArg()template API to prevent link-time failures for unsupported types.The templates accept broad parameter types via
if constexprdispatch, butsrc/rpc/util.cpp:572-579provides only sixArgValuespecializations:std::optional<double>,std::optional<bool>,const std::string*,int,uint64_t, andconst std::string&.Currently, all call sites (
Arg<int>,Arg<uint64_t>,Arg<std::string>,MaybeArg<bool>,MaybeArg<std::string>) are covered. However, adding an unsupported type likeArg<int64_t>orMaybeArg<int>would compile here but fail only at link time.Consider using
static_assert, concepts, or explicit overloads to narrow the API surface and catch misuse in the header.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/rpc/util.h` around lines 399 - 422, The Arg/MaybeArg templates can accept unsupported R and only fail at link time because ArgValue has a limited set of specializations; add a compile-time guard in the header to reject unsupported types: inside template<typename R> auto Arg(size_t i) and template<typename R> auto MaybeArg(size_t i) add a static_assert (or a small concept) that constrains R to the explicit types supported by ArgValue (for Arg: int, uint64_t, const std::string&, and numeric types you actually specialize like double if present; for MaybeArg: std::optional<double>, std::optional<bool>, const std::string*), or rewrite the overloads to only provide those valid instantiations; reference Arg, MaybeArg and ArgValue when implementing the static_assert/concept so misuse (e.g. Arg<int64_t> or MaybeArg<int>) fails at compile time rather than link time.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/rpc/util.cpp`:
- Around line 539-549: DetailMaybeArg() currently returns an RPCArg::Default as
if it were an actual UniValue param, causing MaybeArg<T>() to be unable to
distinguish an omitted argument from an explicitly provided default; modify
DetailMaybeArg() (and the similar block at 560-579) so that it returns nullptr
when the request omits the parameter even if param.m_fallback holds
RPCArg::Default, and only return a pointer to the documented default for callers
that expect a materialized default (e.g., Arg()); adjust callers of
DetailMaybeArg()/MaybeArg<T>() accordingly so MaybeArg<T>() treats nullptr as
"omitted" while Arg() still receives the fallback value when necessary.
In `@src/support/allocators/secure.h`:
- Around line 63-66: The SecureUniqueDeleter::operator()(T* t) currently
deallocates storage without running the destructor for non-trivial T; update
operator() to first call std::destroy_at(t) (to run T's destructor) and then
call secure_allocator<T>().deallocate(t, 1) to free the storage. Make sure to
include <memory> or <iterator> as needed for std::destroy_at and keep the
noexcept specification. This change should be made inside the
SecureUniqueDeleter struct's operator() to ensure placement-new constructed
objects are properly destroyed before deallocation.
In `@test/functional/wallet_fundrawtransaction.py`:
- Around line 1089-1090: The loop variable named input in
test/functional/wallet_fundrawtransaction.py shadows the built-in input() (Ruff
A001); rename the loop variable (both occurrences used over decoded_psbt_inputs)
to a non-builtin name like psbt_input or decoded_input and update any uses
inside the loop (e.g., input["txid"]) accordingly so the tests reference the new
variable name everywhere within each loop (check both the loop at the
decoded_psbt_inputs iteration and the later loop around line 1128).
---
Outside diff comments:
In `@src/support/allocators/secure.h`:
- Around line 12-14: Add a direct include for <utility> at the top of secure.h
and correct the ill-formed std::forward usage by supplying the proper template
parameter; e.g., if the forwarding occurs inside a template<typename T> function
or template<typename... Args> wrapper, replace std::forward(arg) with
std::forward<T>(arg) or std::forward<Args>(arg) respectively so the template
argument is explicit (update the forward call at the site currently using
std::forward without a template argument).
---
Nitpick comments:
In `@src/rpc/util.h`:
- Around line 399-422: The Arg/MaybeArg templates can accept unsupported R and
only fail at link time because ArgValue has a limited set of specializations;
add a compile-time guard in the header to reject unsupported types: inside
template<typename R> auto Arg(size_t i) and template<typename R> auto
MaybeArg(size_t i) add a static_assert (or a small concept) that constrains R to
the explicit types supported by ArgValue (for Arg: int, uint64_t, const
std::string&, and numeric types you actually specialize like double if present;
for MaybeArg: std::optional<double>, std::optional<bool>, const std::string*),
or rewrite the overloads to only provide those valid instantiations; reference
Arg, MaybeArg and ArgValue when implementing the static_assert/concept so misuse
(e.g. Arg<int64_t> or MaybeArg<int>) fails at compile time rather than link
time.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 9483933d-8d02-4b56-b844-6d794c318a00
📒 Files selected for processing (10)
src/key.cppsrc/key.hsrc/rpc/mining.cppsrc/rpc/util.cppsrc/rpc/util.hsrc/support/allocators/secure.hsrc/wallet/rpc/coins.cppsrc/wallet/rpc/spend.cppsrc/wallet/rpc/wallet.cpptest/functional/wallet_fundrawtransaction.py
| static const UniValue* DetailMaybeArg(CheckFn* check, const std::vector<RPCArg>& params, const JSONRPCRequest* req, size_t i) | ||
| { | ||
| CHECK_NONFATAL(i < params.size()); | ||
| const UniValue& arg{CHECK_NONFATAL(req)->params[i]}; | ||
| const RPCArg& param{params.at(i)}; | ||
| if (check) check(param); | ||
|
|
||
| if (!arg.isNull()) return &arg; | ||
| if (!std::holds_alternative<RPCArg::Default>(param.m_fallback)) return nullptr; | ||
| return &std::get<RPCArg::Default>(param.m_fallback); | ||
| } |
There was a problem hiding this comment.
Keep MaybeArg() from materializing documented defaults.
DetailMaybeArg() feeds RPCArg::Default back to both Arg() and MaybeArg(). For MaybeArg<T>(), that makes an omitted parameter with a documented default indistinguishable from an explicitly provided value, which defeats callers that need to detect omission separately.
🛠️ One way to preserve omission for MaybeArg()
-static const UniValue* DetailMaybeArg(CheckFn* check, const std::vector<RPCArg>& params, const JSONRPCRequest* req, size_t i)
+static const UniValue* DetailMaybeArg(CheckFn* check, bool use_default, const std::vector<RPCArg>& params, const JSONRPCRequest* req, size_t i)
{
CHECK_NONFATAL(i < params.size());
const UniValue& arg{CHECK_NONFATAL(req)->params[i]};
const RPCArg& param{params.at(i)};
if (check) check(param);
if (!arg.isNull()) return &arg;
- if (!std::holds_alternative<RPCArg::Default>(param.m_fallback)) return nullptr;
+ if (!use_default || !std::holds_alternative<RPCArg::Default>(param.m_fallback)) return nullptr;
return &std::get<RPCArg::Default>(param.m_fallback);
}
-#define TMPL_INST(check_param, ret_type, return_code) \
+#define TMPL_INST(check_param, use_default, ret_type, return_code) \
template <> \
ret_type RPCHelpMan::ArgValue<ret_type>(size_t i) const \
{ \
const UniValue* maybe_arg{ \
- DetailMaybeArg(check_param, m_args, m_req, i), \
+ DetailMaybeArg(check_param, use_default, m_args, m_req, i), \
}; \
return return_code \
} \
void force_semicolon(ret_type)
-TMPL_INST(nullptr, std::optional<double>, maybe_arg ? std::optional{maybe_arg->get_real()} : std::nullopt;);
-TMPL_INST(nullptr, std::optional<bool>, maybe_arg ? std::optional{maybe_arg->get_bool()} : std::nullopt;);
-TMPL_INST(nullptr, const std::string*, maybe_arg ? &maybe_arg->get_str() : nullptr;);
+TMPL_INST(nullptr, false, std::optional<double>, maybe_arg ? std::optional{maybe_arg->get_real()} : std::nullopt;);
+TMPL_INST(nullptr, false, std::optional<bool>, maybe_arg ? std::optional{maybe_arg->get_bool()} : std::nullopt;);
+TMPL_INST(nullptr, false, const std::string*, maybe_arg ? &maybe_arg->get_str() : nullptr;);
-TMPL_INST(CheckRequiredOrDefault, int, CHECK_NONFATAL(maybe_arg)->getInt<int>(););
-TMPL_INST(CheckRequiredOrDefault, uint64_t, CHECK_NONFATAL(maybe_arg)->getInt<uint64_t>(););
-TMPL_INST(CheckRequiredOrDefault, const std::string&, CHECK_NONFATAL(maybe_arg)->get_str(););
+TMPL_INST(CheckRequiredOrDefault, true, int, CHECK_NONFATAL(maybe_arg)->getInt<int>(););
+TMPL_INST(CheckRequiredOrDefault, true, uint64_t, CHECK_NONFATAL(maybe_arg)->getInt<uint64_t>(););
+TMPL_INST(CheckRequiredOrDefault, true, const std::string&, CHECK_NONFATAL(maybe_arg)->get_str(););Also applies to: 560-579
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/rpc/util.cpp` around lines 539 - 549, DetailMaybeArg() currently returns
an RPCArg::Default as if it were an actual UniValue param, causing MaybeArg<T>()
to be unable to distinguish an omitted argument from an explicitly provided
default; modify DetailMaybeArg() (and the similar block at 560-579) so that it
returns nullptr when the request omits the parameter even if param.m_fallback
holds RPCArg::Default, and only return a pointer to the documented default for
callers that expect a materialized default (e.g., Arg()); adjust callers of
DetailMaybeArg()/MaybeArg<T>() accordingly so MaybeArg<T>() treats nullptr as
"omitted" while Arg() still receives the fallback value when necessary.
| struct SecureUniqueDeleter { | ||
| void operator()(T* t) noexcept { | ||
| secure_allocator<T>().deallocate(t, 1); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In C++20, when a std::unique_ptr uses a custom deleter for an object created with placement new, is the deleter responsible for calling std::destroy_at (or the destructor) before deallocating the raw storage?
💡 Result:
Yes.
std::unique_ptr<T, D>’s destructor does not inherently “know” whether T was created by a normal new expression or by placement new; it simply calls the stored deleter with the stored pointer, and the deleter is required to “dispose of the pointer as appropriate for that deleter” (i.e., do whatever cleanup is correct for how the object/storage were created). [1]
For an object created with placement new, destruction and storage release are separate steps: the destructor is not called implicitly later—you must call it explicitly (e.g., via std::destroy_at(p) or p->~T()), and then (optionally) deallocate the raw storage by whatever mechanism originally provided it. [2] Also, std::destroy_at is purely destruction (it does not deallocate). [3]
So if your unique_ptr owns both:
- the object lifetime created by placement new, and
- the raw storage that must later be freed,
then your custom deleter should typically do both:
struct Del {
void operator()(T* p) const noexcept {
std::destroy_at(p); // end lifetime
::operator delete(p); // or pool.free(p), std::free(p), etc.
}
};If the storage must not be freed (e.g., stack/arena freed elsewhere), the deleter should destroy only.
Sources: [1] std::unique_ptr deleter requirements / disposal semantics (cppreference) [2] placement-new requires explicit destructor call (ISO C++ FAQ) [3] destroy uses std::destroy_at (cppreference allocator_traits::destroy)
Call std::destroy_at() before deallocating storage.
SecureUniqueDeleter deallocates raw storage without destroying the managed object. For non-trivial types T, this skips the destructor and can leak nested resources or bypass required cleanup. Since the object is created via placement new, the deleter must explicitly destroy it before freeing the storage.
Proposed fix
template<typename T>
struct SecureUniqueDeleter {
void operator()(T* t) noexcept {
- secure_allocator<T>().deallocate(t, 1);
+ if (t) {
+ std::destroy_at(t);
+ secure_allocator<T>().deallocate(t, 1);
+ }
}
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| struct SecureUniqueDeleter { | |
| void operator()(T* t) noexcept { | |
| secure_allocator<T>().deallocate(t, 1); | |
| } | |
| struct SecureUniqueDeleter { | |
| void operator()(T* t) noexcept { | |
| if (t) { | |
| std::destroy_at(t); | |
| secure_allocator<T>().deallocate(t, 1); | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/support/allocators/secure.h` around lines 63 - 66, The
SecureUniqueDeleter::operator()(T* t) currently deallocates storage without
running the destructor for non-trivial T; update operator() to first call
std::destroy_at(t) (to run T's destructor) and then call
secure_allocator<T>().deallocate(t, 1) to free the storage. Make sure to include
<memory> or <iterator> as needed for std::destroy_at and keep the noexcept
specification. This change should be made inside the SecureUniqueDeleter
struct's operator() to ensure placement-new constructed objects are properly
destroyed before deallocation.
| for input in decoded_psbt_inputs: | ||
| assert_equal(input["txid"], source_tx["txid"]) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify builtin-shadowing occurrences in this test file
rg -nP '\bfor\s+input\s+in\b' test/functional/wallet_fundrawtransaction.pyRepository: dashpay/dash
Length of output: 1769
🏁 Script executed:
#!/bin/bash
# Search for 'for input in' patterns in the wallet_fundrawtransaction.py test file
cd test/functional
if [ -f wallet_fundrawtransaction.py ]; then
echo "=== Searching for 'for input in' patterns ==="
rg -n 'for\s+input\s+in' wallet_fundrawtransaction.py
echo ""
echo "=== Context around first match (lines 1085-1095) ==="
sed -n '1085,1095p' wallet_fundrawtransaction.py
echo ""
echo "=== Context around second match (lines 1124-1134) ==="
sed -n '1124,1134p' wallet_fundrawtransaction.py
else
echo "File not found"
fiRepository: dashpay/dash
Length of output: 1445
Fix Ruff A001: avoid shadowing builtin input.
Lines 1089 and 1128 use input as a loop variable, which shadows Python's builtin input() function and triggers Ruff A001 linting violations.
Proposed rename
- for input in decoded_psbt_inputs:
- assert_equal(input["txid"], source_tx["txid"])
+ for vin in decoded_psbt_inputs:
+ assert_equal(vin["txid"], source_tx["txid"])This applies to both occurrences at lines 1089 and 1128.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for input in decoded_psbt_inputs: | |
| assert_equal(input["txid"], source_tx["txid"]) | |
| for vin in decoded_psbt_inputs: | |
| assert_equal(vin["txid"], source_tx["txid"]) |
🧰 Tools
🪛 Ruff (0.15.9)
[error] 1089-1089: Variable input is shadowing a Python builtin
(A001)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@test/functional/wallet_fundrawtransaction.py` around lines 1089 - 1090, The
loop variable named input in test/functional/wallet_fundrawtransaction.py
shadows the built-in input() (Ruff A001); rename the loop variable (both
occurrences used over decoded_psbt_inputs) to a non-builtin name like psbt_input
or decoded_input and update any uses inside the loop (e.g., input["txid"])
accordingly so the tests reference the new variable name everywhere within each
loop (check both the loop at the decoded_psbt_inputs iteration and the later
loop around line 1128).
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e6df404452
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| TMPL_INST(nullptr, const std::string*, maybe_arg ? &maybe_arg->get_str() : nullptr;); | ||
|
|
||
| // Required arg or optional arg with default value. | ||
| TMPL_INST(CheckRequiredOrDefault, int, CHECK_NONFATAL(maybe_arg)->getInt<int>();); |
There was a problem hiding this comment.
Return type errors for null required RPC args
ArgValue<int>/ArgValue<const std::string&> now does CHECK_NONFATAL(maybe_arg); when a required parameter is explicitly passed as null, DetailMaybeArg() returns nullptr and this path raises NonFatalCheckError instead of a UniValue::type_error. For RPCs switched to self.Arg<...>() (e.g. generatetodescriptor), malformed input now surfaces as internal RPC_MISC_ERROR rather than a normal type error, which changes API behavior and leaks internal-bug messaging for user input.
Useful? React with 👍 / 👎.
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
I validated the successful agent output against the checked-out source and patch scope. The backport appears mechanically clean overall, but the newly added make_secure_unique helper is not a correct general-purpose forwarding helper because its forwarding expression is malformed and fails on any non-empty argument pack.
Reviewed commit: e6df404
💬 1 nitpick(s)
|
|
||
| // initialize in place, and return as secure_unique_ptr | ||
| try { | ||
| return secure_unique_ptr<T>(new (p) T(std::forward(as)...)); |
There was a problem hiding this comment.
💬 Nitpick: make_secure_unique cannot forward constructor arguments
The new make_secure_unique template is declared as a variadic helper, but it constructs T with std::forward(as)... instead of std::forward<Args>(as).... That expression cannot instantiate for any non-empty argument pack, so the helper only works for default construction despite being introduced as a generic std::make_unique-style utility. The current CKey call site default-constructs KeyType, so this backport still works as used here, but the helper itself is defective as added in this PR.
💡 Suggested change
| return secure_unique_ptr<T>(new (p) T(std::forward(as)...)); | |
| return secure_unique_ptr<T>(new (p) T(std::forward<Args>(as)...)); |
source: ['codex-general']
Bitcoin backports