From 3bdd15e55e58871181b16e5ede268a1f14e93178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarkko=20P=C3=B6yry?= Date: Tue, 10 Jan 2017 23:20:05 +0200 Subject: [PATCH] Make mode descriptor cache initialization thread-safe. Initializing mode descriptor cache in-place is racy and may cause a thread to observe a partially constructed cache if another thread is pre-empted while it's still constructing the cache. In this change, the mode descriptor cache is constructed into a local variable instead and then set globally in a single atomic operation, preventing any possibility of observing an incomplete cache. --- PIL/ImageMode.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/PIL/ImageMode.py b/PIL/ImageMode.py index f78a8df90..93dbeab41 100644 --- a/PIL/ImageMode.py +++ b/PIL/ImageMode.py @@ -14,7 +14,7 @@ # # mode descriptor cache -_modes = {} +_modes = None class ModeDescriptor(object): @@ -32,19 +32,23 @@ class ModeDescriptor(object): def getmode(mode): """Gets a mode descriptor for the given mode.""" + global _modes if not _modes: # initialize mode cache from PIL import Image + modes = {} # core modes for m, (basemode, basetype, bands) in Image._MODEINFO.items(): - _modes[m] = ModeDescriptor(m, bands, basemode, basetype) + modes[m] = ModeDescriptor(m, bands, basemode, basetype) # extra experimental modes - _modes["RGBa"] = ModeDescriptor("RGBa", ("R", "G", "B", "a"), "RGB", "L") - _modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L") - _modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L") - _modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L") + modes["RGBa"] = ModeDescriptor("RGBa", ("R", "G", "B", "a"), "RGB", "L") + modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L") + modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L") + modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L") # mapping modes - _modes["I;16"] = ModeDescriptor("I;16", "I", "L", "L") - _modes["I;16L"] = ModeDescriptor("I;16L", "I", "L", "L") - _modes["I;16B"] = ModeDescriptor("I;16B", "I", "L", "L") + modes["I;16"] = ModeDescriptor("I;16", "I", "L", "L") + modes["I;16L"] = ModeDescriptor("I;16L", "I", "L", "L") + modes["I;16B"] = ModeDescriptor("I;16B", "I", "L", "L") + # set global mode cache atomically + _modes = modes return _modes[mode]