-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Prevent valgrind false positive in rest_blockhash_by_height #18785
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
A bad interaction between valgrind and clang 6.0.0-1ubuntu2 with -O2 optimizations makes valgrind misleadingly imply C++ code is reading an uninitialized blockheight value in rest_blockhash_by_height just because that's what clang optimized code is doing. The C++ code looks like: int32_t blockheight; if (!ParseInt32(height_str, &blockheight) || blockheight < 0) { while the optimized code looks like: 0x00000000000f97ab <+123>: callq 0x4f8860 <ParseInt32(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int*)> 0x00000000000f97b0 <+128>: mov 0xc(%rsp),%ebx 0x00000000000f97b4 <+132>: test %ebx,%ebx 0x00000000000f97b6 <+134>: js 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> 0x00000000000f97bc <+140>: xor $0x1,%al 0x00000000000f97be <+142>: jne 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> During the rest_interface.py test: self.test_rest_request("/blockhashbyheight/", ret_type=RetType.OBJ, status=400) when height_str is empty, ParseInt32 returns false and blockheight value is never assigned. The optimized code reads the uninitialized blockheight value in 0xc(%rsp) before the checking the ParseInt32 return value in %al, which is harmless, but triggers the following error from valgrind: ==30660== Thread 13 b-httpworker.2: ==30660== Conditional jump or move depends on uninitialised value(s) ==30660== at 0x2017B6: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:614) ==30660== by 0x2041B9: operator() (rest.cpp:670) ==30660== by 0x2041B9: std::_Function_handler<bool (HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&), StartREST(util::Ref const&)::$_1>::_M_invoke(std::_Any_data const&, HTTPRequest*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (std_function.h:301) ==30660== by 0x3EC994: operator() (std_function.h:706) ==30660== by 0x3EC994: HTTPWorkItem::operator()() (httpserver.cpp:55) ==30660== by 0x3ED16D: WorkQueue<HTTPClosure>::Run() (httpserver.cpp:114) ==30660== by 0x3E9168: HTTPWorkQueueRun(WorkQueue<HTTPClosure>*, int) (httpserver.cpp:342) ==30660== by 0x3EDAAA: __invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:60) ==30660== by 0x3EDAAA: __invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:95) ==30660== by 0x3EDAAA: _M_invoke<0, 1, 2> (thread:234) ==30660== by 0x3EDAAA: operator() (thread:243) ==30660== by 0x3EDAAA: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> > >::_M_run() (thread:186) ==30660== by 0x64256DE: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25) ==30660== by 0x54876DA: start_thread (pthread_create.c:463) ==30660== by 0x6DC888E: clone (clone.S:95) ==30660== Uninitialised value was created by a stack allocation ==30660== at 0x20173A: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:608) ==30660== { <insert_a_suppression_name_here> Memcheck:Cond fun:_ZL24rest_blockhash_by_heightRKN4util3RefEP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE fun:operator() fun:_ZNSt17_Function_handlerIFbP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEZ9StartRESTRKN4util3RefEE3$_1E9_M_invokeERKSt9_Any_dataOS1_S9_ fun:operator() fun:_ZN12HTTPWorkItemclEv fun:_ZN9WorkQueueI11HTTPClosureE3RunEv fun:_ZL16HTTPWorkQueueRunP9WorkQueueI11HTTPClosureEi fun:__invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:__invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:_M_invoke<0, 1, 2> fun:operator() fun:_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvP9WorkQueueI11HTTPClosureEiES6_iEEEEE6_M_runEv obj:/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 fun:start_thread fun:clone } This is a known bad interaction between clang and valgrind. The clang optimized code is correct but valgrind has no way of knowing that accessing the uninitialized value isn't a problem. Issue has been reported previously: https://bugs.llvm.org/show_bug.cgi?id=32604#c4 Z3Prover/z3#972 This commit just sets blockheight to 0 as a workaround.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK. Nice catch. I stared at this code for at least half an hour, not knowing that the code is right to begin with.
src/rest.cpp
Outdated
@@ -607,7 +607,7 @@ static bool rest_blockhash_by_height(HTTPRequest* req, | |||
std::string height_str; | |||
const RetFormat rf = ParseDataFormat(height_str, str_uri_part); | |||
|
|||
int32_t blockheight; | |||
int32_t blockheight = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int32_t blockheight = 0; | |
int32_t blockheight = 0; // Initialization only needed as workaround for -O2 compiler optimization and valgrind interaction, see https://github.com/bitcoin/bitcoin/pull/18785 |
This will prevent valgrind from detecting real issues, so maybe add a comment with motivation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
re: https://github.com/bitcoin/bitcoin/pull/18785/files#r416090195
This will prevent valgrind from detecting real issues, so maybe add a comment with motivation?
Thanks, added comment. I'm not sure if it is too likely to be helpful to someone reading the code, but I guess it's better to have an explanation for something you wouldn't expect to be necessary.
I also changed init value from 0 to -1 just to make it clear that if height is not parsed it will always trigger the error, regardless of the bool return value, and there's no strange case where this is supposed to return information about block 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated 86433fd -> fcb7261 (pr/grind.1
-> pr/grind.2
, compare) with explanation / less confusing init value
src/rest.cpp
Outdated
@@ -607,7 +607,7 @@ static bool rest_blockhash_by_height(HTTPRequest* req, | |||
std::string height_str; | |||
const RetFormat rf = ParseDataFormat(height_str, str_uri_part); | |||
|
|||
int32_t blockheight; | |||
int32_t blockheight = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
re: https://github.com/bitcoin/bitcoin/pull/18785/files#r416090195
This will prevent valgrind from detecting real issues, so maybe add a comment with motivation?
Thanks, added comment. I'm not sure if it is too likely to be helpful to someone reading the code, but I guess it's better to have an explanation for something you wouldn't expect to be necessary.
I also changed init value from 0 to -1 just to make it clear that if height is not parsed it will always trigger the error, regardless of the bool return value, and there's no strange case where this is supposed to return information about block 0
ACK fcb7261 |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
ACK fcb7261 Note that MemorySanitizer is not fooled by this type of optimization. MemorySanitizer can be trivially be enabled in Travis by merging #18288. Review welcome :) Valgrind has well documented optimization issues. From the Valgrind documentation:
|
…h_by_height fcb7261 Prevent valgrind false positive in rest_blockhash_by_height (Russell Yanofsky) Pull request description: A bad interaction between valgrind and clang 6.0.0-1ubuntu2 with -O2 optimizations makes valgrind misleadingly imply C++ code is reading an uninitialized blockheight value in `rest_blockhash_by_height` just because that's what clang optimized code is doing. The C++ code looks like: ```c++ int32_t blockheight; if (!ParseInt32(height_str, &blockheight) || blockheight < 0) { ``` while the optimized code looks like: ``` 0x00000000000f97ab <+123>: callq 0x4f8860 <ParseInt32(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int*)> 0x00000000000f97b0 <+128>: mov 0xc(%rsp),%ebx 0x00000000000f97b4 <+132>: test %ebx,%ebx 0x00000000000f97b6 <+134>: js 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> 0x00000000000f97bc <+140>: xor $0x1,%al 0x00000000000f97be <+142>: jne 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> ``` During the rest_interface.py test: https://github.com/bitcoin/bitcoin/blob/eef90c14ed0f559e3f6e187341009270b84f45cb/test/functional/interface_rest.py#L266 when `height_str` is empty, `ParseInt32` returns false and `blockheight` value is never assigned. The optimized code reads the uninitialized `blockheight` value in `0xc(%rsp)` before the checking the `ParseInt32` return value in `%al`, which is harmless, but triggers the following error from valgrind: ``` ==30660== Thread 13 b-httpworker.2: ==30660== Conditional jump or move depends on uninitialised value(s) ==30660== at 0x2017B6: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:614) ==30660== by 0x2041B9: operator() (rest.cpp:670) ==30660== by 0x2041B9: std::_Function_handler<bool (HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&), StartREST(util::Ref const&)::$_1>::_M_invoke(std::_Any_data const&, HTTPRequest*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (std_function.h:301) ==30660== by 0x3EC994: operator() (std_function.h:706) ==30660== by 0x3EC994: HTTPWorkItem::operator()() (httpserver.cpp:55) ==30660== by 0x3ED16D: WorkQueue<HTTPClosure>::Run() (httpserver.cpp:114) ==30660== by 0x3E9168: HTTPWorkQueueRun(WorkQueue<HTTPClosure>*, int) (httpserver.cpp:342) ==30660== by 0x3EDAAA: __invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:60) ==30660== by 0x3EDAAA: __invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:95) ==30660== by 0x3EDAAA: _M_invoke<0, 1, 2> (thread:234) ==30660== by 0x3EDAAA: operator() (thread:243) ==30660== by 0x3EDAAA: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> > >::_M_run() (thread:186) ==30660== by 0x64256DE: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25) ==30660== by 0x54876DA: start_thread (pthread_create.c:463) ==30660== by 0x6DC888E: clone (clone.S:95) ==30660== Uninitialised value was created by a stack allocation ==30660== at 0x20173A: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:608) ==30660== { <insert_a_suppression_name_here> Memcheck:Cond fun:_ZL24rest_blockhash_by_heightRKN4util3RefEP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE fun:operator() fun:_ZNSt17_Function_handlerIFbP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEZ9StartRESTRKN4util3RefEE3$_1E9_M_invokeERKSt9_Any_dataOS1_S9_ fun:operator() fun:_ZN12HTTPWorkItemclEv fun:_ZN9WorkQueueI11HTTPClosureE3RunEv fun:_ZL16HTTPWorkQueueRunP9WorkQueueI11HTTPClosureEi fun:__invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:__invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:_M_invoke<0, 1, 2> fun:operator() fun:_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvP9WorkQueueI11HTTPClosureEiES6_iEEEEE6_M_runEv obj:/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 fun:start_thread fun:clone } ``` This is a known bad interaction between clang and valgrind. The clang optimized code is correct but valgrind has no way of knowing that accessing the uninitialized value isn't a problem. Issue has been reported previously: - https://bugs.llvm.org/show_bug.cgi?id=32604#c4 - Z3Prover/z3#972 This commit just sets blockheight to -1 as a workaround. This change was originally made in 41d5d65 from bitcoin#18740 to fix the travis error there (https://travis-ci.org/github/bitcoin/bitcoin/jobs/678453061#L7157) but MarcoFalke suggested bitcoin#18740 (comment) moving to a new PR, since apparently the error's been seen on travis previously ACKs for top commit: MarcoFalke: ACK fcb7261 practicalswift: ACK fcb7261 Tree-SHA512: ec8abf45bd3d6c6e0e7e404d0b2a749efd43910619b84b0b5fe7dab22881598d1011a0f3ff2e146bf46320b63eb152bf63c62c06f1ab84c35dd640abc468f18f
This should no-longer be necessary after bitcoin#18785.
d7120f7 valgrind : remove duplicate BCLog::Logger suppression (fanquake) 708e3c7 valgrind: remove rest_blockhash_by_height suppression (fanquake) Pull request description: bitcoin@708e3c7: `Suppress rest_blockhash_by_height` should no longer be needed after bitcoin#18785. bitcoin@d7120f7 : Removes a duplicate `Suppress BCLog::Logger::StartLogging()` suppression that was added in bitcoin#17770. ACKs for top commit: MarcoFalke: ACK d7120f7 practicalswift: ACK d7120f7 -- patch looks correct and valgrind Travis job is happy Tree-SHA512: 45f5b9fa64bf83cada3cd9ad33c245f660376d5b29f51a2531d83133940090df945f5ef26c5847d6ec024ffab9528d55573c5cf9ca5e73795f9abfc971b3d29b
This should no-longer be necessary after bitcoin#18785.
…h_by_height fcb7261 Prevent valgrind false positive in rest_blockhash_by_height (Russell Yanofsky) Pull request description: A bad interaction between valgrind and clang 6.0.0-1ubuntu2 with -O2 optimizations makes valgrind misleadingly imply C++ code is reading an uninitialized blockheight value in `rest_blockhash_by_height` just because that's what clang optimized code is doing. The C++ code looks like: ```c++ int32_t blockheight; if (!ParseInt32(height_str, &blockheight) || blockheight < 0) { ``` while the optimized code looks like: ``` 0x00000000000f97ab <+123>: callq 0x4f8860 <ParseInt32(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int*)> 0x00000000000f97b0 <+128>: mov 0xc(%rsp),%ebx 0x00000000000f97b4 <+132>: test %ebx,%ebx 0x00000000000f97b6 <+134>: js 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> 0x00000000000f97bc <+140>: xor $0x1,%al 0x00000000000f97be <+142>: jne 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> ``` During the rest_interface.py test: https://github.com/bitcoin/bitcoin/blob/eef90c14ed0f559e3f6e187341009270b84f45cb/test/functional/interface_rest.py#L266 when `height_str` is empty, `ParseInt32` returns false and `blockheight` value is never assigned. The optimized code reads the uninitialized `blockheight` value in `0xc(%rsp)` before the checking the `ParseInt32` return value in `%al`, which is harmless, but triggers the following error from valgrind: ``` ==30660== Thread 13 b-httpworker.2: ==30660== Conditional jump or move depends on uninitialised value(s) ==30660== at 0x2017B6: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:614) ==30660== by 0x2041B9: operator() (rest.cpp:670) ==30660== by 0x2041B9: std::_Function_handler<bool (HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&), StartREST(util::Ref const&)::$_1>::_M_invoke(std::_Any_data const&, HTTPRequest*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (std_function.h:301) ==30660== by 0x3EC994: operator() (std_function.h:706) ==30660== by 0x3EC994: HTTPWorkItem::operator()() (httpserver.cpp:55) ==30660== by 0x3ED16D: WorkQueue<HTTPClosure>::Run() (httpserver.cpp:114) ==30660== by 0x3E9168: HTTPWorkQueueRun(WorkQueue<HTTPClosure>*, int) (httpserver.cpp:342) ==30660== by 0x3EDAAA: __invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:60) ==30660== by 0x3EDAAA: __invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:95) ==30660== by 0x3EDAAA: _M_invoke<0, 1, 2> (thread:234) ==30660== by 0x3EDAAA: operator() (thread:243) ==30660== by 0x3EDAAA: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> > >::_M_run() (thread:186) ==30660== by 0x64256DE: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25) ==30660== by 0x54876DA: start_thread (pthread_create.c:463) ==30660== by 0x6DC888E: clone (clone.S:95) ==30660== Uninitialised value was created by a stack allocation ==30660== at 0x20173A: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:608) ==30660== { <insert_a_suppression_name_here> Memcheck:Cond fun:_ZL24rest_blockhash_by_heightRKN4util3RefEP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE fun:operator() fun:_ZNSt17_Function_handlerIFbP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEZ9StartRESTRKN4util3RefEE3$_1E9_M_invokeERKSt9_Any_dataOS1_S9_ fun:operator() fun:_ZN12HTTPWorkItemclEv fun:_ZN9WorkQueueI11HTTPClosureE3RunEv fun:_ZL16HTTPWorkQueueRunP9WorkQueueI11HTTPClosureEi fun:__invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:__invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:_M_invoke<0, 1, 2> fun:operator() fun:_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvP9WorkQueueI11HTTPClosureEiES6_iEEEEE6_M_runEv obj:/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 fun:start_thread fun:clone } ``` This is a known bad interaction between clang and valgrind. The clang optimized code is correct but valgrind has no way of knowing that accessing the uninitialized value isn't a problem. Issue has been reported previously: - https://bugs.llvm.org/show_bug.cgi?id=32604#c4 - Z3Prover/z3#972 This commit just sets blockheight to -1 as a workaround. This change was originally made in 41d5d65 from bitcoin#18740 to fix the travis error there (https://travis-ci.org/github/bitcoin/bitcoin/jobs/678453061#L7157) but MarcoFalke suggested bitcoin#18740 (comment) moving to a new PR, since apparently the error's been seen on travis previously ACKs for top commit: MarcoFalke: ACK fcb7261 practicalswift: ACK fcb7261 Tree-SHA512: ec8abf45bd3d6c6e0e7e404d0b2a749efd43910619b84b0b5fe7dab22881598d1011a0f3ff2e146bf46320b63eb152bf63c62c06f1ab84c35dd640abc468f18f
…h_by_height fcb7261 Prevent valgrind false positive in rest_blockhash_by_height (Russell Yanofsky) Pull request description: A bad interaction between valgrind and clang 6.0.0-1ubuntu2 with -O2 optimizations makes valgrind misleadingly imply C++ code is reading an uninitialized blockheight value in `rest_blockhash_by_height` just because that's what clang optimized code is doing. The C++ code looks like: ```c++ int32_t blockheight; if (!ParseInt32(height_str, &blockheight) || blockheight < 0) { ``` while the optimized code looks like: ``` 0x00000000000f97ab <+123>: callq 0x4f8860 <ParseInt32(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int*)> 0x00000000000f97b0 <+128>: mov 0xc(%rsp),%ebx 0x00000000000f97b4 <+132>: test %ebx,%ebx 0x00000000000f97b6 <+134>: js 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> 0x00000000000f97bc <+140>: xor $0x1,%al 0x00000000000f97be <+142>: jne 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> ``` During the rest_interface.py test: https://github.com/bitcoin/bitcoin/blob/eef90c14ed0f559e3f6e187341009270b84f45cb/test/functional/interface_rest.py#L266 when `height_str` is empty, `ParseInt32` returns false and `blockheight` value is never assigned. The optimized code reads the uninitialized `blockheight` value in `0xc(%rsp)` before the checking the `ParseInt32` return value in `%al`, which is harmless, but triggers the following error from valgrind: ``` ==30660== Thread 13 b-httpworker.2: ==30660== Conditional jump or move depends on uninitialised value(s) ==30660== at 0x2017B6: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:614) ==30660== by 0x2041B9: operator() (rest.cpp:670) ==30660== by 0x2041B9: std::_Function_handler<bool (HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&), StartREST(util::Ref const&)::$_1>::_M_invoke(std::_Any_data const&, HTTPRequest*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (std_function.h:301) ==30660== by 0x3EC994: operator() (std_function.h:706) ==30660== by 0x3EC994: HTTPWorkItem::operator()() (httpserver.cpp:55) ==30660== by 0x3ED16D: WorkQueue<HTTPClosure>::Run() (httpserver.cpp:114) ==30660== by 0x3E9168: HTTPWorkQueueRun(WorkQueue<HTTPClosure>*, int) (httpserver.cpp:342) ==30660== by 0x3EDAAA: __invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:60) ==30660== by 0x3EDAAA: __invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:95) ==30660== by 0x3EDAAA: _M_invoke<0, 1, 2> (thread:234) ==30660== by 0x3EDAAA: operator() (thread:243) ==30660== by 0x3EDAAA: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> > >::_M_run() (thread:186) ==30660== by 0x64256DE: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25) ==30660== by 0x54876DA: start_thread (pthread_create.c:463) ==30660== by 0x6DC888E: clone (clone.S:95) ==30660== Uninitialised value was created by a stack allocation ==30660== at 0x20173A: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:608) ==30660== { <insert_a_suppression_name_here> Memcheck:Cond fun:_ZL24rest_blockhash_by_heightRKN4util3RefEP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE fun:operator() fun:_ZNSt17_Function_handlerIFbP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEZ9StartRESTRKN4util3RefEE3$_1E9_M_invokeERKSt9_Any_dataOS1_S9_ fun:operator() fun:_ZN12HTTPWorkItemclEv fun:_ZN9WorkQueueI11HTTPClosureE3RunEv fun:_ZL16HTTPWorkQueueRunP9WorkQueueI11HTTPClosureEi fun:__invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:__invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:_M_invoke<0, 1, 2> fun:operator() fun:_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvP9WorkQueueI11HTTPClosureEiES6_iEEEEE6_M_runEv obj:/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 fun:start_thread fun:clone } ``` This is a known bad interaction between clang and valgrind. The clang optimized code is correct but valgrind has no way of knowing that accessing the uninitialized value isn't a problem. Issue has been reported previously: - https://bugs.llvm.org/show_bug.cgi?id=32604#c4 - Z3Prover/z3#972 This commit just sets blockheight to -1 as a workaround. This change was originally made in 41d5d65 from bitcoin#18740 to fix the travis error there (https://travis-ci.org/github/bitcoin/bitcoin/jobs/678453061#L7157) but MarcoFalke suggested bitcoin#18740 (comment) moving to a new PR, since apparently the error's been seen on travis previously ACKs for top commit: MarcoFalke: ACK fcb7261 practicalswift: ACK fcb7261 Tree-SHA512: ec8abf45bd3d6c6e0e7e404d0b2a749efd43910619b84b0b5fe7dab22881598d1011a0f3ff2e146bf46320b63eb152bf63c62c06f1ab84c35dd640abc468f18f
…h_by_height fcb7261 Prevent valgrind false positive in rest_blockhash_by_height (Russell Yanofsky) Pull request description: A bad interaction between valgrind and clang 6.0.0-1ubuntu2 with -O2 optimizations makes valgrind misleadingly imply C++ code is reading an uninitialized blockheight value in `rest_blockhash_by_height` just because that's what clang optimized code is doing. The C++ code looks like: ```c++ int32_t blockheight; if (!ParseInt32(height_str, &blockheight) || blockheight < 0) { ``` while the optimized code looks like: ``` 0x00000000000f97ab <+123>: callq 0x4f8860 <ParseInt32(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int*)> 0x00000000000f97b0 <+128>: mov 0xc(%rsp),%ebx 0x00000000000f97b4 <+132>: test %ebx,%ebx 0x00000000000f97b6 <+134>: js 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> 0x00000000000f97bc <+140>: xor $0x1,%al 0x00000000000f97be <+142>: jne 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> ``` During the rest_interface.py test: https://github.com/bitcoin/bitcoin/blob/eef90c14ed0f559e3f6e187341009270b84f45cb/test/functional/interface_rest.py#L266 when `height_str` is empty, `ParseInt32` returns false and `blockheight` value is never assigned. The optimized code reads the uninitialized `blockheight` value in `0xc(%rsp)` before the checking the `ParseInt32` return value in `%al`, which is harmless, but triggers the following error from valgrind: ``` ==30660== Thread 13 b-httpworker.2: ==30660== Conditional jump or move depends on uninitialised value(s) ==30660== at 0x2017B6: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:614) ==30660== by 0x2041B9: operator() (rest.cpp:670) ==30660== by 0x2041B9: std::_Function_handler<bool (HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&), StartREST(util::Ref const&)::$_1>::_M_invoke(std::_Any_data const&, HTTPRequest*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (std_function.h:301) ==30660== by 0x3EC994: operator() (std_function.h:706) ==30660== by 0x3EC994: HTTPWorkItem::operator()() (httpserver.cpp:55) ==30660== by 0x3ED16D: WorkQueue<HTTPClosure>::Run() (httpserver.cpp:114) ==30660== by 0x3E9168: HTTPWorkQueueRun(WorkQueue<HTTPClosure>*, int) (httpserver.cpp:342) ==30660== by 0x3EDAAA: __invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:60) ==30660== by 0x3EDAAA: __invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:95) ==30660== by 0x3EDAAA: _M_invoke<0, 1, 2> (thread:234) ==30660== by 0x3EDAAA: operator() (thread:243) ==30660== by 0x3EDAAA: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> > >::_M_run() (thread:186) ==30660== by 0x64256DE: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25) ==30660== by 0x54876DA: start_thread (pthread_create.c:463) ==30660== by 0x6DC888E: clone (clone.S:95) ==30660== Uninitialised value was created by a stack allocation ==30660== at 0x20173A: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:608) ==30660== { <insert_a_suppression_name_here> Memcheck:Cond fun:_ZL24rest_blockhash_by_heightRKN4util3RefEP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE fun:operator() fun:_ZNSt17_Function_handlerIFbP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEZ9StartRESTRKN4util3RefEE3$_1E9_M_invokeERKSt9_Any_dataOS1_S9_ fun:operator() fun:_ZN12HTTPWorkItemclEv fun:_ZN9WorkQueueI11HTTPClosureE3RunEv fun:_ZL16HTTPWorkQueueRunP9WorkQueueI11HTTPClosureEi fun:__invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:__invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:_M_invoke<0, 1, 2> fun:operator() fun:_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvP9WorkQueueI11HTTPClosureEiES6_iEEEEE6_M_runEv obj:/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 fun:start_thread fun:clone } ``` This is a known bad interaction between clang and valgrind. The clang optimized code is correct but valgrind has no way of knowing that accessing the uninitialized value isn't a problem. Issue has been reported previously: - https://bugs.llvm.org/show_bug.cgi?id=32604#c4 - Z3Prover/z3#972 This commit just sets blockheight to -1 as a workaround. This change was originally made in 41d5d65 from bitcoin#18740 to fix the travis error there (https://travis-ci.org/github/bitcoin/bitcoin/jobs/678453061#L7157) but MarcoFalke suggested bitcoin#18740 (comment) moving to a new PR, since apparently the error's been seen on travis previously ACKs for top commit: MarcoFalke: ACK fcb7261 practicalswift: ACK fcb7261 Tree-SHA512: ec8abf45bd3d6c6e0e7e404d0b2a749efd43910619b84b0b5fe7dab22881598d1011a0f3ff2e146bf46320b63eb152bf63c62c06f1ab84c35dd640abc468f18f
…h_by_height fcb7261 Prevent valgrind false positive in rest_blockhash_by_height (Russell Yanofsky) Pull request description: A bad interaction between valgrind and clang 6.0.0-1ubuntu2 with -O2 optimizations makes valgrind misleadingly imply C++ code is reading an uninitialized blockheight value in `rest_blockhash_by_height` just because that's what clang optimized code is doing. The C++ code looks like: ```c++ int32_t blockheight; if (!ParseInt32(height_str, &blockheight) || blockheight < 0) { ``` while the optimized code looks like: ``` 0x00000000000f97ab <+123>: callq 0x4f8860 <ParseInt32(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int*)> 0x00000000000f97b0 <+128>: mov 0xc(%rsp),%ebx 0x00000000000f97b4 <+132>: test %ebx,%ebx 0x00000000000f97b6 <+134>: js 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> 0x00000000000f97bc <+140>: xor $0x1,%al 0x00000000000f97be <+142>: jne 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> ``` During the rest_interface.py test: https://github.com/bitcoin/bitcoin/blob/eef90c14ed0f559e3f6e187341009270b84f45cb/test/functional/interface_rest.py#L266 when `height_str` is empty, `ParseInt32` returns false and `blockheight` value is never assigned. The optimized code reads the uninitialized `blockheight` value in `0xc(%rsp)` before the checking the `ParseInt32` return value in `%al`, which is harmless, but triggers the following error from valgrind: ``` ==30660== Thread 13 b-httpworker.2: ==30660== Conditional jump or move depends on uninitialised value(s) ==30660== at 0x2017B6: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:614) ==30660== by 0x2041B9: operator() (rest.cpp:670) ==30660== by 0x2041B9: std::_Function_handler<bool (HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&), StartREST(util::Ref const&)::$_1>::_M_invoke(std::_Any_data const&, HTTPRequest*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (std_function.h:301) ==30660== by 0x3EC994: operator() (std_function.h:706) ==30660== by 0x3EC994: HTTPWorkItem::operator()() (httpserver.cpp:55) ==30660== by 0x3ED16D: WorkQueue<HTTPClosure>::Run() (httpserver.cpp:114) ==30660== by 0x3E9168: HTTPWorkQueueRun(WorkQueue<HTTPClosure>*, int) (httpserver.cpp:342) ==30660== by 0x3EDAAA: __invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:60) ==30660== by 0x3EDAAA: __invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:95) ==30660== by 0x3EDAAA: _M_invoke<0, 1, 2> (thread:234) ==30660== by 0x3EDAAA: operator() (thread:243) ==30660== by 0x3EDAAA: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> > >::_M_run() (thread:186) ==30660== by 0x64256DE: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25) ==30660== by 0x54876DA: start_thread (pthread_create.c:463) ==30660== by 0x6DC888E: clone (clone.S:95) ==30660== Uninitialised value was created by a stack allocation ==30660== at 0x20173A: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:608) ==30660== { <insert_a_suppression_name_here> Memcheck:Cond fun:_ZL24rest_blockhash_by_heightRKN4util3RefEP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE fun:operator() fun:_ZNSt17_Function_handlerIFbP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEZ9StartRESTRKN4util3RefEE3$_1E9_M_invokeERKSt9_Any_dataOS1_S9_ fun:operator() fun:_ZN12HTTPWorkItemclEv fun:_ZN9WorkQueueI11HTTPClosureE3RunEv fun:_ZL16HTTPWorkQueueRunP9WorkQueueI11HTTPClosureEi fun:__invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:__invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:_M_invoke<0, 1, 2> fun:operator() fun:_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvP9WorkQueueI11HTTPClosureEiES6_iEEEEE6_M_runEv obj:/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 fun:start_thread fun:clone } ``` This is a known bad interaction between clang and valgrind. The clang optimized code is correct but valgrind has no way of knowing that accessing the uninitialized value isn't a problem. Issue has been reported previously: - https://bugs.llvm.org/show_bug.cgi?id=32604#c4 - Z3Prover/z3#972 This commit just sets blockheight to -1 as a workaround. This change was originally made in 41d5d65 from bitcoin#18740 to fix the travis error there (https://travis-ci.org/github/bitcoin/bitcoin/jobs/678453061#L7157) but MarcoFalke suggested bitcoin#18740 (comment) moving to a new PR, since apparently the error's been seen on travis previously ACKs for top commit: MarcoFalke: ACK fcb7261 practicalswift: ACK fcb7261 Tree-SHA512: ec8abf45bd3d6c6e0e7e404d0b2a749efd43910619b84b0b5fe7dab22881598d1011a0f3ff2e146bf46320b63eb152bf63c62c06f1ab84c35dd640abc468f18f
…h_by_height fcb7261 Prevent valgrind false positive in rest_blockhash_by_height (Russell Yanofsky) Pull request description: A bad interaction between valgrind and clang 6.0.0-1ubuntu2 with -O2 optimizations makes valgrind misleadingly imply C++ code is reading an uninitialized blockheight value in `rest_blockhash_by_height` just because that's what clang optimized code is doing. The C++ code looks like: ```c++ int32_t blockheight; if (!ParseInt32(height_str, &blockheight) || blockheight < 0) { ``` while the optimized code looks like: ``` 0x00000000000f97ab <+123>: callq 0x4f8860 <ParseInt32(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int*)> 0x00000000000f97b0 <+128>: mov 0xc(%rsp),%ebx 0x00000000000f97b4 <+132>: test %ebx,%ebx 0x00000000000f97b6 <+134>: js 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> 0x00000000000f97bc <+140>: xor $0x1,%al 0x00000000000f97be <+142>: jne 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> ``` During the rest_interface.py test: https://github.com/bitcoin/bitcoin/blob/eef90c14ed0f559e3f6e187341009270b84f45cb/test/functional/interface_rest.py#L266 when `height_str` is empty, `ParseInt32` returns false and `blockheight` value is never assigned. The optimized code reads the uninitialized `blockheight` value in `0xc(%rsp)` before the checking the `ParseInt32` return value in `%al`, which is harmless, but triggers the following error from valgrind: ``` ==30660== Thread 13 b-httpworker.2: ==30660== Conditional jump or move depends on uninitialised value(s) ==30660== at 0x2017B6: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:614) ==30660== by 0x2041B9: operator() (rest.cpp:670) ==30660== by 0x2041B9: std::_Function_handler<bool (HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&), StartREST(util::Ref const&)::$_1>::_M_invoke(std::_Any_data const&, HTTPRequest*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (std_function.h:301) ==30660== by 0x3EC994: operator() (std_function.h:706) ==30660== by 0x3EC994: HTTPWorkItem::operator()() (httpserver.cpp:55) ==30660== by 0x3ED16D: WorkQueue<HTTPClosure>::Run() (httpserver.cpp:114) ==30660== by 0x3E9168: HTTPWorkQueueRun(WorkQueue<HTTPClosure>*, int) (httpserver.cpp:342) ==30660== by 0x3EDAAA: __invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:60) ==30660== by 0x3EDAAA: __invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:95) ==30660== by 0x3EDAAA: _M_invoke<0, 1, 2> (thread:234) ==30660== by 0x3EDAAA: operator() (thread:243) ==30660== by 0x3EDAAA: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> > >::_M_run() (thread:186) ==30660== by 0x64256DE: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25) ==30660== by 0x54876DA: start_thread (pthread_create.c:463) ==30660== by 0x6DC888E: clone (clone.S:95) ==30660== Uninitialised value was created by a stack allocation ==30660== at 0x20173A: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:608) ==30660== { <insert_a_suppression_name_here> Memcheck:Cond fun:_ZL24rest_blockhash_by_heightRKN4util3RefEP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE fun:operator() fun:_ZNSt17_Function_handlerIFbP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEZ9StartRESTRKN4util3RefEE3$_1E9_M_invokeERKSt9_Any_dataOS1_S9_ fun:operator() fun:_ZN12HTTPWorkItemclEv fun:_ZN9WorkQueueI11HTTPClosureE3RunEv fun:_ZL16HTTPWorkQueueRunP9WorkQueueI11HTTPClosureEi fun:__invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:__invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:_M_invoke<0, 1, 2> fun:operator() fun:_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvP9WorkQueueI11HTTPClosureEiES6_iEEEEE6_M_runEv obj:/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 fun:start_thread fun:clone } ``` This is a known bad interaction between clang and valgrind. The clang optimized code is correct but valgrind has no way of knowing that accessing the uninitialized value isn't a problem. Issue has been reported previously: - https://bugs.llvm.org/show_bug.cgi?id=32604#c4 - Z3Prover/z3#972 This commit just sets blockheight to -1 as a workaround. This change was originally made in 41d5d65 from bitcoin#18740 to fix the travis error there (https://travis-ci.org/github/bitcoin/bitcoin/jobs/678453061#L7157) but MarcoFalke suggested bitcoin#18740 (comment) moving to a new PR, since apparently the error's been seen on travis previously ACKs for top commit: MarcoFalke: ACK fcb7261 practicalswift: ACK fcb7261 Tree-SHA512: ec8abf45bd3d6c6e0e7e404d0b2a749efd43910619b84b0b5fe7dab22881598d1011a0f3ff2e146bf46320b63eb152bf63c62c06f1ab84c35dd640abc468f18f
…h_by_height fcb7261 Prevent valgrind false positive in rest_blockhash_by_height (Russell Yanofsky) Pull request description: A bad interaction between valgrind and clang 6.0.0-1ubuntu2 with -O2 optimizations makes valgrind misleadingly imply C++ code is reading an uninitialized blockheight value in `rest_blockhash_by_height` just because that's what clang optimized code is doing. The C++ code looks like: ```c++ int32_t blockheight; if (!ParseInt32(height_str, &blockheight) || blockheight < 0) { ``` while the optimized code looks like: ``` 0x00000000000f97ab <+123>: callq 0x4f8860 <ParseInt32(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int*)> 0x00000000000f97b0 <+128>: mov 0xc(%rsp),%ebx 0x00000000000f97b4 <+132>: test %ebx,%ebx 0x00000000000f97b6 <+134>: js 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> 0x00000000000f97bc <+140>: xor $0x1,%al 0x00000000000f97be <+142>: jne 0xf98aa <rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+378> ``` During the rest_interface.py test: https://github.com/bitcoin/bitcoin/blob/eef90c14ed0f559e3f6e187341009270b84f45cb/test/functional/interface_rest.py#L266 when `height_str` is empty, `ParseInt32` returns false and `blockheight` value is never assigned. The optimized code reads the uninitialized `blockheight` value in `0xc(%rsp)` before the checking the `ParseInt32` return value in `%al`, which is harmless, but triggers the following error from valgrind: ``` ==30660== Thread 13 b-httpworker.2: ==30660== Conditional jump or move depends on uninitialised value(s) ==30660== at 0x2017B6: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:614) ==30660== by 0x2041B9: operator() (rest.cpp:670) ==30660== by 0x2041B9: std::_Function_handler<bool (HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&), StartREST(util::Ref const&)::$_1>::_M_invoke(std::_Any_data const&, HTTPRequest*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (std_function.h:301) ==30660== by 0x3EC994: operator() (std_function.h:706) ==30660== by 0x3EC994: HTTPWorkItem::operator()() (httpserver.cpp:55) ==30660== by 0x3ED16D: WorkQueue<HTTPClosure>::Run() (httpserver.cpp:114) ==30660== by 0x3E9168: HTTPWorkQueueRun(WorkQueue<HTTPClosure>*, int) (httpserver.cpp:342) ==30660== by 0x3EDAAA: __invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:60) ==30660== by 0x3EDAAA: __invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> (invoke.h:95) ==30660== by 0x3EDAAA: _M_invoke<0, 1, 2> (thread:234) ==30660== by 0x3EDAAA: operator() (thread:243) ==30660== by 0x3EDAAA: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> > >::_M_run() (thread:186) ==30660== by 0x64256DE: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25) ==30660== by 0x54876DA: start_thread (pthread_create.c:463) ==30660== by 0x6DC888E: clone (clone.S:95) ==30660== Uninitialised value was created by a stack allocation ==30660== at 0x20173A: rest_blockhash_by_height(util::Ref const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (rest.cpp:608) ==30660== { <insert_a_suppression_name_here> Memcheck:Cond fun:_ZL24rest_blockhash_by_heightRKN4util3RefEP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE fun:operator() fun:_ZNSt17_Function_handlerIFbP11HTTPRequestRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEZ9StartRESTRKN4util3RefEE3$_1E9_M_invokeERKSt9_Any_dataOS1_S9_ fun:operator() fun:_ZN12HTTPWorkItemclEv fun:_ZN9WorkQueueI11HTTPClosureE3RunEv fun:_ZL16HTTPWorkQueueRunP9WorkQueueI11HTTPClosureEi fun:__invoke_impl<void, void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:__invoke<void (*)(WorkQueue<HTTPClosure> *, int), WorkQueue<HTTPClosure> *, int> fun:_M_invoke<0, 1, 2> fun:operator() fun:_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvP9WorkQueueI11HTTPClosureEiES6_iEEEEE6_M_runEv obj:/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25 fun:start_thread fun:clone } ``` This is a known bad interaction between clang and valgrind. The clang optimized code is correct but valgrind has no way of knowing that accessing the uninitialized value isn't a problem. Issue has been reported previously: - https://bugs.llvm.org/show_bug.cgi?id=32604#c4 - Z3Prover/z3#972 This commit just sets blockheight to -1 as a workaround. This change was originally made in 41d5d65 from bitcoin#18740 to fix the travis error there (https://travis-ci.org/github/bitcoin/bitcoin/jobs/678453061#L7157) but MarcoFalke suggested bitcoin#18740 (comment) moving to a new PR, since apparently the error's been seen on travis previously ACKs for top commit: MarcoFalke: ACK fcb7261 practicalswift: ACK fcb7261 Tree-SHA512: ec8abf45bd3d6c6e0e7e404d0b2a749efd43910619b84b0b5fe7dab22881598d1011a0f3ff2e146bf46320b63eb152bf63c62c06f1ab84c35dd640abc468f18f
A bad interaction between valgrind and clang 6.0.0-1ubuntu2 with -O2 optimizations makes valgrind misleadingly imply C++ code is reading an uninitialized blockheight value in
rest_blockhash_by_height
just because that's what clang optimized code is doing. The C++ code looks like:while the optimized code looks like:
During the rest_interface.py test:
bitcoin/test/functional/interface_rest.py
Line 266 in eef90c1
when
height_str
is empty,ParseInt32
returns false andblockheight
value is never assigned. The optimized code reads the uninitializedblockheight
value in0xc(%rsp)
before the checking theParseInt32
return value in%al
, which is harmless, but triggers the following error from valgrind:This is a known bad interaction between clang and valgrind. The clang optimized code is correct but valgrind has no way of knowing that accessing the uninitialized value isn't a problem. Issue has been reported previously:
This commit just sets blockheight to -1 as a workaround.
This change was originally made in 41d5d65 from #18740 to fix the travis error there (https://travis-ci.org/github/bitcoin/bitcoin/jobs/678453061#L7157) but MarcoFalke suggested #18740 (comment) moving to a new PR, since apparently the error's been seen on travis previously