Professional Documents
Culture Documents
C# and Rust
Rainer Stropek | @rstropek | software architects
The Problem
Memory Safety is an Issue
~70% of CVEs/patch year are memory safety related
Source: Microsoft
It is not getting better 🤯
Memory Leak Note: This is not best-practice C++ code, just for demo
purposes. Use types like vector or string, RAII-techniques like
#include <iostream> shared pointers, etc. instead.
#include <stdlib.h>
#include <string.h>
using namespace std;
char *getData() {
char *buffer = (char*)malloc(1024);
strcpy(buffer, "Hi!\n"); // read data from somewhere
return buffer;
}
void getAndProcessData() {
char *buffer = getData();
cout << buffer;
}
int main() {
getAndProcessData();
}
int main() {
char* stmt = (char*)malloc(100);
strcpy(stmt, "INSERT INTO ...");
// Do something else
if (errorHappened) {
logError("Error executing SQL", stmt);
}
} See also CWE-416 Vulnerability
Try online: https://repl.it/@RainerStropek/C-Use-After-Free
Use After Free
using System;
class SqlConnection : IDisposable { … }
class MainClass {
private SqlConnection Connection { get; set; }
public void OpenConnection() { … }
public void ExecSql(SqlConnection conn, string stmt) { … }
public void LogError(string category, SqlConnection conn) { … }
public static void Main (string[] args) { … }
public void Run() {
OpenConnection();
bool errorHappened = false;
try {
ExecSql(Connection, "INSERT INTO ...");
// Continue working with DB
}
catch {
errorHappened = true;
Connection.Dispose();
}
// Do something else
if (errorHappened) {
LogError("Error executing SQL", Connection);
}
}
}
Try online: https://repl.it/@RainerStropek/C-Use-after-Dispose
Double Free Problem
#include <iostream>
using namespace std;
int main() {
int* p = new int; // Allocate and init
*p = 42;
class MainClass {
public static void Main(string[] args) {
var numbers = ArrayPool<int>.Shared.Rent(4);
try { DoSomethingWithNumbers(numbers); }
finally { ArrayPool<int>.Shared.Return(numbers); }
}
class MainClass {
public static void Main (string[] args) {
// Get memory pool, Main is now owner
IMemoryOwner<char> owner = MemoryPool<char>.Shared.Rent(100); Owner Consumer
// Pass memory to consumer, Main is still owner
Memory<char> buffer = owner.Memory;
WriteInt32ToBuffer(42, buffer);
fn consume(numbers: Vec<i32>) {
let sum: i32 = numbers.iter().sum();
consume does not need
println!("The sum is {}", sum);
// numbers gets out of scope -> free memory ownership → borrowing
}
println!("{:?}", numbers);
}