Fix potential race-condition in reference scanning code

Previously the code ensures that the isBase32 array would only be
initialised once in a single-threaded context. If two threads happen to
call the function before the initialisation was completed both of them
would have completed the initialization step. This allowed for a
race-condition where one thread might be done with the initialization
but the other thread sets all the fields to false again. For a brief
moment the base32 detection would then produce false-negatives.
This commit is contained in:
Andreas Rammhold 2021-08-07 19:10:25 +02:00
parent 2b67cb7b8c
commit b2d3976163

View file

@ -5,6 +5,7 @@
#include <map> #include <map>
#include <cstdlib> #include <cstdlib>
#include <mutex>
namespace nix { namespace nix {
@ -16,14 +17,13 @@ static unsigned int refLength = 32; /* characters */
static void search(const unsigned char * s, size_t len, static void search(const unsigned char * s, size_t len,
StringSet & hashes, StringSet & seen) StringSet & hashes, StringSet & seen)
{ {
static bool initialised = false; static std::once_flag initialised;
static bool isBase32[256]; static bool isBase32[256];
if (!initialised) { std::call_once(initialised, [](){
for (unsigned int i = 0; i < 256; ++i) isBase32[i] = false; for (unsigned int i = 0; i < 256; ++i) isBase32[i] = false;
for (unsigned int i = 0; i < base32Chars.size(); ++i) for (unsigned int i = 0; i < base32Chars.size(); ++i)
isBase32[(unsigned char) base32Chars[i]] = true; isBase32[(unsigned char) base32Chars[i]] = true;
initialised = true; });
}
for (size_t i = 0; i + refLength <= len; ) { for (size_t i = 0; i + refLength <= len; ) {
int j; int j;