From 8068d0153f592d9054e8f49ac7ba5e1e72cd4ce4 Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 15 Sep 2022 23:22:55 +0200 Subject: [PATCH] Initialize reserved names once to avoid race condition CanOptimizeCallback::isReservedName function may be executed by multiple threads simultaneously. One of them creates a static but both of them run if statement and see it's empty because none of them added elements there yet. Both of them go to the branch where new elements are added doing it without any synchronization possibly causing SIGSEGV. --- CHANGELOG.md | 1 + components/resource/scenemanager.cpp | 79 ++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1b8ff1f91..d5641fd18c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -179,6 +179,7 @@ Bug #6913: Constant effect enchanted items don't break invisibility Bug #6923: Dispose of corpse prevents respawning after load Bug #6937: Divided by Nix Hounds quest is broken + Bug #7008: Race condition on initializing a vector of reserved node names Feature #890: OpenMW-CS: Column filtering Feature #1465: "Reset" argument for AI functions Feature #2491: Ability to make OpenMW "portable" diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 63319840bd..610aa6b506 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -619,6 +619,67 @@ namespace Resource return node; } + + std::vector makeSortedReservedNames() + { + static constexpr std::string_view names[] = { + "Head", + "Neck", + "Chest", + "Groin", + "Right Hand", + "Left Hand", + "Right Wrist", + "Left Wrist", + "Shield Bone", + "Right Forearm", + "Left Forearm", + "Right Upper Arm", + "Left Upper Arm", + "Right Foot", + "Left Foot", + "Right Ankle", + "Left Ankle", + "Right Knee", + "Left Knee", + "Right Upper Leg", + "Left Upper Leg", + "Right Clavicle", + "Left Clavicle", + "Weapon Bone", + "Tail", + "Bip01", + "Root Bone", + "BoneOffset", + "AttachLight", + "Arrow", + "Camera", + "Collision", + "Right_Wrist", + "Left_Wrist", + "Shield_Bone", + "Right_Forearm", + "Left_Forearm", + "Right_Upper_Arm", + "Left_Clavicle", + "Weapon_Bone", + "Root_Bone", + }; + + std::vector result; + result.reserve(std::size(names)); + + for (std::string_view name : names) + { + std::string prefixedName("Tri "); + prefixedName += name; + result.push_back(std::move(prefixedName)); + } + + std::sort(result.begin(), result.end(), Misc::StringUtils::ciLess); + + return result; + } } osg::ref_ptr load (const std::string& normalizedFilename, const VFS::Manager* vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) @@ -638,23 +699,9 @@ namespace Resource if (name.empty()) return false; - static std::vector reservedNames; - if (reservedNames.empty()) - { - const char* reserved[] = {"Head", "Neck", "Chest", "Groin", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", "Shield Bone", "Right Forearm", "Left Forearm", "Right Upper Arm", - "Left Upper Arm", "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", "Left Knee", "Right Upper Leg", "Left Upper Leg", "Right Clavicle", - "Left Clavicle", "Weapon Bone", "Tail", "Bip01", "Root Bone", "BoneOffset", "AttachLight", "Arrow", "Camera", "Collision", "Right_Wrist", "Left_Wrist", - "Shield_Bone", "Right_Forearm", "Left_Forearm", "Right_Upper_Arm", "Left_Clavicle", "Weapon_Bone", "Root_Bone"}; - - reservedNames = std::vector(reserved, reserved + sizeof(reserved)/sizeof(reserved[0])); - - for (unsigned int i=0; i reservedNames = makeSortedReservedNames(); - std::vector::iterator it = Misc::partialBinarySearch(reservedNames.begin(), reservedNames.end(), name); + const auto it = Misc::partialBinarySearch(reservedNames.begin(), reservedNames.end(), name); return it != reservedNames.end(); }