Skip to content

Commit 53c532e

Browse files
committed
proxy-types: fix clang-tidy StackAddressEscape error
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 <[email protected]> bitcoin/bitcoin#31802 (comment) 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 | }}; | ~
1 parent 132455d commit 53c532e

File tree

2 files changed

+4
-3
lines changed

2 files changed

+4
-3
lines changed

.clang-tidy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ performance-*,
2626
readability-const-return-type,
2727
readability-redundant-declaration,
2828
readability-redundant-string-init,
29+
clang-analyzer-core.StackAddressEscape,
2930
'
3031
HeaderFilterRegex: '.'
3132
WarningsAsErrors: '*'

include/mp/proxy-types.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ struct StructField
9292
template <typename LocalType, typename EmplaceFn>
9393
struct ReadDestEmplace
9494
{
95-
ReadDestEmplace(TypeList<LocalType>, EmplaceFn&& emplace_fn) : m_emplace_fn(emplace_fn) {}
95+
ReadDestEmplace(TypeList<LocalType>, EmplaceFn emplace_fn) : m_emplace_fn(std::move(emplace_fn)) {}
9696

9797
//! Simple case. If ReadField impementation calls this construct() method
9898
//! with constructor arguments, just pass them on to the emplace function.
@@ -123,15 +123,15 @@ struct ReadDestEmplace
123123
return temp;
124124
}
125125
}
126-
EmplaceFn& m_emplace_fn;
126+
EmplaceFn m_emplace_fn;
127127
};
128128

129129
//! Helper function to create a ReadDestEmplace object that constructs a
130130
//! temporary, ReadField can return.
131131
template <typename LocalType>
132132
auto ReadDestTemp()
133133
{
134-
return ReadDestEmplace{TypeList<LocalType>(), [&](auto&&... args) -> decltype(auto) {
134+
return ReadDestEmplace{TypeList<LocalType>(), [](auto&&... args) -> decltype(auto) {
135135
return LocalType{std::forward<decltype(args)>(args)...};
136136
}};
137137
}

0 commit comments

Comments
 (0)