Add a _malloca-like API Span<T>.Alloc(int length) #25423
Description
(This is distinct from the proposal at https://github.com/dotnet/corefx/issues/26954, which considers a more powerful API that can give the caller specific information about the current stack. The proposal under consideration here is only for a "KISS" API. Both proposals could exist side-by-side depending on the scenario, and in fact this proposal could depend on the more powerful API if we decide that's the right behavior.)
As the pattern Span<T> span = stackalloc T[len];
becomes more commonplace, we're seeing a rise in incorrect usage where developers are piping through untrusted len values, potentially making their applications susceptible to reliability issues or DoS attacks. The safe language construct is Span<T> span = ((uint)len <= 128 /* or other const */) ? stackalloc T[len] : new T[len];
. We can't rely on our larger developer audience remembering the safe pattern, and even our more knowledgeable advanced developers can forget the check from time to time.
Following are concrete proposals from the security team as to how this can be addressed.
First, create a utility method public static Span<T> Span<T>.Alloc(int length)
. This API will stackalloc
in the current frame if appropriate; otherwise the method will heap-alloc, similar to the CRT's _malloca API. Adding this method and getting the desired runtime behavior would not require compiler changes, but it would require JIT changes. The implementation of the method would default simply to new T[length]
if length is negative or is too large. Advanced developers who want to pull from an existing array pool as fallback wouldn't use this API; they'd perform the check manually.
Second, once the utility method is in place, the compiler should be smart enough to treat return Span<T>.Alloc(...);
as a compile-time error, just as it does today for Span<T> span = stackalloc T[...]; return span;
. This would require a compiler change.
Third, the developer should be warned when passing a non-constant and non-bounds-checked value into stackalloc
, and the warning should direct the developer to use Span<T>.Alloc
instead. The developer should also be warned when using stackalloc
or Span<T>.Alloc
in a loop. (We considered warning on recursive method calls, but that really belongs in a different analyzer.) Making this a proper compiler warning is probably a bit too noisy, so it could be a Roslyn code analyzer instead. This wouldn't require a compiler or JIT change; it'd just be a new version of the analyzers package for developers who run it as part of build.
Finally, remember that this is a KISS proposal. It's intended for the majority use case for developers who may want to consume Span
-based APIs but need a bit of a safety net. Advanced developers could still use the other APIs under consideration or perform their own custom checks as appropriate for their applications.