Repository: DataDog/dd-trace-dotnet
Pull request #6846: [IAST] Add support for Dotnet 9 ReadOnlySpan String overloads
Author: login: daniel-romano-DD
Labels: name: type:enhancement
description: Improvement to an existing feature
name: area:asm-iast
Created: 2025-04-11T17:05:16Z | Merged: 2025-04-22T11:15:07Z

## Summary of changes
Added IAST support for string overloads using `ReadOnlySpan` s

## Reason for change
Dotnet 6 introduced some overloads in `Concat `function, accepting `ReadOnlySpan<char>` as parameters instead of strings. Dotnet 9 introduced other overloads in Join and Split, getting `ReadOnlySpan<string>` instead of `params string[]`. Add support for both cases.

## Implementation details
For the first case, implement a resolve function that returns the original string address from the first char pointed to by the `ReadOnlySpan<char>`.

For the second cases, and due to the fact that they are dotnet 9 and there is no tracer for that framework, the ReadOnlySpan is converted and the Array overload is called.

## Test coverage
New instrumented tests have been deployed.

## Other details
<!-- Fixes #{issue} -->

<!--  ⚠️ Note: where possible, please obtain 2 approvals prior to merging. Unless CODEOWNERS specifies otherwise, for external teams it is typically best to have one review from a team member, and one review from apm-dotnet. Trivial changes do not require 2 reviews. -->



Diff:
diff --git a/tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs b/tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
index 1c1294b0c6da..5c13c88f4975 100644
--- a/tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
+++ b/tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
@@ -512,6 +512,104 @@ public static string Concat<T>(IEnumerable<T> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2)
+    {
+        var result = string.Concat(param1, param2);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Concat)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3)
+    {
+        var result = string.Concat(param1, param2, param3);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Concat)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <param name="param4"> Fourth param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3, ReadOnlySpan<char> param4)
+    {
+        var result = string.Concat(param1, param2, param3, param4);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3), TaintedObjects.GetString(ref param4)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Concat)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param"> Strings to concat </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.String>)")]
+    public static string Concat(ReadOnlySpan<string> param)
+#pragma warning disable DD0005 // Aspect is in incorrect format
+    {
+        // TODO: use propper overload when dotnet 9 or later target is available
+        var values = param.ToArray();
+        var result = string.Concat(values);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(values, result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Concat)}");
+        }
+
+        return result;
+    }
+#pragma warning restore DD0005 // Aspect is in incorrect format
+
+#endif
+
     /// <summary>
     /// String.Substring aspect
     /// </summary>
@@ -807,6 +905,66 @@ public static string JoinString(string separator, IEnumerable<string> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="separator"> sparator </param>
+    /// <param name="values"> values to join </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Join(System.String,System.ReadOnlySpan`1<System.String>)")]
+    public static string Join(string separator, ReadOnlySpan<string> values)
+#pragma warning disable DD0005 // Aspect is in incorrect format
+    {
+        return Join(separator, values.ToArray());
+    }
+#pragma warning restore DD0005 // Aspect is in incorrect format
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="separator"> sparator </param>
+    /// <param name="values"> values to join </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Join(System.Char,System.ReadOnlySpan`1<System.String>)")]
+    public static string Join(char separator, ReadOnlySpan<string> values)
+#pragma warning disable DD0005 // Aspect is in incorrect format
+    {
+        return Join(separator, values.ToArray());
+    }
+#pragma warning restore DD0005 // Aspect is in incorrect format
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="separator"> sparator </param>
+    /// <param name="values"> values to join </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Join(System.String,System.ReadOnlySpan`1<System.Object>)")]
+    public static string Join(string separator, ReadOnlySpan<object> values)
+#pragma warning disable DD0005 // Aspect is in incorrect format
+    {
+        return Join(separator, values.ToArray());
+    }
+#pragma warning restore DD0005 // Aspect is in incorrect format
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="separator"> sparator </param>
+    /// <param name="values"> values to join </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Join(System.Char,System.ReadOnlySpan`1<System.Object>)")]
+    public static string Join(char separator, ReadOnlySpan<object> values)
+#pragma warning disable DD0005 // Aspect is in incorrect format
+    {
+        return Join(separator, values.ToArray());
+    }
+#pragma warning restore DD0005 // Aspect is in incorrect format
+
+#endif
+
     /// <summary>
     /// String.ToUpper aspect
     /// </summary>
@@ -1279,6 +1437,38 @@ public static string Format(IFormatProvider provider, string format, object[] ar
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Format aspect
+    /// </summary>
+    /// <param name="format"> format of the string </param>
+    /// <param name="args"> first format argument </param>
+    /// <returns> String.Format() </returns>
+    [AspectMethodReplace("System.String::Format(System.String,System.ReadOnlySpan`1<System.Object>)")]
+    public static string Format(string format, ReadOnlySpan<object> args)
+#pragma warning disable DD0005 // Aspect is in incorrect format
+    {
+        return Format(format, args.ToArray());
+    }
+#pragma warning restore DD0005 // Aspect is in incorrect format
+
+    /// <summary>
+    /// String.Format aspect
+    /// </summary>
+    /// <param name="provider"> format provider </param>
+    /// <param name="format"> format of the string </param>
+    /// <param name="args"> first format argument </param>
+    /// <returns> String.Format() </returns>
+    [AspectMethodReplace("System.String::Format(System.IFormatProvider,System.String,System.ReadOnlySpan`1<System.Object>)")]
+    public static string Format(IFormatProvider provider, string format, ReadOnlySpan<object> args)
+#pragma warning disable DD0005 // Aspect is in incorrect format
+    {
+        return Format(provider, format, args.ToArray());
+    }
+#pragma warning restore DD0005 // Aspect is in incorrect format
+#endif
+
 #if NETCOREAPP3_1_OR_GREATER
     /// <summary>
     /// String.Replace aspect
@@ -1612,6 +1802,24 @@ public static string[] Split(string target, char separator, int count, StringSpl
     }
 #endif
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Split aspect
+    /// </summary>
+    /// <param name="target"> instance of the string </param>
+    /// <param name="separator"> separator argument </param>
+    /// <returns> String.Split() </returns>
+    [AspectMethodReplace("System.String::Split(System.ReadOnlySpan`1<System.Char>)", AspectFilter.StringLiteral_0)]
+    public static string[] Split(string target, ReadOnlySpan<char> separator)
+#pragma warning disable DD0005 // Aspect is in incorrect format
+    {
+        return Split(target, separator.ToArray());
+    }
+#pragma warning restore DD0005 // Aspect is in incorrect format
+
+#endif
+
 #pragma warning disable CS0618 // Obsolete
     /// <summary>
     /// String.Copy aspect
diff --git a/tracer/src/Datadog.Trace/Iast/TaintedObjects.cs b/tracer/src/Datadog.Trace/Iast/TaintedObjects.cs
index 9fc69e8b7cab..9bd7a36a31ac 100644
--- a/tracer/src/Datadog.Trace/Iast/TaintedObjects.cs
+++ b/tracer/src/Datadog.Trace/Iast/TaintedObjects.cs
@@ -5,6 +5,10 @@
 
 #nullable enable
 
+using System;
+using InlineIL;
+using static InlineIL.IL.Emit;
+
 namespace Datadog.Trace.Iast
 {
     internal class TaintedObjects
@@ -23,6 +27,32 @@ public TaintedObjects()
             _map = new DefaultTaintedMap();
         }
 
+#if NET6_0_OR_GREATER
+
+        internal static unsafe string? GetString(ref ReadOnlySpan<char> span)
+        {
+            try
+            {
+#pragma warning disable CS8500
+                // Gets the address of the first char
+                fixed (void* spanPointer = &span)
+                {
+                    // Adjust for the string header (8 or 4 bytes) and length (4 bytes)
+                    nint spanAddress = (*(nint*)spanPointer) - IntPtr.Size - 4;
+                    string spanStr = *(string*)&spanAddress;
+                    return spanStr;
+                }
+#pragma warning restore CS8500
+            }
+            catch (Exception ex)
+            {
+                IastModule.LogAspectException(ex, "Error while getting string from ReadOnlySpan");
+            }
+
+            return null;
+        }
+#endif
+
         public bool TaintInputString(string stringToTaint, Source source)
         {
             if (!IsFiltered(stringToTaint))
@@ -73,6 +103,15 @@ public void Taint(object objectToTaint, Range[] ranges)
             return _map.Get(objectToFind) as TaintedObject;
         }
 
+#if NET6_0_OR_GREATER
+        public TaintedObject? Get(ref ReadOnlySpan<char> objectToFind)
+        {
+            var stringToFind = GetString(ref objectToFind);
+            if (stringToFind is null) { return null; }
+            return _map.Get(stringToFind) as TaintedObject;
+        }
+#endif
+
         public int GetEstimatedSize()
         {
             return _map.GetEstimatedSize();
diff --git a/tracer/src/Datadog.Tracer.Native/Generated/generated_callsites.g.cpp b/tracer/src/Datadog.Tracer.Native/Generated/generated_callsites.g.cpp
index 05fe77a52126..385c79e9ce03 100644
--- a/tracer/src/Datadog.Tracer.Native/Generated/generated_callsites.g.cpp
+++ b/tracer/src/Datadog.Tracer.Native/Generated/generated_callsites.g.cpp
@@ -90,6 +90,10 @@ std::vector<WCHAR*> callSites =
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Concat(System.Object,System.Object,System.Object,System.Object)\",\"\",[0],[False],[None],Default,[])] Concat(System.Object,System.Object,System.Object,System.Object) 1"),
 #endif
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Concat(System.Object[])\",\"\",[0],[False],[None],Default,[])] Concat(System.Object[]) 15"),
+(WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)\",\"\",[0],[False],[None],Default,[])] Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>) 8"),
+(WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)\",\"\",[0],[False],[None],Default,[])] Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>) 8"),
+(WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)\",\"\",[0],[False],[None],Default,[])] Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>) 8"),
+(WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Concat(System.ReadOnlySpan`1<System.String>)\",\"\",[0],[False],[None],Default,[])] Concat(System.ReadOnlySpan`1<System.String>) 8"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Concat(System.String,System.String)\",\"\",[0],[False],[StringLiterals_Any],Default,[])] Concat(System.String,System.String) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Concat(System.String,System.String)\",\"\",[0],[False],[StringLiteral_0],Default,[])] Concat_0(System.String,System.String) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Concat(System.String,System.String)\",\"\",[0],[False],[StringLiteral_1],Default,[])] Concat_1(System.String,System.String) 15"),
@@ -101,18 +105,24 @@ std::vector<WCHAR*> callSites =
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Format(System.IFormatProvider,System.String,System.Object,System.Object)\",\"\",[0],[False],[None],Default,[])] Format(System.IFormatProvider,System.String,System.Object,System.Object) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Format(System.IFormatProvider,System.String,System.Object,System.Object,System.Object)\",\"\",[0],[False],[None],Default,[])] Format(System.IFormatProvider,System.String,System.Object,System.Object,System.Object) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Format(System.IFormatProvider,System.String,System.Object[])\",\"\",[0],[False],[None],Default,[])] Format(System.IFormatProvider,System.String,System.Object[]) 15"),
+(WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Format(System.IFormatProvider,System.String,System.ReadOnlySpan`1<System.Object>)\",\"\",[0],[False],[None],Default,[])] Format(System.IFormatProvider,System.String,System.ReadOnlySpan`1<System.Object>) 8"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Format(System.String,System.Object)\",\"\",[0],[False],[StringLiterals],Default,[])] Format(System.String,System.Object) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Format(System.String,System.Object,System.Object)\",\"\",[0],[False],[StringLiterals],Default,[])] Format(System.String,System.Object,System.Object) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Format(System.String,System.Object,System.Object,System.Object)\",\"\",[0],[False],[StringLiterals],Default,[])] Format(System.String,System.Object,System.Object,System.Object) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Format(System.String,System.Object[])\",\"\",[0],[False],[None],Default,[])] Format(System.String,System.Object[]) 15"),
+(WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Format(System.String,System.ReadOnlySpan`1<System.Object>)\",\"\",[0],[False],[None],Default,[])] Format(System.String,System.ReadOnlySpan`1<System.Object>) 8"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Insert(System.Int32,System.String)\",\"\",[0],[False],[StringOptimization],Default,[])] Insert(System.String,System.Int32,System.String) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.Char,System.Collections.Generic.IEnumerable`1<!!0>)\",\"\",[0],[False],[None],Default,[]);V3.2.0] Join(System.Char,System.Collections.Generic.IEnumerable`1<!!0>) 12"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.Char,System.Object[])\",\"\",[0],[False],[None],Default,[])] Join(System.Char,System.Object[]) 12"),
+(WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.Char,System.ReadOnlySpan`1<System.Object>)\",\"\",[0],[False],[None],Default,[])] Join(System.Char,System.ReadOnlySpan`1<System.Object>) 8"),
+(WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.Char,System.ReadOnlySpan`1<System.String>)\",\"\",[0],[False],[None],Default,[])] Join(System.Char,System.ReadOnlySpan`1<System.String>) 8"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.Char,System.String[])\",\"\",[0],[False],[None],Default,[])] Join(System.Char,System.String[]) 12"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.Char,System.String[],System.Int32,System.Int32)\",\"\",[0],[False],[None],Default,[])] Join(System.Char,System.String[],System.Int32,System.Int32) 12"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.String,System.Collections.Generic.IEnumerable`1<!!0>)\",\"\",[0],[False],[None],Default,[]);V3.2.0] Join(System.String,System.Collections.Generic.IEnumerable`1<!!0>) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.String,System.Collections.Generic.IEnumerable`1<System.String>)\",\"\",[0],[False],[None],Default,[])] JoinString(System.String,System.Collections.Generic.IEnumerable`1<System.String>) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.String,System.Object[])\",\"\",[0],[False],[None],Default,[])] Join(System.String,System.Object[]) 15"),
+(WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.String,System.ReadOnlySpan`1<System.Object>)\",\"\",[0],[False],[None],Default,[])] Join(System.String,System.ReadOnlySpan`1<System.Object>) 8"),
+(WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.String,System.ReadOnlySpan`1<System.String>)\",\"\",[0],[False],[None],Default,[])] Join(System.String,System.ReadOnlySpan`1<System.String>) 8"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.String,System.String[])\",\"\",[0],[False],[None],Default,[])] Join(System.String,System.String[]) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Join(System.String,System.String[],System.Int32,System.Int32)\",\"\",[0],[False],[None],Default,[])] Join(System.String,System.String[],System.Int32,System.Int32) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::PadLeft(System.Int32)\",\"\",[0],[False],[StringLiteral_0],Default,[])] PadLeft(System.String,System.Int32) 15"),
@@ -131,6 +141,7 @@ std::vector<WCHAR*> callSites =
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Split(System.Char[],System.Int32)\",\"\",[0],[False],[StringLiteral_0],Default,[])] Split(System.String,System.Char[],System.Int32) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Split(System.Char[],System.Int32,System.StringSplitOptions)\",\"\",[0],[False],[StringLiteral_0],Default,[])] Split(System.String,System.Char[],System.Int32,System.StringSplitOptions) 15"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Split(System.Char[],System.StringSplitOptions)\",\"\",[0],[False],[StringLiteral_0],Default,[])] Split(System.String,System.Char[],System.StringSplitOptions) 15"),
+(WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Split(System.ReadOnlySpan`1<System.Char>)\",\"\",[0],[False],[StringLiteral_0],Default,[])] Split(System.String,System.ReadOnlySpan`1<System.Char>) 8"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Split(System.String,System.Int32,System.StringSplitOptions)\",\"\",[0],[False],[StringLiteral_0],Default,[])] Split(System.String,System.String,System.Int32,System.StringSplitOptions) 12"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Split(System.String,System.StringSplitOptions)\",\"\",[0],[False],[StringLiteral_0],Default,[])] Split(System.String,System.String,System.StringSplitOptions) 12"),
 (WCHAR*)WStr("  [AspectMethodReplace(\"System.String::Split(System.String[],System.Int32,System.StringSplitOptions)\",\"\",[0],[False],[StringLiteral_0],Default,[])] Split(System.String,System.String[],System.Int32,System.StringSplitOptions) 15"),
