This error should not be a real problem because code is taking an invalid
reference to an empty object that has no state and could never be used. But
taking the reference could technically be undefined behavior.
Reported by fanquake <fanquake@gmail.com>
https://github.com/bitcoin/bitcoin/pull/31802#issuecomment-2988011933
https://cirrus-ci.com/task/6552721135763456
https://api.cirrus-ci.com/v1/task/6552721135763456/logs/ci.log
include/mp/proxy-types.h:134:5: error: Address of stack memory associated with temporary object of type '(lambda at include/mp/proxy-types.h:134:51)' is still referred to by a temporary object on the stack upon returning to the caller. This will be a dangling reference [clang-analyzer-core.StackAddressEscape,-warnings-as-errors]
134 | return ReadDestEmplace{TypeList<LocalType>(), [&](auto&&... args) -> decltype(auto) {
| ^
build/test/mp/test/foo.capnp.proxy-server.c++:51:12: note: Calling 'serverInvoke<mp::ProxyServer<mp::test::messages::FooInterface>, capnp::CallContext<mp::test::messages::FooInterface::PassCustomParams, mp::test::messages::FooInterface::PassCustomResults>, mp::ServerField<1, mp::Accessor<mp::foo_fields::Arg, 17>, mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall>>>'
51 | return serverInvoke(*this, call_context, MakeServerField<1, Accessor<foo_fields::Arg, FIELD_IN | FIELD_BOXED>>(Make<ServerRet, Accessor<foo_fields::Result, FIELD_OUT | FIELD_BOXED>>(ServerCall())));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/mp/proxy-types.h:739:16: note: Calling 'ReplaceVoid<(lambda at include/mp/proxy-types.h:739:28), (lambda at include/mp/proxy-types.h:740:13)>'
739 | return ReplaceVoid([&]() { return fn.invoke(server_context, ArgList()); },
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
740 | [&]() { return kj::Promise<CallContext>(kj::mv(call_context)); })
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/mp/proxy-types.h:700:19: note: 'is_same_v' is true
700 | if constexpr (std::is_same_v<decltype(fn()), void>) {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/mp/proxy-types.h:700:5: note: Taking true branch
700 | if constexpr (std::is_same_v<decltype(fn()), void>) {
| ^
include/mp/proxy-types.h:701:9: note: Calling 'operator()'
701 | fn();
| ^~~~
include/mp/proxy-types.h:739:43: note: Calling 'ServerField::invoke'
739 | return ReplaceVoid([&]() { return fn.invoke(server_context, ArgList()); },
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/mp/proxy-types.h:563:16: note: Calling 'PassField<mp::Accessor<mp::foo_fields::Arg, 17>, mp::test::FooCustom, mp::ServerInvokeContext<mp::ProxyServer<mp::test::messages::FooInterface>, capnp::CallContext<mp::test::messages::FooInterface::PassCustomParams, mp::test::messages::FooInterface::PassCustomResults>>, const mp::ServerRet<mp::Accessor<mp::foo_fields::Result, 18>, mp::ServerCall> &, mp::TypeList<>>'
563 | return PassField<Accessor>(Priority<2>(),
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
564 | typename Split<argc, ArgTypes>::First(),
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
565 | server_context,
| ~~~~~~~~~~~~~~~
566 | this->parent(),
| ~~~~~~~~~~~~~~~
567 | typename Split<argc, ArgTypes>::Second(),
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
568 | std::forward<Args>(args)...);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/mp/proxy-types.h:304:5: note: Calling 'MaybeReadField<mp::TypeList<mp::test::FooCustom>, mp::InvokeContext &, mp::StructField<mp::Accessor<mp::foo_fields::Arg, 17>, const mp::test::messages::FooInterface::PassCustomParams::Reader>, mp::ReadDestEmplace<mp::test::FooCustom, (lambda at include/mp/proxy-types.h:305:83)>>'
304 | MaybeReadField(std::integral_constant<bool, Accessor::in>(), TypeList<ArgType>(), invoke_context,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
305 | Make<StructField, Accessor>(params), ReadDestEmplace(TypeList<ArgType>(), [&](auto&&... args) -> auto& {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
306 | param.emplace(std::forward<decltype(args)>(args)...);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
307 | return *param;
| ~~~~~~~~~~~~~~
308 | }));
| ~~~
include/mp/proxy-types.h:276:5: note: Calling 'ReadField<mp::test::FooCustom, mp::InvokeContext &, mp::StructField<mp::Accessor<mp::foo_fields::Arg, 17>, const mp::test::messages::FooInterface::PassCustomParams::Reader>, mp::ReadDestEmplace<mp::test::FooCustom, (lambda at include/mp/proxy-types.h:305:83)>>'
276 | ReadField(std::forward<Args>(args)...);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/mp/proxy-types.h:175:12: note: Calling 'CustomReadField<mp::StructField<mp::Accessor<mp::foo_fields::Arg, 17>, const mp::test::messages::FooInterface::PassCustomParams::Reader>, mp::ReadDestEmplace<mp::test::FooCustom, (lambda at include/mp/proxy-types.h:305:83)>>'
175 | return CustomReadField(TypeList<RemoveCvRef<LocalTypes>...>(), Priority<2>(), std::forward<Args>(args)...);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test/mp/test/foo-types.h:51:12: note: Calling 'ReadDestEmplace::update'
51 | return read_dest.update([&](FooCustom& value) {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
52 | value.v1 = ReadField(TypeList<std::string>(), invoke_context, mp::Make<mp::ValueField>(custom.getV1()), ReadDestTemp<std::string>());
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53 | value.v2 = custom.getV2();
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
54 | });
| ~~
include/mp/proxy-types.h:112:23: note: 'is_const_v' is false
112 | if constexpr (std::is_const_v<std::remove_reference_t<std::invoke_result_t<EmplaceFn>>>) {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/mp/proxy-types.h:112:9: note: Taking false branch
112 | if constexpr (std::is_const_v<std::remove_reference_t<std::invoke_result_t<EmplaceFn>>>) {
| ^
include/mp/proxy-types.h:122:13: note: Calling 'operator()'
122 | update_fn(temp);
| ^~~~~~~~~~~~~~~
test/mp/test/foo-types.h:52:113: note: Calling 'ReadDestTemp<std::basic_string<char>>'
52 | value.v1 = ReadField(TypeList<std::string>(), invoke_context, mp::Make<mp::ValueField>(custom.getV1()), ReadDestTemp<std::string>());
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
include/mp/proxy-types.h:134:5: note: Address of stack memory associated with temporary object of type '(lambda at include/mp/proxy-types.h:134:51)' is still referred to by a temporary object on the stack upon returning to the caller. This will be a dangling reference
134 | return ReadDestEmplace{TypeList<LocalType>(), [&](auto&&... args) -> decltype(auto) {
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
135 | return LocalType{std::forward<decltype(args)>(args)...};
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
136 | }};
| ~