Skip to content

Base64Url.DecodeFromChars crashes with AccessViolationException on non-ASCII char input (Microsoft.Bcl.Memory) #124513

@Tomius

Description

@Tomius

Description

Base64Url.DecodeFromChars causes a fatal AccessViolationException (process crash, exit code 0xC0000005)
when the input ReadOnlySpan<char> contains non-ASCII characters with sufficiently high code point values.

The method should return OperationStatus.InvalidData for invalid input, but instead performs an
out-of-bounds memory read in the scalar decode path via Unsafe.Add into the 256-element DecodingMap.

Reproduction Steps

  1. Create a .NET 8 console app referencing Microsoft.Bcl.Memory (any version — tested with 9.0.5)
  2. Run the following code:
using System.Buffers;
using System.Buffers.Text;

const string input = "AB\u1000D";
byte[] buffer = new byte[Base64Url.GetMaxDecodedLength(input.Length)];
Base64Url.DecodeFromChars(input, buffer, out _, out _);

Expected behavior

DecodeFromChars returns OperationStatus.InvalidData, since \u1000 is not a valid Base64Url character.

Actual behavior

The process crashes with a fatal AccessViolationException:

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at System.Buffers.Text.Base64Helper.DecodeFrom[[...Base64UrlDecoderChar...],[System.UInt16...]](...)
   at System.Buffers.Text.Base64Url.DecodeFromChars(...)

Regression?

This is not a regression — the bug has existed since Base64Url was first made available for .NET 8
via the Microsoft.Bcl.Memory NuGet package.

Known Workarounds

A safe workaround is to call System.Text.Ascii.IsValid(input) before decoding.
Base64 only uses ASCII characters, so any non-ASCII input is inherently invalid.

Configuration

  • Crashes on: .NET 8.0.24, Windows 10 x64, Microsoft.Bcl.Memory 9.0.5
  • Works correctly on: .NET 10.0.2 (in-framework Base64Url — returns InvalidData)
  • Not architecture-specific, but only affects the scalar decode path (short inputs or tail processing)

Other information

Root cause

The scalar fallback path in Base64Helper.DecodeFrom calls decoder.DecodeFourElements(src, ref decodingMap).
For the char/ushort decoder, this uses Unsafe.Add(ref decodingMap, (IntPtr)charValue) to index into
the DecodingMap, which is only 256 elements. A char value > 255 (e.g. \u1000 = 4096) reads
4096 bytes past the start of the map, hitting unmapped memory.

Characters in the range 128–255 do not crash (they read adjacent mapped memory that happens to
contain -1 / invalid values), but characters >= ~4096 reliably trigger the access violation.

The SIMD paths (AVX2, SSE, NEON) are not affected because they narrow ushort to byte before the
lookup, which naturally clamps the value to 0–255.

Notes

  • Base64Url.DecodeFromChars (the 2-parameter overload that throws FormatException) and
    Base64Url.TryDecodeFromChars are equally affected since they call the same internal DecodeFrom method.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions