serialize the access to mutable shared state in System.IO.Packaging (#56367)
authorAdam Sitnik <adam.sitnik@gmail.com>
Tue, 27 Jul 2021 16:10:34 +0000 (18:10 +0200)
committerGitHub <noreply@github.com>
Tue, 27 Jul 2021 16:10:34 +0000 (18:10 +0200)
src/libraries/System.IO.Packaging/src/System.IO.Packaging.csproj
src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackageXmlStringTable.cs

index abb1858..c9a5e30 100644 (file)
@@ -48,6 +48,7 @@
     <Reference Include="System.IO.Compression" />
     <Reference Include="System.Runtime" />
     <Reference Include="System.Xml.ReaderWriter" />
+    <Reference Include="System.Threading" />
   </ItemGroup>
 
   <ItemGroup Condition="'$(TargetFramework)' == 'net461'">
index cf76091..2b1ca4d 100644 (file)
@@ -12,63 +12,63 @@ namespace System.IO.Packaging
     internal static class PackageXmlStringTable
     {
         // Fields
-        private static readonly NameTable s_nameTable = new NameTable();
+        private static readonly ThreadSafeNameTable s_nameTable = new ThreadSafeNameTable();
         private static readonly XmlStringTableStruct[] s_xmlstringtable = new XmlStringTableStruct[0x1b];
 
         // Methods
         static PackageXmlStringTable()
         {
-            object nameString = s_nameTable.Add("http://www.w3.org/2001/XMLSchema-instance");
+            object nameString = s_nameTable.AddNoLock("http://www.w3.org/2001/XMLSchema-instance");
             s_xmlstringtable[1] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
-            nameString = s_nameTable.Add("xsi");
+            nameString = s_nameTable.AddNoLock("xsi");
             s_xmlstringtable[2] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
-            nameString = s_nameTable.Add("xmlns");
+            nameString = s_nameTable.AddNoLock("xmlns");
             s_xmlstringtable[3] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
-            nameString = s_nameTable.Add("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
+            nameString = s_nameTable.AddNoLock("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
             s_xmlstringtable[4] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
-            nameString = s_nameTable.Add("http://purl.org/dc/elements/1.1/");
+            nameString = s_nameTable.AddNoLock("http://purl.org/dc/elements/1.1/");
             s_xmlstringtable[5] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
-            nameString = s_nameTable.Add("http://purl.org/dc/terms/");
+            nameString = s_nameTable.AddNoLock("http://purl.org/dc/terms/");
             s_xmlstringtable[6] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
-            nameString = s_nameTable.Add("dc");
+            nameString = s_nameTable.AddNoLock("dc");
             s_xmlstringtable[7] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
-            nameString = s_nameTable.Add("dcterms");
+            nameString = s_nameTable.AddNoLock("dcterms");
             s_xmlstringtable[8] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
-            nameString = s_nameTable.Add("coreProperties");
+            nameString = s_nameTable.AddNoLock("coreProperties");
             s_xmlstringtable[9] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "NotSpecified");
-            nameString = s_nameTable.Add("type");
+            nameString = s_nameTable.AddNoLock("type");
             s_xmlstringtable[10] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, "NotSpecified");
-            nameString = s_nameTable.Add("creator");
+            nameString = s_nameTable.AddNoLock("creator");
             s_xmlstringtable[11] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("identifier");
+            nameString = s_nameTable.AddNoLock("identifier");
             s_xmlstringtable[12] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("title");
+            nameString = s_nameTable.AddNoLock("title");
             s_xmlstringtable[13] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("subject");
+            nameString = s_nameTable.AddNoLock("subject");
             s_xmlstringtable[14] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("description");
+            nameString = s_nameTable.AddNoLock("description");
             s_xmlstringtable[15] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("language");
+            nameString = s_nameTable.AddNoLock("language");
             s_xmlstringtable[0x10] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("created");
+            nameString = s_nameTable.AddNoLock("created");
             s_xmlstringtable[0x11] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCoreTermsNamespace, "DateTime");
-            nameString = s_nameTable.Add("modified");
+            nameString = s_nameTable.AddNoLock("modified");
             s_xmlstringtable[0x12] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCoreTermsNamespace, "DateTime");
-            nameString = s_nameTable.Add("contentType");
+            nameString = s_nameTable.AddNoLock("contentType");
             s_xmlstringtable[0x13] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("keywords");
+            nameString = s_nameTable.AddNoLock("keywords");
             s_xmlstringtable[20] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("category");
+            nameString = s_nameTable.AddNoLock("category");
             s_xmlstringtable[0x15] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("version");
+            nameString = s_nameTable.AddNoLock("version");
             s_xmlstringtable[0x16] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("lastModifiedBy");
+            nameString = s_nameTable.AddNoLock("lastModifiedBy");
             s_xmlstringtable[0x17] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("contentStatus");
+            nameString = s_nameTable.AddNoLock("contentStatus");
             s_xmlstringtable[0x18] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("revision");
+            nameString = s_nameTable.AddNoLock("revision");
             s_xmlstringtable[0x19] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
-            nameString = s_nameTable.Add("lastPrinted");
+            nameString = s_nameTable.AddNoLock("lastPrinted");
             s_xmlstringtable[0x1a] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "DateTime");
         }
 
@@ -161,5 +161,43 @@ namespace System.IO.Packaging
                 }
             }
         }
+
+        private sealed class ThreadSafeNameTable : NameTable
+        {
+            public override string Add(char[] array, int offset, int length)
+            {
+                lock (this)
+                {
+                    return base.Add(array, offset, length);
+                }
+            }
+
+            public override string Add(string array)
+            {
+                lock (this)
+                {
+                    return base.Add(array);
+                }
+            }
+
+            // can be used only from static ctor (which is always executed by a single thread)
+            internal string AddNoLock(string array) => base.Add(array);
+
+            public override string? Get(char[] array, int offset, int length)
+            {
+                lock (this)
+                {
+                    return base.Get(array, offset, length);
+                }
+            }
+
+            public override string? Get(string array)
+            {
+                lock (this)
+                {
+                    return base.Get(array);
+                }
+            }
+        }
     }
 }