diff --git a/tracer/test/Datadog.Trace.Security.IntegrationTests/IAST/IastInstrumentationUnitTests.cs b/tracer/test/Datadog.Trace.Security.IntegrationTests/IAST/IastInstrumentationUnitTests.cs
index 20c93bb0fbd8..b9ca07970c30 100644
--- a/tracer/test/Datadog.Trace.Security.IntegrationTests/IAST/IastInstrumentationUnitTests.cs
+++ b/tracer/test/Datadog.Trace.Security.IntegrationTests/IAST/IastInstrumentationUnitTests.cs
@@ -282,7 +282,11 @@ public void TestFileClassMethodsAspectCover()
 
     [Theory]
     [InlineData(typeof(StringBuilder))]
+#if NET9_0_OR_GREATER
     [InlineData(typeof(string))]
+#else
+    [InlineData(typeof(string), new[] { "System.String::Concat(System.ReadOnlySpan`1<System.String>)" })]
+#endif
     [InlineData(typeof(StreamWriter))]
     [InlineData(typeof(StreamReader))]
     [InlineData(typeof(FileStream))]
diff --git a/tracer/test/test-applications/integrations/Samples.InstrumentedTests/InstrumentationTestsBase.cs b/tracer/test/test-applications/integrations/Samples.InstrumentedTests/InstrumentationTestsBase.cs
index 0c683161aee0..c0279c04792a 100644
--- a/tracer/test/test-applications/integrations/Samples.InstrumentedTests/InstrumentationTestsBase.cs
+++ b/tracer/test/test-applications/integrations/Samples.InstrumentedTests/InstrumentationTestsBase.cs
@@ -56,7 +56,6 @@ public class InstrumentationTestsBase : IDisposable
     private static MethodInfo _locationProperty = _vulnerabilityType.GetProperty("Location", BindingFlags.Public | BindingFlags.Instance)?.GetMethod;
     private static MethodInfo _pathProperty = _locationType.GetProperty("Path", BindingFlags.Public | BindingFlags.Instance)?.GetMethod;
     private static MethodInfo _lineProperty = _locationType.GetProperty("Line", BindingFlags.Public | BindingFlags.Instance)?.GetMethod;
-    private static MethodInfo _getTaintedObjectsMethod = _taintedObjectsType.GetMethod("Get", BindingFlags.Instance | BindingFlags.Public);
     private static MethodInfo _taintMethod = _taintedObjectsType.GetMethod("Taint", BindingFlags.Instance | BindingFlags.Public);
     private static MethodInfo _enableIastInRequestMethod = _traceContextType.GetMethod("EnableIastInRequest", BindingFlags.Instance | BindingFlags.NonPublic);
     private static MethodInfo _getArrayMethod = _arrayBuilderOfSpanType.GetMethod("GetArray");
@@ -70,6 +69,15 @@ public class InstrumentationTestsBase : IDisposable
     protected static string WeakHashVulnerabilityType = "WEAK_HASH";
     protected static string commandInjectionType = "COMMAND_INJECTION";
 
+#if NET6_0_OR_GREATER
+    private static MethodInfo _getTaintedObjectsMethod = _taintedObjectsType.GetMethod("Get", BindingFlags.Instance | BindingFlags.Public, [typeof(object)]);
+    private static MethodInfo _getSpanTaintedObjectsMethod = _taintedObjectsType.GetMethod("Get", BindingFlags.Instance | BindingFlags.Public, [ typeof(ReadOnlySpan<char>) ]);
+    delegate object? GetSpanDelegate(ref ReadOnlySpan<char> tainted);
+    private GetSpanDelegate _getSpanTaintedObjectsDelegate;
+#else
+    private static MethodInfo _getTaintedObjectsMethod = _taintedObjectsType.GetMethod("Get", BindingFlags.Instance | BindingFlags.Public);
+#endif
+
     [Flags]
     public enum SecureMarks : byte
     {
@@ -94,6 +102,10 @@ public InstrumentationTestsBase()
         _iastRequestContext = _iastRequestContextProperty.Invoke(_traceContext, Array.Empty<object>());
         _taintedObjects = _taintedObjectsField.GetValue(_iastRequestContext);
         _taintedObjects.Should().NotBeNull();
+
+#if NET6_0_OR_GREATER
+        _getSpanTaintedObjectsDelegate = _taintedObjectsType.GetMethod("Get", BindingFlags.Instance | BindingFlags.Public, [typeof(ReadOnlySpan<char>).MakeByRefType()]).CreateDelegate<GetSpanDelegate>(_taintedObjects);
+#endif
     }
 
     public virtual void Dispose()
