
Exploring the Uno Platform: Handling Unsafe Code in Multi-Target Applications
Exploring the Uno Platform: Handling Unsafe Code in Multi-Target Applications
This last weekend I wanted to do a technical experiment as I always do when I have some free time. I decided there was something new I needed to try and see if I could write about. The weekend turned out to be a beautiful surprise as I went back to test the Uno platform – a multi-OS, multi-target UI framework that generates mobile applications, desktop applications, web applications, and even Linux applications.
The idea of Uno is a beautiful concept, but for a long time, the tooling wasn’t quite there. I had made it work several times in the past, but after an update or something in Visual Studio, the setup would break and applications would become basically impossible to compile. That seems to no longer be the case!
Last weekend, I set up Uno on two different computers: my new Surface laptop with an ARM type of processor (which can sometimes be tricky for some tools) and my old MSI with an x64 type of processor. I was thrilled that the setup was effortless on both machines.
After the successful setup, I decided to download the entire Uno demo repository and start trying out the demos. However, for some reason, they didn’t compile. I eventually realized there was a problem with generated code during compilation time that turned out to be unsafe code. Here are my findings about how to handle the unsafe code that is generated.
AllowUnsafeBlocks Setting in Project File
I discovered that this setting was commented out in the Navigation.csproj file:
<!--<AllowUnsafeBlocks>true</AllowUnsafeBlocks>-->
When uncommented, this setting allows the use of unsafe code blocks in your .NET 8 Uno Platform project. To enable unsafe code, you need to remove the comment markers from this line in your project file.
Why It’s Needed
The <AllowUnsafeBlocks>true</AllowUnsafeBlocks> setting is required whenever you want to use “unsafe” code in C#. By default, C# is designed to be memory-safe, preventing direct memory manipulation that could lead to memory corruption, buffer overflows, or security vulnerabilities. When you add this setting to your project file, you’re explicitly telling the compiler to allow portions of code marked with the unsafe keyword.
Unsafe code lets you work with pointers and perform direct memory operations, which can be useful for:
- Performance-critical operations
- Interoperability with native code
- Direct memory manipulation
What Makes Code “Unsafe”
Code is considered “unsafe” when it bypasses .NET’s memory safety guarantees. Specifically, unsafe code includes:
- Pointer operations: Using the * and -> operators with memory addresses
- Fixed statements: Pinning managed objects in memory so their addresses don’t change during garbage collection
- Sizeof operator: Getting the size of a type in bytes
- Stackalloc keyword: Allocating memory on the stack instead of the heap
Example of Unsafe Code
Here’s an example of unsafe code that might be generated:
unsafe { int[] numbers = new int[] { 10, 20, 30, 40, 50 }; // UNSAFE: Pinning an array in memory and getting direct pointer fixed (int* pNumbers = numbers) { // UNSAFE: Pointer declaration and manipulation int* p = pNumbers; // UNSAFE: Dereferencing pointers to modify memory directly *p = *p + 5; *(p + 1) = *(p + 1) + 5; } }
Why Use Unsafe Code?
There are several legitimate reasons to use unsafe code:
- Performance optimization: For extremely performance-critical sections where you need to eliminate overhead from bounds checking or other safety features.
- Interoperability: When interfacing with native libraries or system APIs that require pointers.
- Low-level operations: For systems programming tasks that require direct memory manipulation, like implementing custom memory managers.
- Hardware access: When working directly with device drivers or memory-mapped hardware.
- Algorithms requiring pointer arithmetic: Some specialized algorithms are most efficiently implemented using pointer operations.
Risks and Considerations
Using unsafe code comes with significant responsibilities:
- You bypass the runtime’s safety checks, so errors can cause application crashes or security vulnerabilities
- Memory leaks are possible if you allocate unmanaged memory and don’t free it properly
- Your code becomes less portable across different .NET implementations
- Debugging unsafe code is more challenging
In general, you should only use unsafe code when absolutely necessary and isolate it in small, well-tested sections of your application.
In conclusion, I’m happy to see that the Uno platform has matured significantly. While there are still some challenges like handling unsafe generated code, the setup process has become much more reliable. If you’re looking to develop truly cross-platform applications with a single codebase, Uno is worth exploring – just remember to uncomment that AllowUnsafeBlocks setting if you run into compilation issues!