From 1ad93b5e4883d289b233c2d87ea217393cb88ab3 Mon Sep 17 00:00:00 2001 From: Gregory LEOCADIE Date: Thu, 25 Jul 2024 18:40:03 +0200 Subject: [PATCH] Add specific test --- .../Samples.Computer01/ComputerService.cs | 20 +++ .../LinuxDlIteratePhdrDeadlock.cs | 124 ++++++++++++++++++ .../src/Demos/Samples.Computer01/Program.cs | 2 + .../LinuxOnly/DlIteratePhdrDeadlock.cs | 31 +++++ 4 files changed, 177 insertions(+) create mode 100644 profiler/src/Demos/Samples.Computer01/LinuxDlIteratePhdrDeadlock.cs create mode 100644 profiler/test/Datadog.Profiler.IntegrationTests/LinuxOnly/DlIteratePhdrDeadlock.cs diff --git a/profiler/src/Demos/Samples.Computer01/ComputerService.cs b/profiler/src/Demos/Samples.Computer01/ComputerService.cs index d51a9cff3974..07b51146409f 100644 --- a/profiler/src/Demos/Samples.Computer01/ComputerService.cs +++ b/profiler/src/Demos/Samples.Computer01/ComputerService.cs @@ -44,6 +44,7 @@ public class ComputerService private NullThreadNameBugCheck _nullThreadNameBugCheck; private MethodsSignature _methodsSignature; private SigSegvHandlerExecution _sigsegvHandler; + private LinuxDlIteratePhdrDeadlock _linuxDlIteratePhdrDeadlock; #if NET5_0_OR_GREATER private OpenLdapCrash _openldapCrash; @@ -181,6 +182,10 @@ public void StartService(Scenario scenario, int nbThreads, int parameter) StartStringConcat(parameter); break; + case Scenario.LinuxDlIteratePhdrDeadlock: + StartLinuxDlIteratePhdrDeadlock(); + break; + default: throw new ArgumentOutOfRangeException(nameof(scenario), $"Unsupported scenario #{_scenario}"); } @@ -311,6 +316,10 @@ public void StopService() case Scenario.StringConcat: StopStringConcat(); break; + + case Scenario.LinuxDlIteratePhdrDeadlock: + StopLinuxDlIteratePhdrDeadlock(); + break; } } @@ -575,6 +584,12 @@ private void StartLinuxMallocDeadlock() _linuxMallockDeadlock.Start(); } + private void StartLinuxDlIteratePhdrDeadlock() + { + _linuxDlIteratePhdrDeadlock = new LinuxDlIteratePhdrDeadlock(); + _linuxDlIteratePhdrDeadlock.Start(); + } + private void StartMeasureAllocations() { _measureAllocations = new MeasureAllocations(); @@ -749,6 +764,11 @@ private void StopLinuxMallocDeadlock() _linuxMallockDeadlock.Stop(); } + private void StopLinuxDlIteratePhdrDeadlock() + { + _linuxDlIteratePhdrDeadlock.Stop(); + } + private void StopMeasureAllocations() { _measureAllocations.Stop(); diff --git a/profiler/src/Demos/Samples.Computer01/LinuxDlIteratePhdrDeadlock.cs b/profiler/src/Demos/Samples.Computer01/LinuxDlIteratePhdrDeadlock.cs new file mode 100644 index 000000000000..3e9f9a077418 --- /dev/null +++ b/profiler/src/Demos/Samples.Computer01/LinuxDlIteratePhdrDeadlock.cs @@ -0,0 +1,124 @@ +// +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2022 Datadog, Inc. +// + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Samples.Computer01 +{ + internal class LinuxDlIteratePhdrDeadlock + { + private ManualResetEvent _stopEvent; + private Task _exceptionTask; + private Thread _worker; + + public void Start() + { + if (_stopEvent != null) + { + throw new InvalidOperationException("Already running..."); + } + + _stopEvent = new ManualResetEvent(false); + + _worker = new Thread(ExecuteCallToDlOpenDlClose) + { + IsBackground = false // set to false to prevent the app from shutting down. The test will fail + }; + _worker.Start(); + + _exceptionTask = Task.Factory.StartNew( + () => + { + var nbException = 0; + var loggingClock = Stopwatch.StartNew(); + while (!IsEventSet()) + { + if (loggingClock.ElapsedMilliseconds >= 1000) + { + Console.WriteLine($"* Nb thrown exception {nbException}"); + Thread.Sleep(TimeSpan.FromMilliseconds(500)); + nbException = 0; + loggingClock.Restart(); + } + + for (var i = 0; i < 20; i++) + { + try + { + throw new Exception("dl_iterate_phdr deadlock exception"); + } + catch { } + nbException++; + } + + // wait a bit randomly (23 is a prime number chosen randomly) + Thread.Sleep(TimeSpan.FromMilliseconds(23)); + } + }, + TaskCreationOptions.LongRunning); + } + + public void Run() + { + Start(); + Thread.Sleep(TimeSpan.FromSeconds(10)); + Stop(); + } + + public void Stop() + { + if (_stopEvent == null) + { + throw new InvalidOperationException("Not running..."); + } + + _stopEvent.Set(); + + _worker.Join(); + _exceptionTask.Wait(); + + _stopEvent.Dispose(); + _stopEvent = null; + } + + [DllImport("libdl.so", EntryPoint = "dlopen")] + private static extern IntPtr Dlopen(string filename, int flags); + + [DllImport("libdl.so", EntryPoint = "dlclose")] + private static extern void DlClose(IntPtr handle); + + private void ExecuteCallToDlOpenDlClose() + { + var loggingClock = Stopwatch.StartNew(); + var counter = 0; + + while (!IsEventSet()) + { + if (loggingClock.ElapsedMilliseconds >= 1000) + { + Console.WriteLine($"* Nb execution {counter}"); + Thread.Sleep(TimeSpan.FromMilliseconds(500)); + counter = 0; + loggingClock.Restart(); + } + + var handle = Dlopen("libc.so.6", 2); + Thread.Sleep(TimeSpan.FromMilliseconds(10)); + DlClose(handle); + + counter++; + } + } + + private bool IsEventSet() + { + return _stopEvent.WaitOne(0); + } + } +} diff --git a/profiler/src/Demos/Samples.Computer01/Program.cs b/profiler/src/Demos/Samples.Computer01/Program.cs index 6a4f069fbc5f..7bbd13de7b3d 100644 --- a/profiler/src/Demos/Samples.Computer01/Program.cs +++ b/profiler/src/Demos/Samples.Computer01/Program.cs @@ -40,6 +40,7 @@ public enum Scenario Obfuscation, ThreadSpikes, StringConcat, // parameter = number of strings to concatenate + LinuxDlIteratePhdrDeadlock, } public class Program @@ -76,6 +77,7 @@ public static void Main(string[] args) // 24: use an obfuscated library // 25: create thread spikes // 26: string concatenation + // 27: custom dl_iterate_phdr deadlock // Console.WriteLine($"{Environment.NewLine}Usage:{Environment.NewLine} > {Process.GetCurrentProcess().ProcessName} " + $"[--service] [--iterations ] " + diff --git a/profiler/test/Datadog.Profiler.IntegrationTests/LinuxOnly/DlIteratePhdrDeadlock.cs b/profiler/test/Datadog.Profiler.IntegrationTests/LinuxOnly/DlIteratePhdrDeadlock.cs new file mode 100644 index 000000000000..76be5a594e2d --- /dev/null +++ b/profiler/test/Datadog.Profiler.IntegrationTests/LinuxOnly/DlIteratePhdrDeadlock.cs @@ -0,0 +1,31 @@ +// +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2022 Datadog, Inc. +// + +using Datadog.Profiler.IntegrationTests.Helpers; +using Datadog.Profiler.SmokeTests; +using Xunit; +using Xunit.Abstractions; + +namespace Datadog.Profiler.IntegrationTests.LinuxOnly +{ + [Trait("Category", "LinuxOnly")] + public class DlIteratePhdrDeadlock + { + private const string ScenarioLinuxDliteratePhdrDeadlock = "--scenario 27"; + private readonly ITestOutputHelper _output; + + public DlIteratePhdrDeadlock(ITestOutputHelper output) + { + _output = output; + } + + [TestAppFact("Samples.Computer01")] + public void CheckApplicationDoesNotEndUpInDeadlock(string appName, string framework, string appAssembly) + { + var runner = new SmokeTestRunner(appName, framework, appAssembly, ScenarioLinuxDliteratePhdrDeadlock, _output); + runner.RunAndCheck(); + } + } +}