@@ -145,6 +157,22 @@ private object GetTainted(object tainted)
         return _getTaintedObjectsMethod.Invoke(_taintedObjects, new object[] { tainted });
     }
 
+#if NET6_0_OR_GREATER
+    private object GetTainted(ref ReadOnlySpan<char> tainted)
+    {
+        return _getSpanTaintedObjectsDelegate(ref tainted);
+    }
+    protected void AssertTainted(ref ReadOnlySpan<char> value, string additionalInfo = "")
+    {
+        GetTainted(ref value).Should().NotBeNull(value.ToString() + " is not tainted. " + additionalInfo);
+    }
+    protected void AssertNotTainted(ref ReadOnlySpan<char> value, string additionalInfo = "")
+    {
+        GetTainted(ref value).Should().BeNull(value.ToString() + " is tainted. " + additionalInfo);
+    }
+
+#endif
+
     protected void AssertNotTainted(object value, string additionalInfo = "")
     {
         GetTainted(value).Should().BeNull(value + " is tainted. " + additionalInfo);
diff --git a/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/SpanStringTests.cs b/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/SpanStringTests.cs
new file mode 100644
index 000000000000..678c3389b459
--- /dev/null
+++ b/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/SpanStringTests.cs
@@ -0,0 +1,31 @@
+#if NET6_0_OR_GREATER
+
+using System;
+using Xunit;
+using System.Runtime.CompilerServices;
+using FluentAssertions;
+
+namespace Samples.InstrumentedTests.Iast.Propagation.String;
+
+public class SpanStringTests : InstrumentationTestsBase
+{
+    protected string TaintedValue = "tainted";
+    protected string UntaintedValue = "untainted";
+
+    public SpanStringTests()
+    {
+        AddTainted(TaintedValue);
+    }
+
+    [Fact]
+    public void GivenAnTaintedString_WhenCastingToSpan_SpanIsTainted()
+    {
+        ReadOnlySpan<char> taintedSpan = TaintedValue;
+        ReadOnlySpan<char> nonTaintedSpan = UntaintedValue;
+
+        AssertTainted(ref taintedSpan);
+        AssertNotTainted(ref nonTaintedSpan);
+    }
+}
+
+#endif
diff --git a/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringConcatTests.cs b/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringConcatTests.cs
index 4a757682334f..d512cb6dc2d1 100644
--- a/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringConcatTests.cs
+++ b/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringConcatTests.cs
@@ -707,5 +707,58 @@ public void GivenAnArrayOfObjectsWithAllNullArguments_WhenCalling_Concat_ResultI
 
         System.String.Concat(obj).Should().BeEmpty();
     }
+
+#if NET9_0_OR_GREATER
+    [Fact]
+    public void GivenStringsReadOnlySpan_WhenConcat_ResultIsOk()
+    {
+        var values = new string[] { "concat", "CONCAT2", taintedValue, taintedValue2 };
+        var span = new ReadOnlySpan<string>(values);
+
+        AssertTaintedFormatWithOriginalCallCheck("concatCONCAT2:+-tainted-+::+-TAINTED2-+:", 
+                  System.String.Concat(span), 
+            () => System.String.Concat(values));
+    }
+
+    [Fact]
+    public void GivenTwoReadOnlySpan_WhenConcat_ResultIsOk()
+    {
+        var values = new string[] { "concat", taintedValue };
+        ReadOnlySpan<char> span0 = values[0];
+        ReadOnlySpan<char> span1 = values[1];
+
+        AssertTaintedFormatWithOriginalCallCheck("concat:+-tainted-+:",
+                  System.String.Concat(span0, span1),
+            () => System.String.Concat(values));
+    }
+
+    [Fact]
+    public void GivenThreeReadOnlySpan_WhenConcat_ResultIsOk()
+    {
+        var values = new string[] { "concat", taintedValue, UntaintedString };
+        ReadOnlySpan<char> span0 = values[0];
+        ReadOnlySpan<char> span1 = values[1];
+        ReadOnlySpan<char> span2 = values[2];
+
+        AssertTaintedFormatWithOriginalCallCheck("concat:+-tainted-+:UntaintedString",
+                  System.String.Concat(span0, span1, span2),
+            () => System.String.Concat(values));
+    }
+
+    [Fact]
+    public void GivenFourReadOnlySpan_WhenConcat_ResultIsOk()
+    {
+        var values = new string[] { "concat", taintedValue, UntaintedString, TaintedString };
+        ReadOnlySpan<char> span0 = values[0];
+        ReadOnlySpan<char> span1 = values[1];
+        ReadOnlySpan<char> span2 = values[2];
+        ReadOnlySpan<char> span3 = values[3];
+
+        AssertTaintedFormatWithOriginalCallCheck("concat:+-tainted-+:UntaintedString:+-TaintedString-+:",
+                  System.String.Concat(span0, span1, span2, span3),
+            () => System.String.Concat(values));
+    }
+
+#endif
 }
 
diff --git a/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringFormatTests.cs b/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringFormatTests.cs
index dd0fa8e42f19..a4be12508109 100644
--- a/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringFormatTests.cs
+++ b/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringFormatTests.cs
@@ -362,7 +362,7 @@ public void GivenANotTaintedFormatObject_WhenCallingFormatWithTaintedObjectNoRep
     }
 
 
-#if NET8_0
+#if NET8_0_OR_GREATER
     // System.String Format(System.IFormatProvider, System.Text.CompositeFormat, System.Object[])
 
     [Fact]
@@ -375,4 +375,114 @@ public void GivenATaintedString_WhenCallingStringFormatObjectArrayFormatProvider
             () => System.String.Format(new FormatProviderForTest(), composite, new object[] { _taintedValue, _untaintedString }).ToString());
     }
 #endif
+
+#if NET9_0_OR_GREATER
+
+    // Testing public static string Format(string format, ReadOnlySpan<object>)
+
+    [Fact]
+    public void GivenATaintedFormatObject_WhenCallingFormatWithObjectReadOnlySpan_ResultIsTainted()
+    {
+        var values = new object[] { _taintedValue, _taintedValue2 };
+        var span = new ReadOnlySpan<object>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-formattaintedTAINTED2-+:",
+            System.String.Format(_taintedFormat2Args, span),
+            () => System.String.Format(_taintedFormat2Args, values));
+    }
+
+    [Fact]
+    public void GivenATaintedFormatObject_WhenCallingFormatWithObjectReadOnlySpan_ResultIsTainted2()
+    {
+        var values = new object[] { _taintedValue, "notTainted" };
+        var span = new ReadOnlySpan<object>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-formattaintednotTainted-+:",
+            System.String.Format(_taintedFormat2Args, span),
+            () => System.String.Format(_taintedFormat2Args, values));
+    }
+
+    [Fact]
+    public void GivenANotTaintedFormatObject_WhenCallingFormatWithObjectReadOnlySpan_ResultIsNotTainted2()
+    {
+        var values = new object[] { "notTainted", "notTainted" };
+        var span = new ReadOnlySpan<object>(values);
+        AssertUntaintedWithOriginalCallCheck("FormatnotTaintednotTainted",
+            System.String.Format("Format{0}{1}", span),
+            () => System.String.Format("Format{0}{1}", values));
+    }
+
+    [Fact]
+    public void GivenATaintedFormatObject_WhenCallingFormatWithObjectReadOnlySpan_ResultIsTainted3()
+    {
+        var values = new object[] { "notTainted", _taintedValue };
+        var span = new ReadOnlySpan<object>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-abcnotTaintedtainted-+:",
+            System.String.Format("abc{0}{1}", span),
+            () => System.String.Format("abc{0}{1}", values));
+    }
+
+    [Fact]
+    public void GivenATaintedFormatObject_WhenCallingFormatWithObjectReadOnlySpan_ResultIsTainted4()
+    {
+        var values = new object[] { "ww", "ww", "ww" };
+        var span = new ReadOnlySpan<object>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-formatwwwwww-+:",
+            System.String.Format(_taintedFormat3Args, span),
+            () => System.String.Format(_taintedFormat3Args, values));
+    }
+
+    // Testing public static string Format(IFormatProvider provider, string format, ReadOnlySpan<object>)
+
+    [Fact]
+    public void GivenATaintedObject_WhenCallingFormatWithProviderAndObjectReadOnlySpan_ResultIsTainted()
+    {
+        var values = new object[] { _taintedValue };
+        var span = new ReadOnlySpan<object>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-test: taintedcustomformat-+:",
+            System.String.Format(new FormatProviderForTest(), "test: {0}", span),
+            () => System.String.Format(new FormatProviderForTest(), "test: {0}", values));
+    }
+
+    [Fact]
+    public void GivenATaintedObject_WhenCallingFormatWithProviderAndObjectReadOnlySpan_ResultIsTainted2()
+    {
+        var values = new object[] { _untaintedString, _taintedValue2 };
+        var span = new ReadOnlySpan<object>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-formatUntaintedStringcustomformatTAINTED2customformat-+:",
+            System.String.Format(new FormatProviderForTest(), _taintedFormat2Args, span),
+            () => System.String.Format(new FormatProviderForTest(), _taintedFormat2Args, values));
+    }
+
+    [Fact]
+    public void GivenATaintedObject_WhenCallingFormatWithProviderAndObjectReadOnlySpan_ResultIsTainted8()
+    {
+        var values = new object[] { _untaintedString, _untaintedString };
+        var span = new ReadOnlySpan<object>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-formatUntaintedStringcustomformatUntaintedStringcustomformat-+:",
+            System.String.Format(new FormatProviderForTest(), _taintedFormat2Args, span),
+            () => System.String.Format(new FormatProviderForTest(), _taintedFormat2Args, values));
+    }
+
+    [Fact]
+    public void GivenATaintedObject_WhenCallingFormatWithProviderAndObjectReadOnlySpan_ResultIsTainted3()
+    {
+        var values = new object[] { _taintedValue, _taintedValue2, _untaintedString, _taintedValue2, _otherUntaintedString };
+        var span = new ReadOnlySpan<object>(values);
+        string str = "Literal with tainteds {0}{1} and untainted {2} and tainted {3} and another untainted {4}";
+        AssertTaintedFormatWithOriginalCallCheck(":+-Literal with tainteds taintedcustomformatTAINTED2customformat and untainted UntaintedStringcustomformat and tainted TAINTED2customformat and another untainted OtherUntaintedStringcustomformat-+:",
+            System.String.Format(new FormatProviderForTest(), str, span),
+            () => System.String.Format(new FormatProviderForTest(), str, values));
+    }
+
+    [Fact]
+    public void GivenATaintedObject_WhenCallingFormatWithProviderAndObjectReadOnlySpan_ResultIsTainted13()
+    {
+        var values = new object[] { "ww" };
+        var span = new ReadOnlySpan<object>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-formatwwcustomformat-+:",
+            System.String.Format(new FormatProviderForTest(), _taintedFormat1Arg, span),
+            () => System.String.Format(new FormatProviderForTest(), _taintedFormat1Arg, values));
+    }
+
+#endif
+
 }
diff --git a/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringJoinTests.cs b/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringJoinTests.cs
index b0c3c52112e6..bd9b6139d43e 100644
--- a/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringJoinTests.cs
+++ b/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringJoinTests.cs
@@ -526,4 +526,48 @@ public void GivenStringJoinTGenericClass_WhenJoin_ResultIsOk()
             string.Join<ClassForStringTest>("|", list),
             () => string.Join<ClassForStringTest>("|", list));
     }
+
+#if NET9_0_OR_GREATER
+
+    [Fact]
+    public void GivenStringAndStringReadOnlySpan_WhenJoin_ResultIsOk()
+    {
+        var values = new string[] { TaintedString, UntaintedString, OtherTaintedString, OtherUntaintedString };
+        var span = new ReadOnlySpan<string>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-TaintedString-+:|UntaintedString|:+-OtherTaintedString-+:|OtherUntaintedString",
+            System.String.Join("|", span),
+            () => System.String.Join("|", values)); // Use values here as we can not use span in the lambda expression
+    }
+
+    [Fact]
+    public void GivenATaintedStringInAStringReadOnlySpan_WhenCallingJoin_ResultIsTainted()
+    {
+        var values = new string[] { taintedValue, taintedValue};
+        var span = new ReadOnlySpan<string>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-tainted-+:a:+-tainted-+:",
+            System.String.Join('a', span),
+            () => System.String.Join('a', values)); // Use values here as we can not use span in the lambda expression
+    }
+
+    [Fact]
+    public void GivenStringAndObjectReadOnlySpan_WhenJoin_ResultIsOk()
+    {
+        var values = new object[] { TaintedString, UntaintedString, OtherTaintedString, 1 };
+        var span = new ReadOnlySpan<object>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-TaintedString-+:|UntaintedString|:+-OtherTaintedString-+:|1",
+            System.String.Join("|", span),
+            () => System.String.Join("|", values)); // Use values here as we can not use span in the lambda expression
+    }
+
+    [Fact]
+    public void GivenATaintedStringInAnObjectReadOnlySpan_WhenCallingJoin_ResultIsTainted()
+    {
+        var values = new object[] { taintedValue, taintedValue, 1 };
+        var span = new ReadOnlySpan<object>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-tainted-+:a:+-tainted-+:a1",
+            System.String.Join('a', span),
+            () => System.String.Join('a', values)); // Use values here as we can not use span in the lambda expression
+    }
+
+#endif
 }
diff --git a/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringSplitTests.cs b/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringSplitTests.cs
index 2af0f759a48b..38556ed603ff 100644
--- a/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringSplitTests.cs
+++ b/tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringSplitTests.cs
@@ -482,5 +482,20 @@ public void GivenATaintedObject_WhenCallingSplitWithCharCountAndOptions_ResultIs
         AssertNoneTainted(_untaintedString.Split('i', 2, StringSplitOptions.None));
     }
 
+#endif
+
+#if NET9_0_OR_GREATER
+
+    [Fact]
+    public void GivenATaintedString_WhenCallingSplitWithCharReadOnlySpan_ResultIsTainted2()
+    {
+        var values = new Char[] { 'n' };
+        var span = new ReadOnlySpan<char>(values);
+        AssertTaintedFormatWithOriginalCallCheck(
+            ":+-tai-+:", 
+            _taintedValue.Split(span)[0], 
+            () => _taintedValue.Split(values)[0]);
+    }
+
 #endif
 }


Reviews:
user: login: robertpi
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-18T11:41:53Z
user: login: e-n-0
body: Thanks a lot 😄
Left a few nits
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-18T13:32:30Z
user: login: zacharycmontoya
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T20:19:23Z
user: login: zacharycmontoya
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T20:50:39Z
user: login: zacharycmontoya
body: LGTM. I left a couple of comments on the implementation, but nothing is blocking from me
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T20:54:45Z
user: login: daniel-romano-DD
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:11:46Z
user: login: daniel-romano-DD
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:11:52Z
user: login: daniel-romano-DD
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:12:01Z
user: login: daniel-romano-DD
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:12:08Z
user: login: andrewlock
body: LGTM, though it's a shame to have to trash the performance by calling `ToArray` everywhere 😢 That would definitely be an unexpected side effect for customers I think, because they could potentially go from using `ReadOnlySpan<T>` for performance reasons, to suddenly getting _worse_ performance than if they'd used the original collection
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-22T08:22:20Z
user: login: daniel-romano-DD
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:36:06Z
user: login: daniel-romano-DD
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:37:23Z

