How to host Plug-ins safely with .NET 2.0 - c#

I am writing a chess game which allows two programs compete, the player needs to write a DLL and expose a function to tell the main application where his player will move next, suppose the function looks like this
public static void MoveNext(out int x, out int y, out int discKind);
The player's DLL can be written using C# or C++.
In the chess game application, I start a new thread to call the function that the player's DLL exposed to get where he will move in a turn, and I start a timer to prevent the player timeouts, if a player timesout i will kill the corresponding thread by following APIs
thread.Abort();
thread.Join();
I have the following issues as described below:
The thread cannot be killed with 100% assurance (it depends on the player's code)
During test I found that, if the player uses a deep recursions (and if there is memory leak in the player's program), the memory usage of the host application will increase and then the host application will be terminated without any exceptions.
Are there any techniques, ideas or methods that can handle the above issues?
From this CodeInChaos suggested to load player's DLL into separate domain and then unload it when necessary, I am not sure if it still works for the unmanaged DLL (C++) and if it will cause a low efficiency?

An unhandled exception in their AppDomain will still cause your program to terminate in .Net 2.0. You get a chance to respond to the exception through an event handler but not the ability to handle it.
Your best bet is to use processes for the kind of isolation you're looking for.

If you can ensure your plugin DLL's are always managed code, then you have the option of createing a new application domain in your main application logic and loading the assembly containing the plugin into that domain.
This then gives you the option of trapping unhandled excpetions in that specific app domain and you then have the option of Unloading that whole app domain. That way you can cope with other peoples application plugins misbehaving and throwing exceptions. you also gain the option of specifying partial trust to further restrict what a plugin can do.
However this will not help if you cannot enforce the use of managed code plugins, and the earlier option of a set of seperate processes would be more apropriate.
Reading your post agin it seems you have some quality issues with the plugins you have to use. If you must cope with such buggy plugins I would take the previous advice and go with seperate processes.

Related

C# What exactly is application domain?

I understand that an application domain forms:
an isolation boundary for security,
versioning,
reliability,
and unloading of managed code,
but so does a process
Can someone please help me understand the practical benefits of an application domain?
I assumed app domain provides you a container to load one version of an assembly but recently I discovered that multiple versions of strong key assembly can be loaded in an app domain.
My concept of application domain is still not clear. And I am struggling to understand why this concept was implemented when the concept of process is present.
Thank you.
I can't tell if you are talking in general or specifically .NET's AppDomain.
I am going to assume .NET's AppDomain and why it can be really useful when you need that isolation inside of a single process.
For instance:
Say you are dealing with a library that had certain worker classes and you have no choice, but to use those workers and can't modify the code. It's your job to build a Windows Service that manages said workers and makes sure they all stay up and running and need to work in parallel.
Easy enough right? Well, you hoped. It turns out your worker library is prone to throwing exceptions, uses a static configuration, and is generally just a real PITA.
You could try to launch them in their own process, but monitor them, you'll need to implement namedpipes or try to thoughtfully parse the STDIN and STDOUT of the process.
What else can you do? Well AppDomain actually solves this. I can spawn an AppDomain for each worker, give them their own configuration, they can't screw each other up by changing static properties because they are isolated, and on top of that, if the library bombs out and I failed to catch the exception, it doesn't bother the workers in their domain. And during all of this, I can still communicate with those workers easily.
Sadly, I have had to do this before
EDIT: Started to write this as a comment response, but got too large
Individual processes can work great in many scenarios, however, there are just times where they can become a pain. I am not saying one should use an AppDomain over another process. I think it's uncommon you would need a separate process or AppDomain, but once you need it, you'll definitely know.
The main problem I see with processes in the scenario I've given above is that processes have their own downfalls that are easier to mitigate with the AppDomain.
A process can go rogue, become unresponsive, and crash or be killed at any point.
If you're managing processes, you need to keep track of the process ID and monitor the status of it. IPCs are great, but it does take time to get proper communication going back and forth as needed.
As an example let's say your process just dies. What do you do? Depending on the mechanism you chose to monitor, maybe the communication thread died, perhaps the work finished and you still show it as "processing". What do you do?
Now what happens when you have 20 processes and your management app dies. You don't have any real information, all you have is 20 "myprocess.exe" and maybe now have to start parsing the command line arguments they were started with to see which workers you actually have. Obviously with an AppDomain all 20 would have died too, but did you really gain anything with the process? You still have to code the ability to recover, however, now you have to also code all of the recovery for your processes instead of just firing the workers back up.
As with anything in programming, there's 1,000 different ways to achieve the same goal. It's up to you to decide which solution you feel is most appropriate.
Some practical benefits using app domain:
Multiple app domains can be run in a process. You can also stop individual app domain without stopping the entire process. This alone drastically increases the server scalability.
Managing app domain life cycle is done programmatically by runtime hosts (you can override it as well). For processes & threads, you have to explicitly manage their life cycle. Initialization, execution, termination, inter-process/multithread communication is complex and that's why it's easier to defer that to CLR management.
Source: https://learn.microsoft.com/en-us/dotnet/framework/app-domains/application-domains

Prevent native C++ DLL crashing C# App

We have a c# WPF app and we use a 3rd party SDK with a native C++ DLL, we call the methods with DllImport attributes.
Unfortunately code is not that great and that C++ DLL crashes our C# app.
Is there an elegant and efficient way to isolate the calls to the C++ DLL so their exceptions don't crash our app? We are getting a stream of images and data so it needs to be fast.
We use WCF to offload some operations in a windows service, so we have an infrastructure to do this, but I don't think it will be fast enough to transfer data and image buffers to/from it.
Would a different AppDomain be a good choice? Any examples how to do this?
thanks
Its probably the right behaviour to terminate the app in this situation. If you have control over the DLL I would consider handling its exceptions differently
From memory, i believe (in early versions of .Net) you could just catch via ExternalException class:
Note : .NET v4 and above it disables the delivery of certain exceptions by default
To reenable this i 'believe' you can just edit your manifest or use an attribute, take a look at
legacyCorruptedStateExceptionsPolicy Element
HandleProcessCorruptedStateExceptionsAttribute Class
a similar crash occured to me not long ago.I think first you should resove the native dll error . There is no way that you can use to catch an exception from a native code.
The only way to make sure the C++ DLL does not crash your C# process is to move it to another process which you can restart if it crashes.
You can wrap the C++ DLL in a separate application / service and communicate with your C# application via named pipes to transfer the image data. You will also need some kind of heart beat to detect if the wrapper crashed and restart it as needed.
We implemented this solution for a microscope which came with an ActiveX component that kept crashing our application. This approach worked well and was fast enough.
AppDomains don't provide isolation for native assemblies as they use unmanaged memory, due to this I'm not sure if an access violation in a secondary app domain will bring down your whole process.
I'm guessing that your problem is due to state corruption. So before trying to outboard the service you can try catching those exceptions.
How to handle AccessViolationException
So long as the library itself can recover, you might be OK. Worth giving a go.

Handle access violations in COM interop

My managed app is using COM interop. Unfortunately there is a bug in the COM component that causes access violation. When the bug is hit, the whole app crashes, the handler attached to AppDomain.CurrentDomain.UnhandledException didn't get a chance to run. I wonder if there is a way to handle the AV, show a friendly message to the user and recover the managed app?
There is NO way to "handle" an Access Violation.
Depending on the component you are using and how it is implemented even isolating it inside a second AppDomain might still crash your process - AppDomains are "only" a .NET-thing, from the native perspective of the OS they are NOT isolated.
IF you have some problematic component you can always make your usage of it more robust by using the following approach:
Create a process (EXE) which wraps the usage of that component and exposes an API (for example via any IPC mechanism). You can then start that EXE as a separate process (from your main EXE) and use it... IF you need to kill that component after a certain time and/or when some condition is met you can always kill that "wrapper EXE" from your main EXE... depending on the specific component it might even be useful to implement some special "cleanup code" (possibly in a separate thread) within that "wrapper EXE" which gets executed when you need to kill that "wrapper EXE".
Since you are implementing this in .NET you can even have that "wrapper EXE" as "embedded resource" in your main executable and start it even from RAM without writing it to the filesystem.
There is fundamentally no way to "handle" an Access Violation. You have no way to know which memory the COM component has trashed before it sent the AV.
The only thing you can do with a component like this is to try to run it in a separate AppDomain. That way, if it crashes, it only crashes one AppDomain.

Running a .Net application in a sandbox

Over the months, I've developed a personal tool that I'm using to compile C# 3.5 Xaml projects online. Basically, I'm compiling with the CodeDom compiler. I'm thinking about making it public, but the problem is that it is -very-very- easy to do anything on the server with this tool.
The reason I want to protect my server is because there's a 'Run' button to test and debug the app (in screenshot mode).
Is this possible to run an app in a sandbox - in other words, limiting memory access, hard drive access and BIOS access - without having to run it in a VM? Or should I just analyze every code, or 'disable' the Run mode?
Spin up an AppDomain, load assemblies in it, look for an interface you control, Activate up the implementing type, call your method. Just don't let any instances cross that AppDomain barrier (including exceptions!) that you don't 100% control.
Controlling the security policies for your external-code AppDomain is a bit much for a single answer, but you can check this link on MSDN or just search for "code access security msdn" to get details about how to secure this domain.
Edit: There are exceptions you cannot stop, so it is important to watch for them and record in some manner the assemblies that caused the exception so you will not load them again.
Also, it is always better to inject into this second AppDomain a type that you will then use to do all loading and execution. That way you are ensured that no type (that won't bring down your entire application) will cross any AppDomain boundary. I've found it is useful to define a type that extends MarshalByRefObject that you call methods on that executes insecure code in the second AppDomain. It should never return an unsealed type that isn't marked Serializable across the boundary, either as a method parameter or as a return type. As long as you can accomplish this you are 90% of the way there.

How to deal with exceptions on separate threads in an external dll?

I'm loading in a dll that spawns a few threads within itself. Every now and then the program crashes with an unhandled exception. I can't wrap all my library calls in try/catch statements because the exceptions are being thrown on separate threads, and I don't have access to the library's source to debug/fix the bad error handling. I'd like the program to keep doing other things when these exceptions happen, is there a graceful way to handle these exceptions? Or is the only thing I can do to do a global catch all exceptions method?
If you load the DLL into a separate appdomain, you should be able to isolate exceptions generated with a AppDomain.UnhandledException, but, be aware that this is not fool proof and there are certain situations where it will still take your process out too and there is nothing you can do about it (stack overflow, out of memory etc).
The best you can do in that case is load them in a separate process completely with some kind of dll communication harness and using some form of remoting to talk to that process.
I would recommend to implement a separate process (EXE) which your application launches and which in turn loads the DLL.
This allows you to kill/restart the process whenever need be...
I see several options on how to communicate - for example:
you could use COM (if you implement it as an out-of-process COM server)
you could use shared memory (very high performance, see this for a walkthrough and this for a .NET 2 wrapper)
IF the method must be compatible with several Windows versions THEN I would refrain from using anything "networky" for the IPC (since some come with a desktop firewall).

Categories

Resources