From 652a74e0872fa3127c6df12e9ac1cbe0893d0793 Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Tue, 31 Jan 2023 10:23:12 +1000 Subject: [PATCH] AddType - Support compiling with /unsafe C# code (#79853) * AddType - Support compiling with /unsafe C# code * Update Ansible version in docstring --- changelogs/fragments/AddType-unsafe.yml | 2 + .../Ansible.ModuleUtils.AddType.psm1 | 20 ++++++ .../library/add_type_test.ps1 | 68 +++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 changelogs/fragments/AddType-unsafe.yml diff --git a/changelogs/fragments/AddType-unsafe.yml b/changelogs/fragments/AddType-unsafe.yml new file mode 100644 index 00000000000..43d1ab8e9cf --- /dev/null +++ b/changelogs/fragments/AddType-unsafe.yml @@ -0,0 +1,2 @@ +minor_changes: +- Ansible.ModuleUtils.AddType - Add support for compiling ``unsafe`` code with the ``//AllowUnsafe`` directive diff --git a/lib/ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 b/lib/ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 index 6dc2917fb80..f40c3384cbc 100644 --- a/lib/ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +++ b/lib/ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 @@ -65,6 +65,10 @@ Function Add-CSharpType { * Create automatic type accelerators to simplify long namespace names (Ansible 2.9+) //TypeAccelerator -Name -TypeName + + * Compile with unsafe support (Ansible 2.15+) + + //AllowUnsafe #> param( [Parameter(Mandatory = $true)][AllowEmptyCollection()][String[]]$References, @@ -117,6 +121,7 @@ Function Add-CSharpType { $assembly_pattern = [Regex]"//\s*AssemblyReference\s+-(?(Name)|(Type))\s+(?[\w.]*)(\s+-CLR\s+(?Core|Framework))?" $no_warn_pattern = [Regex]"//\s*NoWarn\s+-Name\s+(?[\w\d]*)(\s+-CLR\s+(?Core|Framework))?" $type_pattern = [Regex]"//\s*TypeAccelerator\s+-Name\s+(?[\w.]*)\s+-TypeName\s+(?[\w.]*)" + $allow_unsafe_pattern = [Regex]"//\s*AllowUnsafe?" # PSCore vs PSDesktop use different methods to compile the code, # PSCore uses Roslyn and can compile the code purely in memory @@ -142,11 +147,13 @@ Function Add-CSharpType { $ignore_warnings = New-Object -TypeName 'System.Collections.Generic.Dictionary`2[[String], [Microsoft.CodeAnalysis.ReportDiagnostic]]' $parse_options = ([Microsoft.CodeAnalysis.CSharp.CSharpParseOptions]::Default).WithPreprocessorSymbols($defined_symbols) $syntax_trees = [System.Collections.Generic.List`1[Microsoft.CodeAnalysis.SyntaxTree]]@() + $allow_unsafe = $false foreach ($reference in $References) { # scan through code and add any assemblies that match # //AssemblyReference -Name ... [-CLR Core] # //NoWarn -Name ... [-CLR Core] # //TypeAccelerator -Name ... -TypeName ... + # //AllowUnsafe $assembly_matches = $assembly_pattern.Matches($reference) foreach ($match in $assembly_matches) { $clr = $match.Groups["CLR"].Value @@ -180,6 +187,10 @@ Function Add-CSharpType { foreach ($match in $type_matches) { $type_accelerators.Add(@{Name = $match.Groups["Name"].Value; TypeName = $match.Groups["TypeName"].Value }) } + + if ($allow_unsafe_pattern.Matches($reference).Count) { + $allow_unsafe = $true + } } # Release seems to contain the correct line numbers compared to @@ -194,6 +205,10 @@ Function Add-CSharpType { $compiler_options = $compiler_options.WithSpecificDiagnosticOptions($ignore_warnings) } + if ($allow_unsafe) { + $compiler_options = $compiler_options.WithAllowUnsafe($true) + } + # create compilation object $compilation = [Microsoft.CodeAnalysis.CSharp.CSharpCompilation]::Create( [System.Guid]::NewGuid().ToString(), @@ -297,6 +312,7 @@ Function Add-CSharpType { # //AssemblyReference -Name ... [-CLR Framework] # //NoWarn -Name ... [-CLR Framework] # //TypeAccelerator -Name ... -TypeName ... + # //AllowUnsafe $assembly_matches = $assembly_pattern.Matches($reference) foreach ($match in $assembly_matches) { $clr = $match.Groups["CLR"].Value @@ -330,6 +346,10 @@ Function Add-CSharpType { foreach ($match in $type_matches) { $type_accelerators.Add(@{Name = $match.Groups["Name"].Value; TypeName = $match.Groups["TypeName"].Value }) } + + if ($allow_unsafe_pattern.Matches($reference).Count) { + $compiler_options.Add("/unsafe") > $null + } } if ($ignore_warnings.Count -gt 0) { $compiler_options.Add("/nowarn:" + ([String]::Join(",", $ignore_warnings.ToArray()))) > $null diff --git a/test/integration/targets/module_utils_Ansible.ModuleUtils.AddType/library/add_type_test.ps1 b/test/integration/targets/module_utils_Ansible.ModuleUtils.AddType/library/add_type_test.ps1 index d18c42d70fb..5cb1a72da70 100644 --- a/test/integration/targets/module_utils_Ansible.ModuleUtils.AddType/library/add_type_test.ps1 +++ b/test/integration/targets/module_utils_Ansible.ModuleUtils.AddType/library/add_type_test.ps1 @@ -328,5 +328,73 @@ finally { } Assert-Equal -actual ([Namespace12.Class12]::GetString()) -expected "b" +$unsafe_code_fail = @' +using System; + +namespace Namespace13 +{ + public class Class13 + { + + public static int GetNumber() + { + int num = 2; + int* numPtr = # + + DoubleNumber(numPtr); + + return num; + } + + private unsafe static void DoubleNumber(int* num) + { + *num = *num * 3; + } + } +} +'@ +$failed = $false +try { + Add-CSharpType -Reference $unsafe_code_fail +} +catch { + $failed = $true + $actual = $_.Exception.Message.Contains("error CS0227: Unsafe code may only appear if compiling with /unsafe") + Assert-Equal -actual $actual -expected $true +} +Assert-Equal -actual $failed -expected $true + +$unsafe_code = @' +using System; + +//AllowUnsafe + +namespace Namespace13 +{ + public class Class13 + { + public static int GetNumber() + { + int num = 2; + unsafe + { + int* numPtr = # + + DoubleNumber(numPtr); + } + + return num; + } + + private unsafe static void DoubleNumber(int* num) + { + *num = *num * 2; + } + } +} +'@ +Add-CSharpType -Reference $unsafe_code +Assert-Equal -actual ([Namespace13.Class13]::GetNumber()) -expected 4 + $result.res = "success" Exit-Json -obj $result