/// <summary> /// It's a hack to manually Dispose Roslyns cache because GC fails with permissions exception. /// </summary> /// <remarks> /// Currently Roslyn's MetadataCache stores AssembliesFromFiles property that stores information about object metadata. /// But it doesn't clean it, so it will be cleaned by GC. but the problem with GC that it will be executed with lower permissions that it needs /// AssembliesFromFiles uses WinApi to create MemoryMappedFile /// </remarks> private static void TryCleanRoslynCacheHack() { if (!SandboxHelper.IsInstanceInsideRunContainer()) { return; } // increase to FullTrust new PermissionSet(PermissionState.Unrestricted).Assert(); var type = Type.GetType("Roslyn.Compilers.MetadataCache, Roslyn.Compilers"); var property = type.GetProperty("AssembliesFromFiles", BindingFlags.Static | BindingFlags.NonPublic); var dict = property.GetValue(null) as IDictionary; if (dict == null) { return; } if (dict.Count != 0) { var caches = dict.Values; FieldInfo weakReferenceField = null; PropertyInfo targetProp = null; foreach (var cache in caches) { // init it if (weakReferenceField == null) { weakReferenceField = cache.GetType().GetField("Metadata"); var tmp = weakReferenceField.GetValue(cache); targetProp = tmp.GetType().GetProperty("Target", BindingFlags.Instance | BindingFlags.NonPublic); } var weakReference = weakReferenceField.GetValue(cache); var obj = targetProp.GetValue(weakReference); ((IDisposable)obj).Dispose(); } } dict.Clear(); }
/// <summary> /// Init worker configuration in the new AppDomain /// </summary> public void InitWorkerSettings(Guid?workerId, string sandboxFolder, Type codeHelperType) { try { _sandboxFolder = sandboxFolder; SandboxHelper.ExecuteInFullTrust( () => { WorkerConfiguration.SetConfiguration(sandboxFolder, workerId); AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; }); _codeHelperType = codeHelperType; ServicePointManager.DefaultConnectionLimit = 1; HttpWebRequest.DefaultMaximumResponseHeadersLength = 0; Initialize(); } catch { throw; } }
private void CodeHelper_RequestedConsoleInput(object sender, EventArgs eventArgs) { SandboxHelper.ExecuteInFullTrust(() => _executingThread.Abort(new ConsoleInputRequest())); }
public RunResult Run(RunOptsBase opts) { RunResult result = null; if (!CheckCodeBlock(opts, ref result)) { return(result); } // we should copy it before running, becuase it can be changed during execution var sandboxFolder = _sandboxFolder; var codeHelper = SandboxHelper.ExecuteInFullTrust(() => (CodeHelper)Activator.CreateInstance(_codeHelperType)); codeHelper.NuGetDllReferences = opts.NuGetDllReferences; codeHelper.StartingExecution += this.CodeHelper_StartingExecution; codeHelper.FinishedExecution += this.CodeHelper_FinishedExecution; codeHelper.RequestedConsoleInput += this.CodeHelper_RequestedConsoleInput; _executingThread = new Thread( () => { try { _runAt = DateTime.Now; result = this.ExecuteCodeBlock(opts, codeHelper); } finally { // in theory in can be null at this point if something bad happened.... if (result == null) { result = new RunResult() { FailureType = RunResultFailureType.FatalError, IsSuccess = false }; } result.Stats = SandboxHelper.ExecuteInFullTrust(() => GatherStatistics()); _compilationCompleted.Set(); } }); _executingThread.Start(); var monitoringTask = Task.Factory.StartNew(MonitorHealth, _tokenSource.Token); // wait for compilation. Just to be sure we have 15 seconds timeout _compilationCompleted.WaitOne(TimeSpan.FromSeconds(15)); // if something happened during compilation, then we fire _compilationCompleted on exit, and result will be filled, so we just need to return it if (result != null) { return(result); } // it will use some time for compilation // it can hungs for some unmanaged call like Console.ReadKey(), so we wait with timeout // we might need to rewrite it to ManualEvent that will be fired when CodeHelper starts execution _executingThread.Join(WorkerConfiguration.Current.ExecutionLimitTimeoutMs * 2); _tokenSource.Cancel(); // we can't move it to new method, as it can be executed via reflection SandboxHelper.ExecuteInFullTrust( () => { try { if (Directory.Exists(sandboxFolder)) { foreach (var file in Directory.EnumerateFiles(sandboxFolder, "*", SearchOption.AllDirectories)) { File.Delete(file); } } } catch { if (result != null) { result.SandboxUnloadReason = SandboxUnloadReason.ClearDirFailed; } } }); return(result); }