< Summary

Information
Class: DotnetFuzzing.Fuzzers.Base64Fuzzer
Assembly: DotnetFuzzing
File(s): D:\runner\runtime\src\libraries\Fuzzing\DotnetFuzzing\Fuzzers\Base64Fuzzer.cs
Line coverage
96%
Covered lines: 226
Uncovered lines: 9
Coverable lines: 235
Total lines: 333
Line coverage: 96.1%
Branch coverage
73%
Covered branches: 22
Total branches: 30
Branch coverage: 73.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
FuzzTarget(...)100%11100%
TestCases(...)100%11100%
TestBase64(...)66.66%121297.24%
TestBase64Chars(...)75%121296.51%
TestToStringToCharArray(...)100%11100%
ToBase64_CalculateOutputLength(...)83.33%6693.33%

File(s)

D:\runner\runtime\src\libraries\Fuzzing\DotnetFuzzing\Fuzzers\Base64Fuzzer.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Buffers;
 5using System.Buffers.Text;
 6
 7namespace DotnetFuzzing.Fuzzers
 8{
 9    internal sealed class Base64Fuzzer : IFuzzer
 10    {
 11        private const int Base64LineBreakPosition = 76; // Needs to be in sync with Convert.Base64LineBreakPosition
 12
 013        public string[] TargetAssemblies => [];
 14
 015        public string[] TargetCoreLibPrefixes => ["System.Buffers.Text.Base64", "System.Convert"];
 16
 17        public void FuzzTarget(ReadOnlySpan<byte> bytes)
 178718        {
 178719            using PooledBoundedMemory<byte> inputPoisonBefore = PooledBoundedMemory<byte>.Rent(bytes, PoisonPagePlacemen
 178720            using PooledBoundedMemory<byte> inputPoisonAfter = PooledBoundedMemory<byte>.Rent(bytes, PoisonPagePlacement
 21
 178722            TestCases(inputPoisonBefore.Span, PoisonPagePlacement.Before);
 178723            TestCases(inputPoisonAfter.Span, PoisonPagePlacement.After);
 357424        }
 25
 26        private void TestCases(Span<byte> input, PoisonPagePlacement poison)
 357427        {
 357428            TestBase64(input, poison);
 357429            TestBase64Chars(input, poison);
 357430            TestToStringToCharArray(input, Base64FormattingOptions.None);
 357431            TestToStringToCharArray(input, Base64FormattingOptions.InsertLineBreaks);
 357432        }
 33
 34        private void TestBase64(Span<byte> input, PoisonPagePlacement poison)
 357435        {
 357436            int maxEncodedLength = Base64.GetMaxEncodedToUtf8Length(input.Length);
 357437            using PooledBoundedMemory<byte> destPoisoned = PooledBoundedMemory<byte>.Rent(maxEncodedLength, poison);
 357438            Span<byte> encoderDest = destPoisoned.Span;
 357439            using PooledBoundedMemory<byte> decoderDestPoisoned = PooledBoundedMemory<byte>.Rent(Base64.GetMaxDecodedFro
 357440            Span<byte> decoderDest = decoderDestPoisoned.Span;
 357441            { // IsFinalBlock = true
 357442                OperationStatus status = Base64.EncodeToUtf8(input, encoderDest, out int bytesConsumed, out int bytesEnc
 357443                Assert.Equal(OperationStatus.Done, status);
 357444                Assert.Equal(input.Length, bytesConsumed);
 357445                Assert.Equal(true, maxEncodedLength >= bytesEncoded && maxEncodedLength - 2 <= bytesEncoded);
 46
 357447                status = Base64.DecodeFromUtf8(encoderDest.Slice(0, bytesEncoded), decoderDest, out int bytesRead, out i
 48
 357449                Assert.Equal(OperationStatus.Done, status);
 357450                Assert.Equal(input.Length, bytesDecoded);
 357451                Assert.Equal(bytesEncoded, bytesRead);
 357452                Assert.SequenceEqual(input, decoderDest.Slice(0, bytesDecoded));
 357453            }
 54
 357455            { // IsFinalBlock = false
 357456                encoderDest.Clear();
 357457                decoderDest.Clear();
 357458                OperationStatus status = Base64.EncodeToUtf8(input, encoderDest, out int bytesConsumed, out int bytesEnc
 357459                Span<byte> decodeInput = encoderDest.Slice(0, bytesEncoded);
 60
 357461                if (input.Length % 3 == 0)
 99662                {
 99663                    Assert.Equal(OperationStatus.Done, status);
 99664                    Assert.Equal(input.Length, bytesConsumed);
 99665                    Assert.Equal(true, maxEncodedLength == bytesEncoded);
 66
 99667                    status = Base64.DecodeFromUtf8(decodeInput, decoderDest, out int bytesRead, out int bytesDecoded, is
 68
 99669                    Assert.Equal(OperationStatus.Done, status);
 99670                    Assert.Equal(input.Length, bytesDecoded);
 99671                    Assert.Equal(bytesEncoded, bytesRead);
 99672                    Assert.SequenceEqual(input, decoderDest.Slice(0, bytesDecoded));
 99673                }
 74                else
 257875                {
 257876                    Assert.Equal(OperationStatus.NeedMoreData, status);
 257877                    Assert.Equal(true, input.Length / 3 * 4 == bytesEncoded);
 78
 257879                    status = Base64.DecodeFromUtf8(decodeInput, decoderDest, out int bytesRead, out int bytesDecoded, is
 80
 257881                    if (decodeInput.Length % 4 == 0)
 257882                    {
 257883                        Assert.Equal(OperationStatus.Done, status);
 257884                        Assert.Equal(bytesConsumed, bytesDecoded);
 257885                        Assert.Equal(bytesEncoded, bytesRead);
 257886                    }
 87                    else
 088                    {
 089                        Assert.Equal(OperationStatus.NeedMoreData, status);
 090                    }
 91
 257892                    Assert.SequenceEqual(input.Slice(0, bytesDecoded), decoderDest.Slice(0, bytesDecoded));
 257893                }
 357494            }
 95
 357496            { // Encode / decode in place
 357497                encoderDest.Clear();
 357498                input.CopyTo(encoderDest);
 357499                OperationStatus status = Base64.EncodeToUtf8InPlace(encoderDest, input.Length, out int bytesEncoded);
 100
 3574101                Assert.Equal(OperationStatus.Done, status);
 3574102                Assert.Equal(true, maxEncodedLength >= bytesEncoded && maxEncodedLength - 2 <= bytesEncoded);
 103
 3574104                status = Base64.DecodeFromUtf8InPlace(encoderDest.Slice(0, bytesEncoded), out int bytesDecoded);
 105
 3574106                Assert.Equal(OperationStatus.Done, status);
 3574107                Assert.Equal(input.Length, bytesDecoded);
 3574108                Assert.SequenceEqual(input, encoderDest.Slice(0, bytesDecoded));
 3574109            }
 110
 3574111            { // Decode the random input directly, Assert IsValid result matches with decoded result
 3574112                decoderDest.Clear();
 3574113                if (Base64.IsValid(input, out int decodedLength))
 254114                {
 254115                    int maxDecodedLength = Base64.GetMaxDecodedFromUtf8Length(input.Length);
 254116                    OperationStatus status = Base64.DecodeFromUtf8(input, decoderDest, out int bytesRead, out int bytesD
 254117                    Assert.Equal(OperationStatus.Done, status);
 254118                    Assert.Equal(input.Length, bytesRead);
 254119                    Assert.Equal(decodedLength, bytesDecoded);
 254120                    Assert.Equal(true, maxDecodedLength >= bytesDecoded);
 121
 254122                    status = Base64.DecodeFromUtf8InPlace(input, out int inPlaceDecoded);
 254123                    Assert.Equal(OperationStatus.Done, status);
 254124                    Assert.Equal(bytesDecoded, inPlaceDecoded);
 254125                    Assert.SequenceEqual<byte>(input.Slice(0, inPlaceDecoded), decoderDest.Slice(0, bytesDecoded));
 254126                }
 127                else
 3320128                {
 3320129                    Assert.Equal(OperationStatus.InvalidData, Base64.DecodeFromUtf8(input, decoderDest, out int _, out i
 3320130                    Assert.Equal(OperationStatus.InvalidData, Base64.DecodeFromUtf8InPlace(input, out int inPlaceDecoded
 3320131                }
 3574132            }
 133
 3574134            { // Test new simplified UTF-8 APIs
 135                // Test EncodeToUtf8 returning byte[]
 3574136                byte[] encodedArray = Base64.EncodeToUtf8(input);
 3574137                Assert.Equal(true, maxEncodedLength >= encodedArray.Length && maxEncodedLength - 2 <= encodedArray.Lengt
 138
 139                // Test EncodeToUtf8 returning int
 3574140                encoderDest.Clear();
 3574141                int charsWritten = Base64.EncodeToUtf8(input, encoderDest);
 3574142                Assert.SequenceEqual(encodedArray.AsSpan(), encoderDest.Slice(0, charsWritten));
 143
 144                // Test TryEncodeToUtf8
 3574145                encoderDest.Clear();
 3574146                Assert.Equal(true, Base64.TryEncodeToUtf8(input, encoderDest, out int tryCharsWritten));
 3574147                Assert.Equal(charsWritten, tryCharsWritten);
 3574148                Assert.SequenceEqual(encodedArray.AsSpan(), encoderDest.Slice(0, tryCharsWritten));
 149
 150                // Test DecodeFromUtf8 returning byte[]
 3574151                byte[] decodedArray = Base64.DecodeFromUtf8(encodedArray);
 3574152                Assert.SequenceEqual(input, decodedArray.AsSpan());
 153
 154                // Test DecodeFromUtf8 returning int
 3574155                decoderDest.Clear();
 3574156                int bytesWritten = Base64.DecodeFromUtf8(encodedArray, decoderDest);
 3574157                Assert.Equal(input.Length, bytesWritten);
 3574158                Assert.SequenceEqual(input, decoderDest.Slice(0, bytesWritten));
 159
 160                // Test TryDecodeFromUtf8
 3574161                decoderDest.Clear();
 3574162                Assert.Equal(true, Base64.TryDecodeFromUtf8(encodedArray, decoderDest, out int tryBytesWritten));
 3574163                Assert.Equal(input.Length, tryBytesWritten);
 3574164                Assert.SequenceEqual(input, decoderDest.Slice(0, tryBytesWritten));
 165
 166                // Test TryEncodeToUtf8InPlace
 3574167                using PooledBoundedMemory<byte> inPlaceBuffer = PooledBoundedMemory<byte>.Rent(maxEncodedLength, poison)
 3574168                Span<byte> inPlaceDest = inPlaceBuffer.Span;
 3574169                input.CopyTo(inPlaceDest);
 3574170                Assert.Equal(true, Base64.TryEncodeToUtf8InPlace(inPlaceDest, input.Length, out int inPlaceWritten));
 3574171                Assert.SequenceEqual(encodedArray.AsSpan(), inPlaceDest.Slice(0, inPlaceWritten));
 172
 173                // Test GetEncodedLength matches GetMaxEncodedToUtf8Length
 3574174                Assert.Equal(Base64.GetMaxEncodedToUtf8Length(input.Length), Base64.GetEncodedLength(input.Length));
 175
 176                // Test GetMaxDecodedLength matches GetMaxDecodedFromUtf8Length
 3574177                Assert.Equal(Base64.GetMaxDecodedFromUtf8Length(maxEncodedLength), Base64.GetMaxDecodedLength(maxEncoded
 3574178            }
 7148179        }
 180
 181        private static void TestBase64Chars(Span<byte> input, PoisonPagePlacement poison)
 3574182        {
 3574183            int encodedLength = Base64.GetEncodedLength(input.Length);
 3574184            int maxDecodedLength = Base64.GetMaxDecodedLength(encodedLength);
 185
 3574186            using PooledBoundedMemory<char> destPoisoned = PooledBoundedMemory<char>.Rent(encodedLength, poison);
 3574187            using PooledBoundedMemory<byte> decoderDestPoisoned = PooledBoundedMemory<byte>.Rent(maxDecodedLength, poiso
 188
 3574189            Span<char> encoderDest = destPoisoned.Span;
 3574190            Span<byte> decoderDest = decoderDestPoisoned.Span;
 191
 3574192            { // IsFinalBlock = true
 3574193                OperationStatus status = Base64.EncodeToChars(input, encoderDest, out int bytesConsumed, out int charsEn
 194
 3574195                Assert.Equal(OperationStatus.Done, status);
 3574196                Assert.Equal(input.Length, bytesConsumed);
 3574197                Assert.Equal(encodedLength, charsEncoded);
 198
 3574199                string encodedString = Base64.EncodeToString(input);
 3574200                Assert.Equal(encodedString, new string(encoderDest.Slice(0, charsEncoded)));
 201
 3574202                status = Base64.DecodeFromChars(encoderDest.Slice(0, charsEncoded), decoderDest, out int charsRead, out 
 203
 3574204                Assert.Equal(OperationStatus.Done, status);
 3574205                Assert.Equal(input.Length, bytesDecoded);
 3574206                Assert.Equal(charsEncoded, charsRead);
 3574207                Assert.SequenceEqual(input, decoderDest.Slice(0, bytesDecoded));
 3574208            }
 209
 3574210            { // IsFinalBlock = false
 3574211                encoderDest.Clear();
 3574212                decoderDest.Clear();
 3574213                OperationStatus status = Base64.EncodeToChars(input, encoderDest, out int bytesConsumed, out int charsEn
 3574214                Span<char> decodeInput = encoderDest.Slice(0, charsEncoded);
 215
 3574216                if (input.Length % 3 == 0)
 996217                {
 996218                    Assert.Equal(OperationStatus.Done, status);
 996219                    Assert.Equal(input.Length, bytesConsumed);
 996220                    Assert.Equal(encodedLength, charsEncoded);
 221
 996222                    status = Base64.DecodeFromChars(decodeInput, decoderDest, out int charsRead, out int bytesDecoded, i
 223
 996224                    Assert.Equal(OperationStatus.Done, status);
 996225                    Assert.Equal(input.Length, bytesDecoded);
 996226                    Assert.Equal(charsEncoded, charsRead);
 996227                    Assert.SequenceEqual(input, decoderDest.Slice(0, bytesDecoded));
 996228                }
 229                else
 2578230                {
 2578231                    Assert.Equal(OperationStatus.NeedMoreData, status);
 2578232                    Assert.Equal(true, input.Length / 3 * 4 == charsEncoded);
 233
 2578234                    status = Base64.DecodeFromChars(decodeInput, decoderDest, out int charsRead, out int bytesDecoded, i
 235
 2578236                    if (decodeInput.Length % 4 == 0)
 2578237                    {
 2578238                        Assert.Equal(OperationStatus.Done, status);
 2578239                        Assert.Equal(bytesConsumed, bytesDecoded);
 2578240                        Assert.Equal(charsEncoded, charsRead);
 2578241                    }
 242                    else
 0243                    {
 0244                        Assert.Equal(OperationStatus.NeedMoreData, status);
 0245                    }
 246
 2578247                    Assert.SequenceEqual(input.Slice(0, bytesDecoded), decoderDest.Slice(0, bytesDecoded));
 2578248                }
 3574249            }
 250
 3574251            { // Test array-returning and int-returning overloads
 3574252                char[] encodedChars = Base64.EncodeToChars(input);
 3574253                Assert.Equal(encodedLength, encodedChars.Length);
 254
 3574255                encoderDest.Clear();
 3574256                int charsWritten = Base64.EncodeToChars(input, encoderDest);
 3574257                Assert.Equal(encodedLength, charsWritten);
 3574258                Assert.SequenceEqual(encodedChars.AsSpan(), encoderDest.Slice(0, charsWritten));
 259
 3574260                byte[] decodedBytes = Base64.DecodeFromChars(encodedChars);
 3574261                Assert.SequenceEqual(input, decodedBytes.AsSpan());
 262
 3574263                decoderDest.Clear();
 3574264                int bytesWritten = Base64.DecodeFromChars(encodedChars, decoderDest);
 3574265                Assert.Equal(input.Length, bytesWritten);
 3574266                Assert.SequenceEqual(input, decoderDest.Slice(0, bytesWritten));
 3574267            }
 268
 3574269            { // Test Try* variants
 3574270                encoderDest.Clear();
 3574271                Assert.Equal(true, Base64.TryEncodeToChars(input, encoderDest, out int charsWritten));
 3574272                Assert.Equal(encodedLength, charsWritten);
 273
 3574274                decoderDest.Clear();
 3574275                Assert.Equal(true, Base64.TryDecodeFromChars(encoderDest.Slice(0, charsWritten), decoderDest, out int by
 3574276                Assert.Equal(input.Length, bytesWritten);
 3574277                Assert.SequenceEqual(input, decoderDest.Slice(0, bytesWritten));
 3574278            }
 279
 3574280            { // Decode the random chars directly (as chars, from the input bytes interpreted as UTF-16)
 281                // Create a char span from the input bytes for testing decode with random data
 3574282                if (input.Length >= 2)
 3556283                {
 3556284                    ReadOnlySpan<char> inputChars = System.Runtime.InteropServices.MemoryMarshal.Cast<byte, char>(input)
 3556285                    decoderDest.Clear();
 286
 287                    // Try decoding - may succeed or fail depending on if input is valid base64
 3556288                    OperationStatus status = Base64.DecodeFromChars(inputChars, decoderDest, out int charsConsumed, out 
 289                    // Just verify we don't crash - the result depends on input validity
 3556290                    Assert.Equal(true, status == OperationStatus.Done || status == OperationStatus.InvalidData ||
 3556291                                       status == OperationStatus.NeedMoreData || status == OperationStatus.DestinationTo
 3556292                }
 3574293            }
 7148294        }
 295
 296        private static void TestToStringToCharArray(Span<byte> input, Base64FormattingOptions options)
 7148297        {
 7148298            int encodedLength = ToBase64_CalculateOutputLength(input.Length, options == Base64FormattingOptions.InsertLi
 7148299            char[] dest = new char[encodedLength];
 300
 7148301            string toStringResult = Convert.ToBase64String(input, options);
 7148302            byte[] decoded = Convert.FromBase64String(toStringResult);
 303
 7148304            Assert.SequenceEqual(input, decoded);
 305
 7148306            int written = Convert.ToBase64CharArray(input.ToArray(), 0, input.Length, dest, 0, options);
 7148307            decoded = Convert.FromBase64CharArray(dest, 0, written);
 308
 7148309            Assert.SequenceEqual(input, decoded);
 7148310            Assert.SequenceEqual(toStringResult.AsSpan(), dest.AsSpan(0, written));
 7148311        }
 312
 313        private static int ToBase64_CalculateOutputLength(int inputLength, bool insertLineBreaks)
 7148314        {
 7148315            uint outlen = ((uint)inputLength + 2) / 3 * 4;
 316
 7148317            if (outlen == 0)
 0318                return 0;
 319
 7148320            if (insertLineBreaks)
 3574321            {
 3574322                (uint newLines, uint remainder) = Math.DivRem(outlen, Base64LineBreakPosition);
 3574323                if (remainder == 0)
 74324                {
 74325                    --newLines;
 74326                }
 3574327                outlen += newLines * 2; // 2 line break chars added: "\r\n"
 3574328            }
 329
 7148330            return (int)outlen;
 7148331        }
 332    }
 333}