Review comments:
diff_hunk: @@ -512,6 +512,104 @@ public static string Concat<T>(IEnumerable<T> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2)
+    {
+        var result = string.Concat(param1, param2);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: e-n-0
body: I guess the method reported in the error here should be `Concat` instead of `Join`?
created_at: 2025-04-18T13:13:53Z
author_association: MEMBER
diff_hunk: @@ -512,6 +512,104 @@ public static string Concat<T>(IEnumerable<T> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2)
+    {
+        var result = string.Concat(param1, param2);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3)
+    {
+        var result = string.Concat(param1, param2, param3);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <param name="param4"> Fourth param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3, ReadOnlySpan<char> param4)
+    {
+        var result = string.Concat(param1, param2, param3, param4);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3), TaintedObjects.GetString(ref param4)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: e-n-0
body: same here
created_at: 2025-04-18T13:14:34Z
author_association: MEMBER
diff_hunk: @@ -512,6 +512,104 @@ public static string Concat<T>(IEnumerable<T> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2)
+    {
+        var result = string.Concat(param1, param2);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3)
+    {
+        var result = string.Concat(param1, param2, param3);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: e-n-0
body: same here
created_at: 2025-04-18T13:16:55Z
author_association: MEMBER
diff_hunk: @@ -22,6 +22,7 @@
     <!-- as those force choosing the span overloads (which we currently don't support)   -->
     <!-- Once we add support for those overloads, we should remove this   -->
     <LangVersion>12.0</LangVersion>
+    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
path: tracer/test/test-applications/integrations/Samples.InstrumentedTests/Samples.InstrumentedTests.csproj
user: login: e-n-0
body: Is it really needed? Maybe an artefact but might not needed anymore?
created_at: 2025-04-18T13:31:32Z
author_association: MEMBER
diff_hunk: @@ -22,6 +22,7 @@
     <!-- as those force choosing the span overloads (which we currently don't support)   -->
     <!-- Once we add support for those overloads, we should remove this   -->
     <LangVersion>12.0</LangVersion>
+    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
path: tracer/test/test-applications/integrations/Samples.InstrumentedTests/Samples.InstrumentedTests.csproj
user: login: zacharycmontoya
body: +1 I'm surprised to see this here since none of your updates to the test code seem to require it
created_at: 2025-04-18T20:19:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -807,6 +905,66 @@ public static string JoinString(string separator, IEnumerable<string> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="separator"> sparator </param>
+    /// <param name="values"> values to join </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Join(System.String,System.ReadOnlySpan`1<System.String>)")]
+    public static string Join(string separator, ReadOnlySpan<string> values)
+#pragma warning disable DD0005 // Aspect is in incorrect format
+    {
+        return Join(separator, values.ToArray());
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: zacharycmontoya
body: Perhaps this can be done as a follow-up, but can you write a NET6_0_OR_GREATER version of `Join` / `OnStringJoin<T>` to accept and iterate over a `ReadOnlySpan<T>`? I can't see an obvious reason why you couldn't, but maybe I'm missing something
created_at: 2025-04-18T20:50:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -512,6 +512,104 @@ public static string Concat<T>(IEnumerable<T> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2)
+    {
+        var result = string.Concat(param1, param2);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: andrewlock
body: ```suggestion
            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Concat)}");
```
created_at: 2025-04-22T08:03:40Z
author_association: MEMBER
diff_hunk: @@ -512,6 +512,104 @@ public static string Concat<T>(IEnumerable<T> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2)
+    {
+        var result = string.Concat(param1, param2);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3)
+    {
+        var result = string.Concat(param1, param2, param3);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: andrewlock
body: ```suggestion
            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Concat)}");
```
created_at: 2025-04-22T08:04:02Z
author_association: MEMBER
diff_hunk: @@ -512,6 +512,104 @@ public static string Concat<T>(IEnumerable<T> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2)
+    {
+        var result = string.Concat(param1, param2);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3)
+    {
+        var result = string.Concat(param1, param2, param3);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <param name="param4"> Fourth param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3, ReadOnlySpan<char> param4)
+    {
+        var result = string.Concat(param1, param2, param3, param4);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3), TaintedObjects.GetString(ref param4)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: andrewlock
body: ```suggestion
            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Concat)}");
```
created_at: 2025-04-22T08:04:15Z
author_association: MEMBER
diff_hunk: @@ -22,6 +22,7 @@
     <!-- as those force choosing the span overloads (which we currently don't support)   -->
     <!-- Once we add support for those overloads, we should remove this   -->
     <LangVersion>12.0</LangVersion>
+    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
path: tracer/test/test-applications/integrations/Samples.InstrumentedTests/Samples.InstrumentedTests.csproj
user: login: daniel-romano-DD
body: Yep, a leftover from initial implementation testing. Removing it
created_at: 2025-04-22T08:11:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -512,6 +512,104 @@ public static string Concat<T>(IEnumerable<T> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2)
+    {
+        var result = string.Concat(param1, param2);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3)
+    {
+        var result = string.Concat(param1, param2, param3);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: daniel-romano-DD
body: Fixing it
created_at: 2025-04-22T08:11:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -512,6 +512,104 @@ public static string Concat<T>(IEnumerable<T> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2)
+    {
+        var result = string.Concat(param1, param2);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3)
+    {
+        var result = string.Concat(param1, param2, param3);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <param name="param4"> Fourth param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3, ReadOnlySpan<char> param4)
+    {
+        var result = string.Concat(param1, param2, param3, param4);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3), TaintedObjects.GetString(ref param4)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: daniel-romano-DD
body: Fixing it
created_at: 2025-04-22T08:12:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -512,6 +512,104 @@ public static string Concat<T>(IEnumerable<T> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2)
+    {
+        var result = string.Concat(param1, param2);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: daniel-romano-DD
body: Fixing it
created_at: 2025-04-22T08:12:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -512,6 +512,104 @@ public static string Concat<T>(IEnumerable<T> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2)
+    {
+        var result = string.Concat(param1, param2);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3)
+    {
+        var result = string.Concat(param1, param2, param3);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param1"> First param </param>
+    /// <param name="param2"> Second param </param>
+    /// <param name="param3"> Third param </param>
+    /// <param name="param4"> Fourth param </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>)")]
+    public static string Concat(ReadOnlySpan<char> param1, ReadOnlySpan<char> param2, ReadOnlySpan<char> param3, ReadOnlySpan<char> param4)
+    {
+        var result = string.Concat(param1, param2, param3, param4);
+        try
+        {
+            return StringModuleImpl.OnStringConcat(new StringConcatParams(TaintedObjects.GetString(ref param1), TaintedObjects.GetString(ref param2), TaintedObjects.GetString(ref param3), TaintedObjects.GetString(ref param4)), result);
+        }
+        catch (Exception ex)
+        {
+            IastModule.LogAspectException(ex, $"{nameof(StringAspects)}.{nameof(Join)}");
+        }
+
+        return result;
+    }
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="param"> Strings to concat </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Concat(System.ReadOnlySpan`1<System.String>)")]
+    public static string Concat(ReadOnlySpan<string> param)
+#pragma warning disable DD0005 // Aspect is in incorrect format
+    {
+        // TODO: use propper overload when dotnet 9 or later target is available
+        var values = param.ToArray();
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: andrewlock
body: How concerned should we be about the fact that this allocates an array, when the whole purpose of the `Concat(System.ReadOnlySpan`1<System.String>)` call is to _not_ allocate 🤔 

Somewhat unrelated, but I was trying to find the source code for the `Concat(System.ReadOnlySpan`1<System.String>)` call (to see if we could trivially implement it here instead) and couldn't find it anywhere 🤔 
created_at: 2025-04-22T08:15:18Z
author_association: MEMBER
diff_hunk: @@ -807,6 +905,66 @@ public static string JoinString(string separator, IEnumerable<string> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="separator"> sparator </param>
+    /// <param name="values"> values to join </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Join(System.String,System.ReadOnlySpan`1<System.String>)")]
+    public static string Join(string separator, ReadOnlySpan<string> values)
+#pragma warning disable DD0005 // Aspect is in incorrect format
+    {
+        return Join(separator, values.ToArray());
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: andrewlock
body: I was trying to establish the same thing for `Concat(ReadOnlySpan<string>)` above but I think actually the "trivial" implementation is basically [this](https://github.com/dotnet/runtime/blob/1d1bf92fcf43aa6981804dc53c5174445069c9e4/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs#L913-L1001) which is far from trivial 😅 
created_at: 2025-04-22T08:18:04Z
author_association: MEMBER
diff_hunk: @@ -526,4 +526,48 @@ public void GivenStringJoinTGenericClass_WhenJoin_ResultIsOk()
             string.Join<ClassForStringTest>("|", list),
             () => string.Join<ClassForStringTest>("|", list));
     }
+
+#if NET9_0_OR_GREATER
+
+    [Fact]
+    public void GivenStringAndStringReadOnlySpan_WhenJoin_ResultIsOk()
+    {
+        var values = new string[] { TaintedString, UntaintedString, OtherTaintedString, OtherUntaintedString };
+        var span = new ReadOnlySpan<string>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-TaintedString-+:|UntaintedString|:+-OtherTaintedString-+:|OtherUntaintedString",
+            System.String.Join("|", span),
+            () => System.String.Join("|", values)); // Use values here as we can not use span in the lambda expression
+    }
+
+    [Fact]
+    public void GivenATaintedStringInAStringReadOnlySpan_WhenCallingJoin_ResultIsTainted()
+    {
+        var values = new string[] { taintedValue, taintedValue};
+        var span = new ReadOnlySpan<string>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-tainted-+:a:+-tainted-+:",
+            System.String.Join('a', span),
+            () => System.String.Join('a', values)); // Use values here as we can not use span in the lambda expression
path: tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringJoinTests.cs
user: login: andrewlock
body: > // Use values here as we can not use span in the lambda expression

So are we _actually_ testing the code we think we are? 🤔 The lambda is for calculating the "expected" value right? If so then this is fine 👍 
created_at: 2025-04-22T08:20:34Z
author_association: MEMBER
diff_hunk: @@ -807,6 +905,66 @@ public static string JoinString(string separator, IEnumerable<string> values)
         return result;
     }
 
+#if NET6_0_OR_GREATER
+
+    /// <summary>
+    /// String.Join aspect
+    /// </summary>
+    /// <param name="separator"> sparator </param>
+    /// <param name="values"> values to join </param>
+    /// <returns> Join result </returns>
+    [AspectMethodReplace("System.String::Join(System.String,System.ReadOnlySpan`1<System.String>)")]
+    public static string Join(string separator, ReadOnlySpan<string> values)
+#pragma warning disable DD0005 // Aspect is in incorrect format
+    {
+        return Join(separator, values.ToArray());
path: tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs
user: login: daniel-romano-DD
body: I agree. But right now these methods will be called very seldom (if anytime at all), and it would imply duplicating code, so I prefer the lesser evil of an extra alloc for the sake of simplicity. But in the future, when these overloads become more "popular" it's something to consider.
created_at: 2025-04-22T08:36:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -526,4 +526,48 @@ public void GivenStringJoinTGenericClass_WhenJoin_ResultIsOk()
             string.Join<ClassForStringTest>("|", list),
             () => string.Join<ClassForStringTest>("|", list));
     }
+
+#if NET9_0_OR_GREATER
+
+    [Fact]
+    public void GivenStringAndStringReadOnlySpan_WhenJoin_ResultIsOk()
+    {
+        var values = new string[] { TaintedString, UntaintedString, OtherTaintedString, OtherUntaintedString };
+        var span = new ReadOnlySpan<string>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-TaintedString-+:|UntaintedString|:+-OtherTaintedString-+:|OtherUntaintedString",
+            System.String.Join("|", span),
+            () => System.String.Join("|", values)); // Use values here as we can not use span in the lambda expression
+    }
+
+    [Fact]
+    public void GivenATaintedStringInAStringReadOnlySpan_WhenCallingJoin_ResultIsTainted()
+    {
+        var values = new string[] { taintedValue, taintedValue};
+        var span = new ReadOnlySpan<string>(values);
+        AssertTaintedFormatWithOriginalCallCheck(":+-tainted-+:a:+-tainted-+:",
+            System.String.Join('a', span),
+            () => System.String.Join('a', values)); // Use values here as we can not use span in the lambda expression
path: tracer/test/test-applications/integrations/Samples.InstrumentedTests/Propagation/String/StringJoinTests.cs
user: login: daniel-romano-DD
body: That's the case.
created_at: 2025-04-22T08:37:23Z
author_association: CONTRIBUTOR

PR comments:
user: login: datadog-datadog-prod-us1[bot]
created_at: 2025-04-11T17:25:42Z
body: 
# Datadog Report

All test runs `76ea175` [:link:](https://app.datadoghq.com/ci/test-runs?query=%40git.repository.id_v2%3A%22github.com%2Fdatadog%2Fdd-trace-dotnet%22+%40git.commit.sha%3A76ea1753b856f7290e2d809ce101482ab53bf1c6+%40git.branch%3A%22dani%2Fiast%2Fdonet_9_overloads%22&_user_click_origin_=github)

:x: **2 Total Test Services**: 1 Failed, 1 Passed



<details>
<summary>Test Services</summary>

| Service Name | Failed | Known Flaky | New Flaky | Passed | Skipped | Total Time | Test Service View |
| ------------ | ------ | ----------- | --------- | ------ | ------- | --------- | ----------------- |
| [**`dd-trace-dotnet`**](https://app.datadoghq.com/ci/test-commit/github.com%2Fdatadog%2Fdd-trace-dotnet/dd-trace-dotnet/dani%2Fiast%2Fdonet_9_overloads/76ea1753b856f7290e2d809ce101482ab53bf1c6?env=ci&index=citest&_user_click_origin_=github) | 1 | 0 | 0 | 587097 | 5602 | 48h 23m 8.93s |  [Link](https://app.datadoghq.com/ci/test-branch/github.com%2Fdatadog%2Fdd-trace-dotnet/dd-trace-dotnet/dani%2Fiast%2Fdonet_9_overloads?env=ci&index=citest&_user_click_origin_=github) |
| [**`exploration_tests`**](https://app.datadoghq.com/ci/test-commit/github.com%2Fdatadog%2Fdd-trace-dotnet/exploration_tests/dani%2Fiast%2Fdonet_9_overloads/76ea1753b856f7290e2d809ce101482ab53bf1c6?env=none&index=citest&_user_click_origin_=github) | 0 | 0 | 0 | 22085 | 3 | 12m 14.58s |  [Link](https://app.datadoghq.com/ci/test-branch/github.com%2Fdatadog%2Fdd-trace-dotnet/exploration_tests/dani%2Fiast%2Fdonet_9_overloads?env=none&index=citest&_user_click_origin_=github) |
</details>

### :x: Failed Tests (1)

* `MethodProbeTest` - `Datadog.Trace.Debugger.IntegrationTests.ProbesTests` - [Details](https://app.datadoghq.com/ci/test/AwAAAZZculYg303APAAAABhBWlpjdmI3OUFBQWU3UG9VaUlYS3pISUEAAAAkMDE5NjVjYmMtODE5Zi00NjhhLTlkNDctOTliOWRjMmQ0ZGU1AADOKQ?colorBy=service&spanViewType=metadata&env=ci&spanID=8607584707269215766&eventStack=AwAAAZZculYg303APAAAABhBWlpjdmI3OUFBQWU3UG9VaUlYS3pISUEAAAAkMDE5NjVjYmMtODE5Zi00NjhhLTlkNDctOTliOWRjMmQ0ZGU1AADOKQ)

	<details>
	<summary>Expand for error</summary>

	```
	Expected exit code: 0, actual exit code: 139.
	```
	</details>


author_association: NONE
user: login: andrewlock
created_at: 2025-04-11T17:42:54Z
body: ## Execution-Time Benchmarks Report :stopwatch:

Execution-time results for samples comparing the following branches/commits:
- [This PR (6846)](https://github.com/DataDog/dd-trace-dotnet/tree/76ea1753b856f7290e2d809ce101482ab53bf1c6)
- [master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)

Execution-time benchmarks measure the whole time it takes to execute a program. And are intended to measure the one-off costs. Cases where the execution time results for the PR are worse than latest master results are shown in **red**. The following thresholds were used for comparing the execution times:
* Welch test with statistical test for significance of **5%**
* Only results indicating a difference greater than **5%** and **5 ms** are considered.


Note that these results are based on a _single_ point-in-time result for each branch. For full results, see the [dashboard](https://ddstaging.datadoghq.com/dashboard/4qn-6fi-54p/apm-net-execution-time-benchmarks).

Graphs show the p99 interval based on the mean and StdDev of the test run, as well as the mean value of the run (shown as a diamond below the graph).
```mermaid
gantt
    title Execution time (ms) FakeDbCommand (.NET Framework 4.6.2) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (6846) - mean (69ms)  : 67, 71
     .   : milestone, 69,
    master - mean (70ms)  : 64, 77
     .   : milestone, 70,

    section CallTarget+Inlining+NGEN
    This PR (6846) - mean (1,010ms)  : 990, 1030
     .   : milestone, 1010,
    master - mean (1,010ms)  : 984, 1036
     .   : milestone, 1010,

```
```mermaid
gantt
    title Execution time (ms) FakeDbCommand (.NET Core 3.1) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (6846) - mean (103ms)  : 100, 105
     .   : milestone, 103,
    master - mean (103ms)  : 100, 105
     .   : milestone, 103,

    section CallTarget+Inlining+NGEN
    This PR (6846) - mean (692ms)  : 666, 718
     .   : milestone, 692,
    master - mean (697ms)  : 682, 712
     .   : milestone, 697,

```
```mermaid
gantt
    title Execution time (ms) FakeDbCommand (.NET 6) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (6846) - mean (89ms)  : 87, 91
     .   : milestone, 89,
    master - mean (89ms)  : 86, 92
     .   : milestone, 89,

    section CallTarget+Inlining+NGEN
    This PR (6846) - mean (650ms)  : 630, 670
     .   : milestone, 650,
    master - mean (655ms)  : 632, 678
     .   : milestone, 655,

```
```mermaid
gantt
    title Execution time (ms) HttpMessageHandler (.NET Framework 4.6.2) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (6846) - mean (190ms)  : 186, 193
     .   : milestone, 190,
    master - mean (190ms)  : 186, 194
     .   : milestone, 190,

    section CallTarget+Inlining+NGEN
    This PR (6846) - mean (1,107ms)  : 1079, 1136
     .   : milestone, 1107,
    master - mean (1,111ms)  : 1085, 1138
     .   : milestone, 1111,

```
```mermaid
gantt
    title Execution time (ms) HttpMessageHandler (.NET Core 3.1) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (6846) - mean (269ms)  : 265, 272
     .   : milestone, 269,
    master - mean (268ms)  : 265, 272
     .   : milestone, 268,

    section CallTarget+Inlining+NGEN
    This PR (6846) - mean (880ms)  : 849, 910
     .   : milestone, 880,
    master - mean (881ms)  : 848, 914
     .   : milestone, 881,

```
```mermaid
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (6846) - mean (260ms)  : 256, 264
     .   : milestone, 260,
    master - mean (261ms)  : 256, 266
     .   : milestone, 261,

    section CallTarget+Inlining+NGEN
    This PR (6846) - mean (864ms)  : 837, 890
     .   : milestone, 864,
    master - mean (876ms)  : 845, 907
     .   : milestone, 876,

```
author_association: MEMBER
user: login: datadog-ddstaging[bot]
created_at: 2025-04-11T18:02:02Z
body: 
## Datadog Report

Branch report: [`dani/iast/donet_9_overloads`](https://ddstaging.datadoghq.com/ci/test-branch/github.com%2Fdatadog%2Fdd-trace-dotnet/dd-trace-dotnet/dani%2Fiast%2Fdonet_9_overloads?env=ci&index=citest&_user_click_origin_=github)
Commit report: [`1ad929c`](https://ddstaging.datadoghq.com/ci/test-commit/github.com%2Fdatadog%2Fdd-trace-dotnet/dd-trace-dotnet/dani%2Fiast%2Fdonet_9_overloads/1ad929c6bf1100b5943257df44da58840355a581?env=ci&index=citest&_user_click_origin_=github)
Test service: `dd-trace-dotnet`

:white_check_mark: 0 Failed, 6 Passed, 0 Skipped, 0s Total Time




author_association: NONE
user: login: andrewlock
created_at: 2025-04-11T18:06:42Z
body: ## Benchmarks Report for appsec :snail:

Benchmarks for #6846 compared to [master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394): 
* 3 benchmarks are **slower**, with geometric mean 1.189
* 1 benchmarks have **more** allocations


The following thresholds were used for comparing the benchmark speeds:
* Mann–Whitney U test with statistical test for significance of **5%**
* Only results indicating a difference greater than **10%** and **0.3 ns** are considered.

Allocation changes below **0.5%** are ignored.


### Benchmark details


<details><summary><strong>Benchmarks.Trace.Asm.AppSecBodyBenchmark</strong> - Slower :warning: Same allocations :heavy_check_mark:



#### Slower :warning: in #6846

|  Benchmark         | diff/base | Base Median (ns) | Diff Median (ns) | Modality   |
|:----------|-----------:|-----------:|--------:|--------:|
| Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody&#8209;net472 | 1.196 | 3,542.11 | 4,238.11 | 

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`AllCycleSimpleBody`|net6.0|211μs|179ns|646ns|2.13| 0|0|196.71&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`AllCycleSimpleBody`|netcoreapp3.1|313μs|347ns|1.34μs|1.99| 0|0|204.37&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`AllCycleSimpleBody`|net472|284μs|524ns|2.03μs|37.1| 1.43|0|237.3&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`AllCycleMoreComplexBody`|net6.0|213μs|139ns|518ns|2.14| 0|0|200.21&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`AllCycleMoreComplexBody`|netcoreapp3.1|329μs|451ns|1.63μs|1.81| 0|0|207.78&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`AllCycleMoreComplexBody`|net472|290μs|272ns|1.05μs|37.4| 1.44|0|240.82&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`ObjectExtractorSimpleBody`|net6.0|145ns|0.187ns|0.7ns|0.00374| 0|0|280&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`ObjectExtractorSimpleBody`|netcoreapp3.1|199ns|0.187ns|0.723ns|0.00296| 0|0|272&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`ObjectExtractorSimpleBody`|net472|168ns|0.195ns|0.756ns|0.0444| 0|0|281&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`ObjectExtractorMoreComplexBody`|net6.0|2.96μs|3.19ns|11.9ns|0.0443| 0|0|3.78&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`ObjectExtractorMoreComplexBody`|netcoreapp3.1|3.8μs|4.31ns|15.5ns|0.038| 0|0|3.69&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`ObjectExtractorMoreComplexBody`|net472|3.55μs|4.73ns|18.3ns|0.603| 0|0|3.8&nbsp;KB|
|#6846|`AllCycleSimpleBody`|net6.0|208μs|181ns|652ns|2.08| 0|0|196.71&nbsp;KB|
|#6846|`AllCycleSimpleBody`|netcoreapp3.1|318μs|313ns|1.21μs|1.73| 0|0|204.37&nbsp;KB|
|#6846|`AllCycleSimpleBody`|net472|280μs|335ns|1.3μs|36.7| 1.41|0|237.31&nbsp;KB|
|#6846|`AllCycleMoreComplexBody`|net6.0|223μs|91ns|341ns|2.2| 0|0|200.21&nbsp;KB|
|#6846|`AllCycleMoreComplexBody`|netcoreapp3.1|316μs|383ns|1.43μs|1.73| 0|0|207.78&nbsp;KB|
|#6846|`AllCycleMoreComplexBody`|net472|290μs|359ns|1.34μs|37.6| 1.45|0|240.82&nbsp;KB|
|#6846|`ObjectExtractorSimpleBody`|net6.0|135ns|0.245ns|0.949ns|0.00342| 0|0|280&nbsp;B|
|#6846|`ObjectExtractorSimpleBody`|netcoreapp3.1|197ns|0.273ns|1.02ns|0.00296| 0|0|272&nbsp;B|
|#6846|`ObjectExtractorSimpleBody`|net472|176ns|0.523ns|2.02ns|0.0441| 0|0|281&nbsp;B|
|#6846|`ObjectExtractorMoreComplexBody`|net6.0|2.92μs|3.02ns|11.7ns|0.0437| 0|0|3.78&nbsp;KB|
|#6846|`ObjectExtractorMoreComplexBody`|netcoreapp3.1|3.8μs|3.57ns|13.4ns|0.038| 0|0|3.69&nbsp;KB|
|#6846|`ObjectExtractorMoreComplexBody`|net472|4.24μs|3.44ns|12.4ns|0.593| 0|0|3.8&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.Asm.AppSecEncoderBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EncodeArgs`|net6.0|37.4μs|54.8ns|212ns|0.374| 0|0|32.4&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EncodeArgs`|netcoreapp3.1|53.3μs|30.7ns|106ns|0.266| 0|0|32.4&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EncodeArgs`|net472|65.6μs|97.2ns|377ns|4.85| 0|0|32.51&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EncodeLegacyArgs`|net6.0|73.1μs|38.4ns|149ns|0| 0|0|2.14&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EncodeLegacyArgs`|netcoreapp3.1|107μs|70ns|262ns|0| 0|0|2.14&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EncodeLegacyArgs`|net472|152μs|49ns|183ns|0| 0|0|2.15&nbsp;KB|
|#6846|`EncodeArgs`|net6.0|38.5μs|38ns|137ns|0.383| 0|0|32.4&nbsp;KB|
|#6846|`EncodeArgs`|netcoreapp3.1|54.1μs|57.1ns|206ns|0.269| 0|0|32.4&nbsp;KB|
|#6846|`EncodeArgs`|net472|65.2μs|101ns|391ns|4.86| 0|0|32.51&nbsp;KB|
|#6846|`EncodeLegacyArgs`|net6.0|71.3μs|28.2ns|105ns|0| 0|0|2.14&nbsp;KB|
|#6846|`EncodeLegacyArgs`|netcoreapp3.1|105μs|226ns|847ns|0| 0|0|2.14&nbsp;KB|
|#6846|`EncodeLegacyArgs`|net472|151μs|59ns|229ns|0| 0|0|2.15&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.Asm.AppSecWafBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`RunWafRealisticBenchmark`|net6.0|174μs|190ns|736ns|0| 0|0|2.54&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`RunWafRealisticBenchmark`|netcoreapp3.1|184μs|307ns|1.19μs|0| 0|0|2.49&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`RunWafRealisticBenchmark`|net472|199μs|136ns|508ns|0| 0|0|2.55&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`RunWafRealisticBenchmarkWithAttack`|net6.0|114μs|256ns|993ns|0| 0|0|1.57&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`RunWafRealisticBenchmarkWithAttack`|netcoreapp3.1|124μs|398ns|1.54μs|0| 0|0|1.55&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`RunWafRealisticBenchmarkWithAttack`|net472|131μs|58.1ns|209ns|0| 0|0|1.58&nbsp;KB|
|#6846|`RunWafRealisticBenchmark`|net6.0|173μs|102ns|367ns|0| 0|0|2.54&nbsp;KB|
|#6846|`RunWafRealisticBenchmark`|netcoreapp3.1|183μs|276ns|996ns|0| 0|0|2.49&nbsp;KB|
|#6846|`RunWafRealisticBenchmark`|net472|199μs|366ns|1.32μs|0| 0|0|2.56&nbsp;KB|
|#6846|`RunWafRealisticBenchmarkWithAttack`|net6.0|114μs|69.3ns|259ns|0| 0|0|1.57&nbsp;KB|
|#6846|`RunWafRealisticBenchmarkWithAttack`|netcoreapp3.1|122μs|226ns|876ns|0| 0|0|1.55&nbsp;KB|
|#6846|`RunWafRealisticBenchmarkWithAttack`|net472|131μs|224ns|774ns|0| 0|0|1.58&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.Iast.StringAspectsBenchmark</strong> - Slower :warning: More allocations :warning:



#### Slower :warning: in #6846

|  Benchmark         | diff/base | Base Median (ns) | Diff Median (ns) | Modality   |
|:----------|-----------:|-----------:|--------:|--------:|
| Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark&#8209;net6.0 | 1.200 | 52,200.00 | 62,650.00 | bimodal
| Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark&#8209;netcoreapp3.1 | 1.169 | 53,450.00 | 62,500.00 | bimodal



#### More allocations :warning: in #6846

|  Benchmark         | Base Allocated | Diff Allocated | Change   | Change % |
|:----------|-----------:|-----------:|--------:|--------:|
| Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark&#8209;net472 | 58.04 KB | 61.7 KB | 3.66 KB | 6.31%

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StringConcatBenchmark`|net6.0|52.4μs|263ns|1.14μs|0| 0|0|43.44&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StringConcatBenchmark`|netcoreapp3.1|53.4μs|252ns|1.01μs|0| 0|0|42.64&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StringConcatBenchmark`|net472|37.1μs|60.4ns|218ns|0| 0|0|58.04&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StringConcatAspectBenchmark`|net6.0|325μs|1.67μs|12.4μs|0| 0|0|256.13&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StringConcatAspectBenchmark`|netcoreapp3.1|345μs|1.88μs|11.1μs|0| 0|0|255.18&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StringConcatAspectBenchmark`|net472|283μs|6.43μs|61.7μs|0| 0|0|278.53&nbsp;KB|
|#6846|`StringConcatBenchmark`|net6.0|63.7μs|988ns|9.78μs|0| 0|0|43.44&nbsp;KB|
|#6846|`StringConcatBenchmark`|netcoreapp3.1|63.5μs|824ns|8.08μs|0| 0|0|42.64&nbsp;KB|
|#6846|`StringConcatBenchmark`|net472|36μs|87.4ns|327ns|0| 0|0|61.7&nbsp;KB|
|#6846|`StringConcatAspectBenchmark`|net6.0|294μs|6.36μs|62.7μs|0| 0|0|255.94&nbsp;KB|
|#6846|`StringConcatAspectBenchmark`|netcoreapp3.1|355μs|1.76μs|10.6μs|0| 0|0|255.36&nbsp;KB|
|#6846|`StringConcatAspectBenchmark`|net472|303μs|8.06μs|79.8μs|0| 0|0|278.53&nbsp;KB|
</details>


author_association: MEMBER
user: login: andrewlock
created_at: 2025-04-11T18:14:12Z
body: ## Benchmarks Report for tracer :snail:

Benchmarks for #6846 compared to [master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394): 
* All benchmarks have **the same** speed
* 2 benchmarks have **fewer** allocations


The following thresholds were used for comparing the benchmark speeds:
* Mann–Whitney U test with statistical test for significance of **5%**
* Only results indicating a difference greater than **10%** and **0.3 ns** are considered.

Allocation changes below **0.5%** are ignored.


### Benchmark details


<details><summary><strong>Benchmarks.Trace.ActivityBenchmark</strong> - Same speed :heavy_check_mark: Fewer allocations :tada:



#### Fewer allocations :tada: in #6846

|  Benchmark         | Base Allocated | Diff Allocated | Change   | Change % |
|:----------|-----------:|-----------:|--------:|--------:|
| Benchmarks.Trace.ActivityBenchmark.StartStopWithChild&#8209;netcoreapp3.1 | 5.8 KB | 5.76 KB | -42 B | -0.72%

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StartStopWithChild`|net6.0|7.65μs|99.5ns|995ns|0| 0|0|5.58&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StartStopWithChild`|netcoreapp3.1|10.3μs|87.9ns|848ns|0| 0|0|5.8&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StartStopWithChild`|net472|15.4μs|84.9ns|537ns|0.971| 0.299|0.0747|6.11&nbsp;KB|
|#6846|`StartStopWithChild`|net6.0|8.36μs|154ns|1.54μs|0| 0|0|5.58&nbsp;KB|
|#6846|`StartStopWithChild`|netcoreapp3.1|10μs|143ns|1.43μs|0| 0|0|5.76&nbsp;KB|
|#6846|`StartStopWithChild`|net472|15.4μs|84.7ns|479ns|1| 0.308|0.0771|6.1&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.AgentWriterBenchmark</strong> - Same speed :heavy_check_mark: Fewer allocations :tada:



#### Fewer allocations :tada: in #6846

|  Benchmark         | Base Allocated | Diff Allocated | Change   | Change % |
|:----------|-----------:|-----------:|--------:|--------:|
| Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces&#8209;net472 | 3.35 KB | 3.31 KB | -34 B | -1.02%

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`WriteAndFlushEnrichedTraces`|net6.0|500μs|450ns|1.56μs|0| 0|0|2.71&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`WriteAndFlushEnrichedTraces`|netcoreapp3.1|666μs|3.42μs|15.3μs|0| 0|0|2.7&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`WriteAndFlushEnrichedTraces`|net472|849μs|1.18μs|4.41μs|0| 0|0|3.35&nbsp;KB|
|#6846|`WriteAndFlushEnrichedTraces`|net6.0|505μs|1.19μs|4.46μs|0| 0|0|2.7&nbsp;KB|
|#6846|`WriteAndFlushEnrichedTraces`|netcoreapp3.1|674μs|842ns|3.15μs|0| 0|0|2.7&nbsp;KB|
|#6846|`WriteAndFlushEnrichedTraces`|net472|854μs|1.88μs|7.03μs|0| 0|0|3.31&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.AspNetCoreBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`SendRequest`|net6.0|126μs|732ns|6.04μs|0| 0|0|14.48&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`SendRequest`|netcoreapp3.1|146μs|803ns|4.54μs|0| 0|0|17.28&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`SendRequest`|net472|0.00235ns|0.00077ns|0.00298ns|0| 0|0|0&nbsp;b|
|#6846|`SendRequest`|net6.0|130μs|684ns|3.42μs|0| 0|0|14.48&nbsp;KB|
|#6846|`SendRequest`|netcoreapp3.1|143μs|780ns|4.74μs|0| 0|0|17.28&nbsp;KB|
|#6846|`SendRequest`|net472|0.00372ns|0.0012ns|0.00464ns|0| 0|0|0&nbsp;b|
</details>


<details><summary><strong>Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`WriteAndFlushEnrichedTraces`|net6.0|646μs|7.81μs|77.7μs|0| 0|0|41.56&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`WriteAndFlushEnrichedTraces`|netcoreapp3.1|754μs|10.7μs|106μs|0| 0|0|41.67&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`WriteAndFlushEnrichedTraces`|net472|886μs|5.4μs|54μs|8.33| 4.17|0|53.39&nbsp;KB|
|#6846|`WriteAndFlushEnrichedTraces`|net6.0|661μs|9.34μs|93.4μs|0| 0|0|41.55&nbsp;KB|
|#6846|`WriteAndFlushEnrichedTraces`|netcoreapp3.1|815μs|14μs|140μs|0| 0|0|41.81&nbsp;KB|
|#6846|`WriteAndFlushEnrichedTraces`|net472|908μs|7.32μs|72.9μs|7.81| 3.91|0|53.38&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.DbCommandBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`ExecuteNonQuery`|net6.0|1.38μs|2.96ns|11.1ns|0.0136| 0|0|1.03&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`ExecuteNonQuery`|netcoreapp3.1|1.76μs|5.04ns|18.9ns|0.00874| 0|0|1.02&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`ExecuteNonQuery`|net472|2.07μs|3.48ns|13ns|0.154| 0.0103|0|995&nbsp;B|
|#6846|`ExecuteNonQuery`|net6.0|1.39μs|5.34ns|20.7ns|0.0137| 0|0|1.03&nbsp;KB|
|#6846|`ExecuteNonQuery`|netcoreapp3.1|1.82μs|3.85ns|14.4ns|0.00906| 0|0|1.02&nbsp;KB|
|#6846|`ExecuteNonQuery`|net472|2.13μs|5.15ns|19.3ns|0.148| 0.0106|0|995&nbsp;B|
</details>


<details><summary><strong>Benchmarks.Trace.ElasticsearchBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`CallElasticsearch`|net6.0|1.25μs|1.08ns|4.2ns|0.0127| 0|0|984&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`CallElasticsearch`|netcoreapp3.1|1.59μs|1.46ns|5.25ns|0.008| 0|0|984&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`CallElasticsearch`|net472|2.6μs|1.75ns|6.79ns|0.156| 0|0|1&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`CallElasticsearchAsync`|net6.0|1.22μs|0.757ns|2.93ns|0.0122| 0|0|960&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`CallElasticsearchAsync`|netcoreapp3.1|1.67μs|1.76ns|6.6ns|0.00847| 0|0|1.03&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`CallElasticsearchAsync`|net472|2.71μs|1.37ns|5.29ns|0.164| 0|0|1.06&nbsp;KB|
|#6846|`CallElasticsearch`|net6.0|1.19μs|4.89ns|17.6ns|0.0118| 0|0|984&nbsp;B|
|#6846|`CallElasticsearch`|netcoreapp3.1|1.61μs|1.56ns|5.39ns|0.00796| 0|0|984&nbsp;B|
|#6846|`CallElasticsearch`|net472|2.54μs|1.32ns|4.92ns|0.152| 0|0|1&nbsp;KB|
|#6846|`CallElasticsearchAsync`|net6.0|1.35μs|2.56ns|9.23ns|0.0135| 0|0|960&nbsp;B|
|#6846|`CallElasticsearchAsync`|netcoreapp3.1|1.63μs|2.16ns|7.8ns|0.00818| 0|0|1.03&nbsp;KB|
|#6846|`CallElasticsearchAsync`|net472|2.81μs|0.992ns|3.71ns|0.155| 0|0|1.06&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.GraphQLBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`ExecuteAsync`|net6.0|1.3μs|1.66ns|6.42ns|0.013| 0|0|960&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`ExecuteAsync`|netcoreapp3.1|1.68μs|1.28ns|4.95ns|0.00839| 0|0|960&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`ExecuteAsync`|net472|1.88μs|1.11ns|4.32ns|0.141| 0|0|923&nbsp;B|
|#6846|`ExecuteAsync`|net6.0|1.36μs|1.79ns|6.71ns|0.0135| 0|0|960&nbsp;B|
|#6846|`ExecuteAsync`|netcoreapp3.1|1.69μs|1.2ns|4.33ns|0.00837| 0|0|960&nbsp;B|
|#6846|`ExecuteAsync`|net472|1.84μs|0.571ns|2.14ns|0.138| 0|0|923&nbsp;B|
</details>


<details><summary><strong>Benchmarks.Trace.HttpClientBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`SendAsync`|net6.0|4.42μs|4.17ns|15ns|0.0221| 0|0|2.32&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`SendAsync`|netcoreapp3.1|5.35μs|5.7ns|21.3ns|0.0267| 0|0|2.86&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`SendAsync`|net472|7.59μs|7.6ns|29.4ns|0.492| 0|0|3.13&nbsp;KB|
|#6846|`SendAsync`|net6.0|4.42μs|1.6ns|5.98ns|0.022| 0|0|2.32&nbsp;KB|
|#6846|`SendAsync`|netcoreapp3.1|5.61μs|20.4ns|76.2ns|0.0271| 0|0|2.86&nbsp;KB|
|#6846|`SendAsync`|net472|7.45μs|5.49ns|21.3ns|0.483| 0|0|3.13&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.ILoggerBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EnrichedLog`|net6.0|1.65μs|1.59ns|6.15ns|0.0248| 0|0|1.71&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EnrichedLog`|netcoreapp3.1|2.35μs|2.1ns|7.85ns|0.0118| 0|0|1.71&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EnrichedLog`|net472|2.56μs|2.09ns|8.08ns|0.256| 0|0|1.64&nbsp;KB|
|#6846|`EnrichedLog`|net6.0|1.67μs|1.32ns|5.13ns|0.0168| 0|0|1.71&nbsp;KB|
|#6846|`EnrichedLog`|netcoreapp3.1|2.19μs|2.5ns|9.36ns|0.0217| 0|0|1.71&nbsp;KB|
|#6846|`EnrichedLog`|net472|2.46μs|1.38ns|4.96ns|0.259| 0|0|1.64&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.Log4netBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EnrichedLog`|net6.0|112μs|211ns|760ns|0| 0|0|4.32&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EnrichedLog`|netcoreapp3.1|116μs|245ns|948ns|0| 0|0|4.32&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EnrichedLog`|net472|153μs|376ns|1.46μs|0| 0|0|4.51&nbsp;KB|
|#6846|`EnrichedLog`|net6.0|112μs|374ns|1.45μs|0| 0|0|4.32&nbsp;KB|
|#6846|`EnrichedLog`|netcoreapp3.1|116μs|180ns|697ns|0| 0|0|4.32&nbsp;KB|
|#6846|`EnrichedLog`|net472|150μs|214ns|831ns|0| 0|0|4.51&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.NLogBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EnrichedLog`|net6.0|3μs|4.34ns|16.8ns|0.0301| 0|0|2.26&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EnrichedLog`|netcoreapp3.1|4.09μs|4.5ns|17.4ns|0.0205| 0|0|2.26&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EnrichedLog`|net472|4.97μs|3.15ns|12.2ns|0.323| 0|0|2.09&nbsp;KB|
|#6846|`EnrichedLog`|net6.0|3.18μs|1.83ns|6.83ns|0.0318| 0|0|2.26&nbsp;KB|
|#6846|`EnrichedLog`|netcoreapp3.1|4.28μs|1.86ns|6.97ns|0.0217| 0|0|2.26&nbsp;KB|
|#6846|`EnrichedLog`|net472|4.74μs|3.36ns|13ns|0.309| 0|0|2.09&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.RedisBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`SendReceive`|net6.0|1.29μs|0.856ns|3.31ns|0.0129| 0|0|1.15&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`SendReceive`|netcoreapp3.1|1.8μs|2.61ns|9.77ns|0.00892| 0|0|1.15&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`SendReceive`|net472|2.07μs|0.899ns|3.48ns|0.176| 0|0|1.16&nbsp;KB|
|#6846|`SendReceive`|net6.0|1.27μs|0.524ns|1.89ns|0.0126| 0|0|1.15&nbsp;KB|
|#6846|`SendReceive`|netcoreapp3.1|1.83μs|1.34ns|5.01ns|0.00909| 0|0|1.15&nbsp;KB|
|#6846|`SendReceive`|net472|2.07μs|0.915ns|3.42ns|0.175| 0|0|1.16&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.SerilogBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EnrichedLog`|net6.0|2.78μs|1.59ns|6.15ns|0.014| 0|0|1.64&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EnrichedLog`|netcoreapp3.1|3.98μs|1.71ns|5.93ns|0.0198| 0|0|1.69&nbsp;KB|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`EnrichedLog`|net472|4.5μs|4.44ns|17.2ns|0.315| 0|0|2.08&nbsp;KB|
|#6846|`EnrichedLog`|net6.0|2.73μs|3.93ns|14.2ns|0.0136| 0|0|1.64&nbsp;KB|
|#6846|`EnrichedLog`|netcoreapp3.1|3.99μs|1.95ns|7.28ns|0.02| 0|0|1.69&nbsp;KB|
|#6846|`EnrichedLog`|net472|4.47μs|2.63ns|9.84ns|0.312| 0|0|2.08&nbsp;KB|
</details>


<details><summary><strong>Benchmarks.Trace.SpanBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StartFinishSpan`|net6.0|421ns|0.288ns|1.12ns|0.0084| 0|0|584&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StartFinishSpan`|netcoreapp3.1|637ns|0.455ns|1.7ns|0.00635| 0|0|584&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StartFinishSpan`|net472|674ns|0.157ns|0.568ns|0.0912| 0|0|586&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StartFinishScope`|net6.0|517ns|0.31ns|1.2ns|0.00774| 0|0|704&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StartFinishScope`|netcoreapp3.1|734ns|1.03ns|3.72ns|0.00729| 0|0|704&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`StartFinishScope`|net472|827ns|0.448ns|1.74ns|0.104| 0|0|666&nbsp;B|
|#6846|`StartFinishSpan`|net6.0|448ns|0.191ns|0.713ns|0.00673| 0|0|584&nbsp;B|
|#6846|`StartFinishSpan`|netcoreapp3.1|619ns|0.451ns|1.69ns|0.00626| 0|0|584&nbsp;B|
|#6846|`StartFinishSpan`|net472|632ns|0.438ns|1.7ns|0.0923| 0|0|586&nbsp;B|
|#6846|`StartFinishScope`|net6.0|479ns|0.364ns|1.31ns|0.00952| 0|0|704&nbsp;B|
|#6846|`StartFinishScope`|netcoreapp3.1|768ns|0.724ns|2.81ns|0.00776| 0|0|704&nbsp;B|
|#6846|`StartFinishScope`|net472|854ns|0.584ns|2.26ns|0.102| 0|0|666&nbsp;B|
</details>


<details><summary><strong>Benchmarks.Trace.TraceAnnotationsBenchmark</strong> - Same speed :heavy_check_mark: Same allocations :heavy_check_mark:

</summary>

### Raw results


|  Branch |                      Method |     Toolchain |     Mean | StdError |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------|---------------------------- |-------------- |---------:|---------:|--------:|-------:|------:|------:|----------:|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`RunOnMethodBegin`|net6.0|628ns|0.836ns|3.24ns|0.00938| 0|0|704&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`RunOnMethodBegin`|netcoreapp3.1|970ns|1.72ns|6.67ns|0.00487| 0|0|704&nbsp;B|
|[master](https://github.com/DataDog/dd-trace-dotnet/tree/d718df82027e18894d1a83aab5b0cf931a63d394)|`RunOnMethodBegin`|net472|1.14μs|0.881ns|3.41ns|0.102| 0|0|666&nbsp;B|
|#6846|`RunOnMethodBegin`|net6.0|659ns|0.53ns|1.91ns|0.00977| 0|0|704&nbsp;B|
|#6846|`RunOnMethodBegin`|netcoreapp3.1|950ns|1.25ns|4.67ns|0.00479| 0|0|704&nbsp;B|
|#6846|`RunOnMethodBegin`|net472|1.07μs|0.39ns|1.46ns|0.101| 0|0|666&nbsp;B|
</details>


author_association: MEMBER