Add tests to verify that JSON deserializer doesn't do any multiplication or addition...
authorEugene Samoylov <eugenesmlv@gmail.com>
Thu, 24 Oct 2019 22:52:56 +0000 (03:52 +0500)
committerStephen Toub <stoub@microsoft.com>
Thu, 24 Oct 2019 22:52:56 +0000 (18:52 -0400)
* Add deserialization tests for very long input strings (dotnet/corefx#41687)

* Fix tests

* Add deserialization tests for the maximum possible string length

* Improve long strings creation in deserialization tests for netcoreapp

* Extract common logic from if/def block

* Fix assertion

* Remove unnecessary test cases

* Remove other extra test cases

Commit migrated from https://github.com/dotnet/corefx/commit/7105528014425ca7f042e05e8d57e9e243931a62

src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.cs

index 4236cca..d7661f1 100644 (file)
@@ -380,12 +380,47 @@ namespace System.Text.Json.Serialization.Tests
         public static void LongInputString(int length)
         {
             // Verify boundary conditions in Deserialize() that inspect the size to determine allocation strategy.
-            string repeated = new string('x', length - 2);
-            string json = $"\"{repeated}\"";
-            Assert.Equal(length, json.Length);
+            DeserializeLongJsonString(length);
+        }
+
+        private const int MaxInt = int.MaxValue / MaxExpansionFactorWhileTranscoding;
+        private const int MaximumPossibleStringLength = int.MaxValue / 2 - 32;
+
+        // NOTE: VeryLongInputString test is constrained to run on Windows and MacOSX because it causes
+        //       problems on Linux due to the way deferred memory allocation works. On Linux, the allocation can
+        //       succeed even if there is not enough memory but then the test may get killed by the OOM killer at the
+        //       time the memory is accessed which triggers the full memory allocation.
+        [ConditionalTheory(nameof(IsX64))]
+        [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.OSX)]
+        [InlineData(MaxInt)]
+        [InlineData(MaximumPossibleStringLength)]
+        [OuterLoop]
+        public static void VeryLongInputString(int length)
+        {
+            // Verify that deserializer does not do any multiplication or addition on the string length
+            DeserializeLongJsonString(length);
+        }
+
+        private static void DeserializeLongJsonString(int stringLength)
+        {
+            string json;
+            char fillChar = 'x';
+
+#if BUILDING_INBOX_LIBRARY
+            json = string.Create(stringLength, fillChar, (chars, fillChar) =>
+            {
+                chars.Fill(fillChar);
+                chars[0] = '"';
+                chars[chars.Length - 1] = '"';
+            });
+#else
+            string repeated = new string(fillChar, stringLength - 2);
+            json = $"\"{repeated}\"";
+#endif
+            Assert.Equal(stringLength, json.Length);
 
             string str = JsonSerializer.Deserialize<string>(json);
-            Assert.Equal(repeated, str);
+            Assert.True(json.AsSpan(1, json.Length - 2).SequenceEqual(str.AsSpan()));
         }
     }
 }