You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -428,15 +428,15 @@ bounds checks when it is safe to do so.
428
428
3. ✔️ DO provide additional hints to the JIT, such as manual bounds checks before loops and saving fields to locals, as [.NET Memory Model](https://github.com/dotnet/runtime/blob/main/docs/design/specs/Memory-model.md) might conservatively prevent the JIT from removing bounds checks in some scenarios.
429
429
4. ✔️ DO guard code with `Debug.Assert` bounds checks if unsafe code is still necessary. Consider the example below.
430
430
431
-
```cs
431
+
```csharp
432
432
Debug.Assert(arrayisnotnull);
433
433
Debug.Assert((index>=0) && (index<array.Length));
434
434
// Unsafe code here
435
435
```
436
436
437
437
You might even refactor these checks into reusable helper methods.
@@ -575,7 +575,7 @@ instead of aligned ones such as `Unsafe.Read`/`Unsafe.Write` or `Unsafe.As` if d
575
575
Be cautious when you use various serialization-like APIs to copy or read structs to or from byte arrays.
576
576
If a struct contains paddings or non-blittable members (for example, `bool` or GC fields), then classic unsafe memory operations such as `Fill`, `CopyTo`, and `SequenceEqual` might accidentally copy sensitive data from the stack to the paddings or treat garbage data as significant during comparisons creating rarely reproducible bugs. A common anti-pattern might look like this:
Span<int>s=stackallocint[length]; // Bad practice: check the range of `length`!
@@ -664,7 +664,7 @@ the intended logic.
664
664
665
665
Fixedversion:
666
666
667
-
```cs
667
+
```csharp
668
668
voidBetterCode(intlength)
669
669
{
670
670
// The "throw if length < 0" check below is important, as attempting to stackalloc a negative
@@ -685,7 +685,7 @@ the intended logic.
685
685
Fixed-sizebufferswereusefulfor interop scenarios with data sources from other languages or platforms. They then were replaced by safer and more convenient [inline-arrays](../../csharp/language-reference/proposals/csharp-12.0/inline-arrays.md).
A modern and a safer alternative is [inline-arrays](../../csharp/language-reference/proposals/csharp-12.0/inline-arrays.md):
700
700
701
-
```cs
701
+
```csharp
702
702
[System.Runtime.CompilerServices.InlineArray(8)]
703
703
publicstructBuffer
704
704
{
@@ -725,7 +725,7 @@ ms.buffer[10] = 0; // Compiler knows this is out of range and produces compiler
725
725
726
726
Avoid defining APIs that accept unmanaged or managed pointers to contiguous data. Instead, use `Span<T>` or `ReadOnlySpan<T>`:
727
727
728
-
```cs
728
+
```csharp
729
729
// Poor API designs:
730
730
voidConsume(refbytedata, intlength);
731
731
voidConsume(byte*data, intlength);
@@ -748,7 +748,7 @@ can lead to information disclosure, data corruption, or process termination via
748
748
2. ❌ DON'T use implicit contracts for byref arguments, such as requiring all callers to allocate the input on the stack. If such a contract is necessary, consider using [ref struct](../../csharp/language-reference/builtin-types/ref-struct.md) instead.
749
749
3. ❌ DON'T assume buffers are zero-terminated unless the scenario explicitly documents that this is a valid assumption. For example, even though .NET guarantees that `string` instances are null-terminated, the same does not hold of other buffer types like `ReadOnlySpan<char>` or `char[]`.
@@ -779,7 +779,7 @@ can lead to information disclosure, data corruption, or process termination via
779
779
780
780
4. ❌ DON'T pass a pinned `Span<char>` or `ReadOnlySpan<char>` across a p/invoke boundary unless you have also passed an explicit length argument. Otherwise, the code on the other side of the p/invoke boundary might improperly believe the buffer is null-terminated.
To resolve this, use an alternative p/invoke signature that accepts _both_ the data pointer _and_ the length if possible. Otherwise, if the receiver has no way of accepting a separate length argument, ensure the original data is converted to a `string` before pinning it and passing it across the p/invoke boundary.
Strings in C# are immutable by design, and any attempt to mutate them using unsafe code can lead to undefined behavior. Example:
827
827
828
-
```cs
828
+
```csharp
829
829
strings="Hello";
830
830
fixed (char*p=s)
831
831
{
@@ -836,7 +836,7 @@ Console.WriteLine("Hello"); // prints "_ello" instead of "Hello"
836
836
837
837
Modifying an interned string (*most* string literals are) will change the value for all other uses. Even without string interning, writing into a newly created string should be replaced with the safer `String.Create` API:
1. ❌ DON'T mutate strings. Use the `String.Create` API to create a new string if complex copying logic is needed. Otherwise, use `.ToString()`, `StringBuilder`, `new string(...)` or string interpolation syntax.
856
+
1. ❌ DON'T mutate strings. Use the `String.Create` API to create a new string if complex copying logic is needed. Otherwise, use `.ToString()`, `StringBuilder`, `new string(...)`, or string interpolation syntax.
857
857
858
858
## 18. Raw IL code (for example, System.Reflection.Emit and Mono.Cecil)
859
859
@@ -884,7 +884,7 @@ Avoid using such techniques unless absolutely necessary.
884
884
allocating temporary buffers for I/O operations or other short-lived scenarios. While the API is straightforward
885
885
and doesn't inherently contain unsafe features, it can lead to use-after-free bugs in C#. Example:
886
886
887
-
```cs
887
+
```csharp
888
888
varbuffer=ArrayPool<byte>.Shared.Rent(1024);
889
889
_buffer=buffer; // buffer object escapes the scope
890
890
Use(buffer);
@@ -904,7 +904,7 @@ but the bug becomes harder to detect when `Rent` and `Return` are in different s
904
904
905
905
While ECMA-335 standard defines a Boolean as 0-255 where `true` is any non-zero value, it's better to avoid any explicit conversions between integers and Booleans in order to avoid introducing "denormalized" values as anything other than 0 or 1 likely leads to unreliable behavior.
906
906
907
-
```cs
907
+
```csharp
908
908
// Bad:
909
909
boolb=Unsafe.As<int, bool>(refsomeInteger);
910
910
inti=Unsafe.As<bool, int>(refsomeBool);
@@ -922,7 +922,7 @@ The JIT present in earlier .NET runtimes did not fully optimize the safe version
922
922
2. ✔️ DO use ternary operators (or other branching logic) instead. Modern .NET JITs will optimize them effectively.
923
923
3. ❌ DON'T read `bool` using unsafe APIs such as `Unsafe.ReadUnaligned` or `MemoryMarshal.Cast` if you don't trust the input. Consider using ternary operators or equality comparisons instead:
0 commit comments