/// <summary>
/// Run code
/// </summary>
/// <returns></returns>
public static async Task<MessageBuilder> OnRunPlainCode(MessageChain message)
{
var codeTemplate = @"
namespace DynamicCodeExecution {
public static class Runnable {
public static object? Run() {
#nullable enable
" + $"{message}" + @"
#nullable restore
}
}
}
";
// Try compile the code
if (Compiler.TryCompile(codeTemplate,
out var context, out var assembly))
{
try
{
// Get type
var type = assembly!.GetType("DynamicCodeExecution.Runnable");
#nullable enable
// Run the code
var cancelation = new CancellationTokenSource();
cancelation.CancelAfter(new TimeSpan(0, 0, 0, 5));
var task = new Task<object?>(() =>
{
var result = type!.GetMethod("Run")!.Invoke(null, null);
return result;
}, cancelation.Token);
#nullable restore
try
{
// Wait for code return
task.Start();
await task.WaitAsync(cancelation.Token);
return MessageBuilder.Eval(task.Result!.ToString());
}
catch (Exception e)
{
if (e is TaskCanceledException)
{
return new MessageBuilder("Timeout while the code execution. (> 5000ms)");
}
}
}
// Any exceptions
catch (Exception e)
{
return null;
}
// Unload assembly
finally
{
context!.Unload();
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
return null;
}
Last active
February 1, 2022 08:25
-
-
Save TheSnowfield/a6ec7474a0a845ea4570411d8500cfdc to your computer and use it in GitHub Desktop.
compile code in runtime
public static class Compiler
{
public static bool TryCompile(string code,
out AssemblyLoadContext context, out Assembly assembly)
{
// Make syntax tree
var syntaxTree = CSharpSyntaxTree.ParseText(code);
// Reference path
var assemblyPath = Path.Combine(Path.GetDirectoryName
(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location));
// Code complation
var compilation = CSharpCompilation.Create(null, new[] {syntaxTree},
options: new CSharpCompilationOptions(
usings: new[]
{
"System",
"System.Text",
"System.Linq",
"System.Drawing",
"System.Collections",
"System.Numerics",
"System.Object",
"System.Nullable",
},
allowUnsafe: true,
outputKind: OutputKind.DynamicallyLinkedLibrary
),
references: new[]
{
$"{assemblyPath}/System.dll",
$"{assemblyPath}/System.Drawing.dll",
$"{assemblyPath}/System.Linq.dll",
$"{assemblyPath}/System.Runtime.dll",
$"{assemblyPath}/System.Private.CoreLib.dll",
$"{assemblyPath}/System.Numerics.dll",
$"{assemblyPath}/System.Text.Json.dll",
$"{assemblyPath}/System.Text.Encoding.dll",
$"{assemblyPath}/System.Text.RegularExpressions.dll",
}.Select(r => MetadataReference.CreateFromFile(r)).ToArray()
);
{
// Read pe stream
using (var peStream = new MemoryStream())
{
// Compilation failed
if (!compilation.Emit(peStream).Success)
{
context = null;
assembly = null;
return false;
}
peStream.Seek(0, SeekOrigin.Begin);
// Create load context
context = new DynamicCodeContext();
assembly = context.LoadFromStream(peStream);
return true;
}
}
}
private class DynamicCodeContext : AssemblyLoadContext
{
public DynamicCodeContext() : base(isCollectible: true)
{
}
protected override Assembly Load(AssemblyName assemblyName)
=> null;
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment