-
Notifications
You must be signed in to change notification settings - Fork 37.8k
Add copy constructor and copy operator= to CScript to remove ubsan suppression #17510
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
@@ -412,6 +412,9 @@ class CScript : public CScriptBase | |||
CScript(std::vector<unsigned char>::const_iterator pbegin, std::vector<unsigned char>::const_iterator pend) : CScriptBase(pbegin, pend) { } | |||
CScript(const unsigned char* pbegin, const unsigned char* pend) : CScriptBase(pbegin, pend) { } | |||
|
|||
// Define a copy constructor so that operator= is a copy instead of a move to avoid undefined behavior |
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.
If this is needed, there is another problem. Why does a move cause UB? And why is a move being invoked in the first place with operator=?
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.
No idea. Maybe @practicalswift can shed some light here?
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.
See also: #17156 (comment)
For reference, one tb is this:
|
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. |
Agree. This is kind of scary, and working around it like this seems a bad idea if we don't understand why it happens. |
Could this pragma in prevector.h be causing alignment issues? (doesn't it mean something like "ignore all padding requirements within the struct")
|
Smaller code to reproduce: struct Test {
uint8_t a : 8;
CScript script;
};
{
const std::array<unsigned char, 5> D{1, 2, 3, 4, 5};
Test t{0x0f, {}};
t.script = CScript{D.begin(), D.end()};
} Result:
|
Does it go away if you remove the pragma? |
Yes, with this diff it goes away: diff --git a/src/prevector.h b/src/prevector.h
index d307495fbe..a55bcb50fe 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -14,7 +14,6 @@
#include <cstddef>
#include <type_traits>
-#pragma pack(push, 1)
/** Implements a drop-in replacement for std::vector<T> which stores up to N
* elements directly (without heap allocation). The types Size and Diff are
* used to store element counts, and can be any unsigned + signed type.
@@ -522,6 +521,5 @@ public:
return item_ptr(0);
}
};
-#pragma pack(pop)
#endif // BITCOIN_PREVECTOR_H |
I would prefer that solution, then. I'm not sure in how far unaligned integers are really UB in C++ (versus architecture/implementation defined), but it'd be better to avoid that for architectures that don't support (or have slow fallback paths for) unaligned reads/writes. (E.g. SiFive U540 traps into the kernel/bootloader to handle unaligned reads and writes, with a function, in software. Wouldn't be surprised if it's 1000 times slower) |
@laanwj John Regehr and Pascal Cuoq's excellent post "Undefined Behavior in 2017" has a nice section on Alignment Violations. Highly recommended reading! |
`#pragma pack(1)` prevents aligning the struct and its members to their required alignment. This can result in code that performs non-aligned reads and writes to integers and pointers, which is problematic on some architectures. It also triggers UBsan — see bitcoin#17156 (comment) and bitcoin#17510.
`#pragma pack(1)` prevents aligning the struct and its members to their required alignment. This can result in code that performs non-aligned reads and writes to integers and pointers, which is problematic on some architectures. It also triggers UBsan — see bitcoin#17156 (comment) and bitcoin#17510.
`#pragma pack(1)` prevents aligning the struct and its members to their required alignment. This can result in code that performs non-aligned reads and writes to integers and pointers, which is problematic on some architectures. It also triggers UBsan — see bitcoin#17156 (comment) and bitcoin#17510.
`#pragma pack(1)` prevents aligning the struct and its members to their required alignment. This can result in code that performs non-aligned reads and writes to integers and pointers, which is problematic on some architectures. It also triggers UBsan — see bitcoin/bitcoin#17156 (comment) and #17510.
As noted in #17156 (comment), the PSBT fuzzer is triggering a UBSan condition which is fixed by this PR. Additionally, by fixing this, some UBSan suppressions can be removed.
Split from #17156