Merge bitcoin/bitcoin#22875: util: Fix Racy ParseOpCode function initialization

7b481f015a Fix Racy ParseOpCode function initialization (Jeremy Rubin)

Pull request description:

  If multiple callers call ParseOpCode concurrently it will cause a race condition. We can either move the static to it's own area and require init be called explicitly, or just allow concurrent first callers to race to fill in an atomic variable that never changes thereafter. The second approach is taken here.

  Static initialization *is* threadsafe, but only insofar as definining the variable being guaranteed to be called once. This is used incorrectly here.

  practicalswift --> are there tools we can deploy to catch usage like this?

ACKs for top commit:
  MarcoFalke:
    re-ACK 7b481f015a 🗣

Tree-SHA512: cbf9dc3af26d7335305026f32ce8472a018309b89b3d81a67357e59fbeed72c37b5b8a6e30325ea68145c3b2403867be82de01f22decefb6e6717cf0c0045633
This commit is contained in:
MarcoFalke 2021-12-24 10:02:53 +01:00
commit dada92fed2
No known key found for this signature in database
GPG Key ID: CE2B75697E69A548

View File

@ -21,13 +21,15 @@
#include <string>
namespace {
opcodetype ParseOpCode(const std::string& s)
class OpCodeParser
{
static std::map<std::string, opcodetype> mapOpNames;
private:
std::map<std::string, opcodetype> mapOpNames;
if (mapOpNames.empty()) {
for (unsigned int op = 0; op <= MAX_OPCODE; op++) {
public:
OpCodeParser()
{
for (unsigned int op = 0; op <= MAX_OPCODE; ++op) {
// Allow OP_RESERVED to get into mapOpNames
if (op < OP_NOP && op != OP_RESERVED) {
continue;
@ -44,10 +46,18 @@ opcodetype ParseOpCode(const std::string& s)
}
}
}
opcodetype Parse(const std::string& s) const
{
auto it = mapOpNames.find(s);
if (it == mapOpNames.end()) throw std::runtime_error("script parse error: unknown opcode");
return it->second;
}
};
auto it = mapOpNames.find(s);
if (it == mapOpNames.end()) throw std::runtime_error("script parse error: unknown opcode");
return it->second;
opcodetype ParseOpCode(const std::string& s)
{
static const OpCodeParser ocp;
return ocp.Parse(s);
}
} // namespace