-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Make CTransaction(const CMutableTransaction &tx) explicit #5054
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
Can you explain why? |
The implicit casting can cause hard to find segmentation faults. Any function or method (including constructors) that takes a CTransaction (or a reference to it) as parameter will create a temporary instance using the implicit constructor from a CMutableTransaction. That instance is only in memory during the execution of the function and gets destroyed just after it. Any later access to a reference of the temporary CTransaction should raise an unauthorized memory access exception.
jtimon@dfd5c6d#diff-b81dfdd8a5bd80fe9f82b5a40c4c991eR45 The auxiliary variable and constructor could be eliminated if there was a guarantee that the Constructor will always be called with a CTransaction& and never a CMutationCTransaction that gets implicitly copied to a temporary CTransaction. That guarantee can be achieved with the "explicit" keyword. |
Indeed, the parameter will create a temporary instance using the implicit constructor. It will have the scope of the current statement only. Isn't the root issue then that some functions assume that a const reference that is passed has a longer validity than the function call? Not the implicit conversion itself? Ie if a function takes a IMO if the goal is to pass a longer-living structure, I don't think references are the right thing to use. Using a pointer will avoid any implicit conversions, and documents that something potentially dangerous is going on (and you need reference counting, or ownership transfer, or at least make it clear what the scope is). Or if acceptable, just make a copy. |
What you say makes sense, but creating an additional copy has some cost that I would like to save when it's not necessary. Maybe this only makes sense after #4989. |
So use a pointer, then. I think no matter what, assuming that a reference that is passed to a function outlives that function is wrong. |
I tried to do it with pointers and castings instead of implicit constructors but the tests keep failing " memory access violation" We could make all constructors with a single parameter explicit. We could even make that a style rule. If we did, when we "assume that a reference that is passed to a function outlives that function" either by mistake or due to a conscientious decision based purely on performance (and no, just like performance is not always more important than appropriate semantics, style is not always more important than performance). And although in my preferred language "explicit is better than implicit", I don't think it's fair to blame C++ in this case when it provides a specific keyword to avoid the explosions. But if you don't mind, I will keep this open for now to hear more feedback. |
I am not blaming C++. I'm just saying that temporaries are something to be expected if you use (const) references. You can try to change the world around it, or just accept it and use a style that is not conductive to a kind of error. Even if you make sure that all constructors in bitcoin core itself are explicit, there could still be an implicit conversion through boost, or the standard library (like the std::string/const char* I mention above). (to be clear: there are very good reasons for making constructors explicit, for example if the goal of the constructor is not to convert between types, or when the constructor does something unsafe to the object passed in. But |
Avoiding a copy is probably always an optimization. Your rule of simply not using constructors that use a const ref and expect it to remain in memory makes a lot of sense to me. |
These implicit castings are dangerous. They exploded in my face several times when coding #4989 . I'll post a version of that PR rebased on top of this one that will be slightly more memory efficient (I'll be able to remove txAux attribute and the constructor using CMutableTransaction).