Skip to content

Commit 9cb000f

Browse files
improve thread safety for concurrent tiff loads (#3767)
* Make lookups of const unordered_maps thread-safe * added back deleted end brace * clang-format --------- Co-authored-by: Larry Gritz <[email protected]>
1 parent 86aea43 commit 9cb000f

File tree

1 file changed

+49
-21
lines changed

1 file changed

+49
-21
lines changed

src/libOpenImageIO/icc.cpp

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -105,22 +105,30 @@ struct ICCTag {
105105
static const char*
106106
icc_device_class_name(const std::string& device_class)
107107
{
108-
static std::unordered_map<std::string, const char*> device_class_names = {
109-
{ "scnr", "Input device profile" },
110-
{ "mntr", "Display device profile" },
111-
{ "prtr", "Output device profile" },
112-
{ "link", "DeviceLink profile" },
113-
{ "spac", "ColorSpace profile" },
114-
{ "abst", "Abstract profile" },
115-
{ "nmcl", "NamedColor profile" },
116-
};
117-
return device_class_names[device_class];
108+
static const std::unordered_map<std::string, const char*> device_class_names
109+
= {
110+
{ "scnr", "Input device profile" },
111+
{ "mntr", "Display device profile" },
112+
{ "prtr", "Output device profile" },
113+
{ "link", "DeviceLink profile" },
114+
{ "spac", "ColorSpace profile" },
115+
{ "abst", "Abstract profile" },
116+
{ "nmcl", "NamedColor profile" },
117+
};
118+
// std::unordered_map::operator[](const Key& key) will add the key to the map if
119+
// it doesn't exist. This isn't what is intended and isn't thread safe.
120+
// Instead, just do the lookup and return the value or a nullptr.
121+
//
122+
// return device_class_names[device_class];
123+
auto it = device_class_names.find(device_class);
124+
return (it != device_class_names.end()) ? it->second : nullptr;
118125
}
119126

120127
static const char*
121128
icc_color_space_name(string_view color_space)
122129
{
123-
static std::unordered_map<std::string, const char*> color_space_names = {
130+
// clang-format off
131+
static const std::unordered_map<std::string, const char*> color_space_names = {
124132
{ "XYZ ", "XYZ" }, { "Lab ", "CIELAB" }, { "Luv ", "CIELUV" },
125133
{ "YCbr", "YCbCr" }, { "Yxy ", "CIEYxy" }, { "RGB ", "RGB" },
126134
{ "GRAY", "Gray" }, { "HSV ", "HSV" }, { "HLS ", "HLS" },
@@ -131,19 +139,33 @@ icc_color_space_name(string_view color_space)
131139
{ "BCLR", "12 color" }, { "CCLR", "13 color" }, { "DCLR", "14 color" },
132140
{ "ECLR", "15 color" }, { "FCLR", "16 color" },
133141
};
134-
return color_space_names[color_space];
142+
// clang-format on
143+
// std::unordered_map::operator[](const Key& key) will add the key to the map if
144+
// it doesn't exist. This isn't what is intended and isn't thread safe.
145+
// Instead, just do the lookup and return the value or a nullptr.
146+
//
147+
// return color_space_names[color_space];
148+
auto it = color_space_names.find(color_space);
149+
return (it != color_space_names.end()) ? it->second : nullptr;
135150
}
136151

137152
static const char*
138153
icc_primary_platform_name(const std::string& platform)
139154
{
140-
static std::unordered_map<std::string, const char*> primary_platforms = {
141-
{ "APPL", "Apple Computer, Inc." },
142-
{ "MSFT", "Microsoft Corporation" },
143-
{ "SGI ", "Silicon Graphics, Inc." },
144-
{ "SUNW", "Sun Microsystems, Inc." },
145-
};
146-
return primary_platforms[platform];
155+
static const std::unordered_map<std::string, const char*> primary_platforms
156+
= {
157+
{ "APPL", "Apple Computer, Inc." },
158+
{ "MSFT", "Microsoft Corporation" },
159+
{ "SGI ", "Silicon Graphics, Inc." },
160+
{ "SUNW", "Sun Microsystems, Inc." },
161+
};
162+
// std::unordered_map::operator[](const Key& key) will add the key to the map if
163+
// it doesn't exist. This isn't what is intended and isn't thread safe.
164+
// Instead, just do the lookup and return the value or a nullptr.
165+
//
166+
// return primary_platforms[platform];
167+
auto it = primary_platforms.find(platform);
168+
return (it != primary_platforms.end()) ? it->second : nullptr;
147169
}
148170

149171
static const char*
@@ -158,15 +180,21 @@ icc_rendering_intent_name(uint32_t intent)
158180
static std::string
159181
icc_tag_name(const std::string& tag)
160182
{
161-
static std::unordered_map<std::string, std::string> tagnames = {
183+
static const std::unordered_map<std::string, std::string> tagnames = {
162184
{ "targ", "characterization_target" },
163185
{ "cprt", "copyright" },
164186
{ "desc", "profile_description" },
165187
{ "dmdd", "device_model_description" },
166188
{ "dmnd", "device_manufacturer_description" },
167189
{ "vued", "viewing_conditions_description" },
168190
};
169-
return tagnames[tag];
191+
// std::unordered_map::operator[](const Key& key) will add the key to the map if
192+
// it doesn't exist. This isn't what is intended and isn't thread safe.
193+
// Instead, just do the lookup and return the value or an empty string.
194+
//
195+
//return tagnames[tag];
196+
auto it = tagnames.find(tag);
197+
return (it != tagnames.end()) ? it->second : std::string();
170198
}
171199

172200

0 commit comments

Comments
 (0)