or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

callbacks-handles.mdcore-ffi.mddata-conversion.mderror-handling.mdindex.mdmemory-management.mdsource-generation.mdtype-system.md

memory-management.mddocs/

0

# Memory Management

1

2

C memory allocation, deallocation, garbage collection, and address operations. CFFI provides automatic memory management with options for custom allocators and manual control.

3

4

## Capabilities

5

6

### Memory Allocation

7

8

Allocates C data structures with automatic garbage collection and optional initialization.

9

10

```python { .api }

11

def new(self, cdecl, init=None):

12

"""

13

Allocate C data according to the specified type.

14

15

Parameters:

16

- cdecl (str): C type declaration (pointer or array)

17

- init: Optional initializer value

18

19

Returns:

20

CData object with automatic memory management

21

"""

22

```

23

24

**Usage Examples:**

25

26

```python

27

# Allocate single values

28

p_int = ffi.new("int *")

29

p_int[0] = 42

30

31

# Allocate with initialization

32

p_initialized = ffi.new("int *", 100)

33

34

# Allocate arrays

35

arr = ffi.new("int[10]") # Fixed size array

36

dyn_arr = ffi.new("int[]", 5) # Dynamic array with 5 elements

37

38

# Initialize arrays

39

data = ffi.new("int[]", [1, 2, 3, 4, 5])

40

41

# Allocate structures

42

ffi.cdef("struct point { int x, y; };")

43

point = ffi.new("struct point *")

44

point.x = 10

45

point.y = 20

46

47

# Initialize structures

48

point_init = ffi.new("struct point *", {"x": 10, "y": 20})

49

```

50

51

### Custom Allocators

52

53

Creates custom memory allocators with user-defined allocation and deallocation functions.

54

55

```python { .api }

56

def new_allocator(self, alloc=None, free=None, should_clear_after_alloc=True):

57

"""

58

Create custom allocator function.

59

60

Parameters:

61

- alloc: Custom allocation function (takes size, returns pointer)

62

- free: Custom deallocation function (takes pointer)

63

- should_clear_after_alloc (bool): Whether to zero-initialize memory

64

65

Returns:

66

Allocator function compatible with new() interface

67

"""

68

```

69

70

**Usage Example:**

71

72

```python

73

# Create custom allocator

74

def my_alloc(size):

75

print(f"Allocating {size} bytes")

76

return ffi.cast("void *", ffi.new("char[]", size))

77

78

def my_free(ptr):

79

print("Freeing memory")

80

# Memory automatically freed by CFFI

81

82

allocator = ffi.new_allocator(my_alloc, my_free)

83

84

# Use custom allocator

85

data = allocator("int[100]")

86

```

87

88

### Type Casting

89

90

Converts between different C types and Python objects.

91

92

```python { .api }

93

def cast(self, cdecl, source):

94

"""

95

Cast source to the specified C type.

96

97

Parameters:

98

- cdecl (str): Target C type declaration

99

- source: Source value (CData, int, pointer, etc.)

100

101

Returns:

102

CData object of the specified type

103

"""

104

```

105

106

**Usage Examples:**

107

108

```python

109

# Cast integers to pointers

110

ptr = ffi.cast("void *", 0x12345678)

111

112

# Cast between pointer types

113

int_ptr = ffi.new("int *", 42)

114

void_ptr = ffi.cast("void *", int_ptr)

115

back_to_int = ffi.cast("int *", void_ptr)

116

117

# Cast arrays to pointers

118

arr = ffi.new("int[5]", [1, 2, 3, 4, 5])

119

ptr = ffi.cast("int *", arr)

120

121

# Cast to different integer types

122

value = ffi.cast("unsigned char", 256) # Results in 0 (overflow)

123

```

124

125

### Address Operations

126

127

Gets the address of C data objects and structure fields.

128

129

```python { .api }

130

def addressof(self, cdata, *fields_or_indexes):

131

"""

132

Get address of C data or field within structure/array.

133

134

Parameters:

135

- cdata: C data object

136

- *fields_or_indexes: Field names or array indexes for nested access

137

138

Returns:

139

Pointer to the specified location

140

"""

141

```

142

143

**Usage Examples:**

144

145

```python

146

# Get address of simple data

147

x = ffi.new("int *", 42)

148

addr = ffi.addressof(x[0])

149

150

# Get address of structure fields

151

ffi.cdef("struct point { int x, y; };")

152

point = ffi.new("struct point *")

153

x_addr = ffi.addressof(point, "x")

154

y_addr = ffi.addressof(point, "y")

155

156

# Get address of array elements

157

arr = ffi.new("int[10]")

158

element_addr = ffi.addressof(arr, 5)

159

160

# Nested structure access

161

ffi.cdef("""

162

struct inner { int value; };

163

struct outer { struct inner data[5]; };

164

""")

165

outer = ffi.new("struct outer *")

166

inner_addr = ffi.addressof(outer, "data", 2, "value")

167

```

168

169

### Garbage Collection Control

170

171

Attaches custom destructors to C data objects for cleanup when garbage collected.

172

173

```python { .api }

174

def gc(self, cdata, destructor, size=0):

175

"""

176

Attach destructor to C data object.

177

178

Parameters:

179

- cdata: C data object

180

- destructor: Function to call on garbage collection

181

- size (int): Estimated size for GC scheduling

182

183

Returns:

184

New CData object with attached destructor

185

"""

186

```

187

188

**Usage Example:**

189

190

```python

191

def cleanup_func(ptr):

192

print("Cleaning up resource")

193

# Perform cleanup operations

194

195

# Allocate resource with cleanup

196

resource = ffi.new("void **")

197

managed_resource = ffi.gc(resource, cleanup_func)

198

```

199

200

## Memory Safety Patterns

201

202

### Automatic Memory Management

203

204

```python

205

def process_data():

206

# Memory automatically freed when function exits

207

buffer = ffi.new("char[1024]")

208

# Use buffer...

209

return ffi.string(buffer) # Safe: string is copied

210

```

211

212

### Long-lived References

213

214

```python

215

class DataProcessor:

216

def __init__(self):

217

# Keep reference to prevent garbage collection

218

self.buffer = ffi.new("char[4096]")

219

self.processed = ffi.gc(self.buffer, self._cleanup)

220

221

def _cleanup(self, ptr):

222

print("Buffer cleaned up")

223

```

224

225

### Working with C Libraries that Manage Memory

226

227

```python

228

ffi.cdef("""

229

void* create_object(int size);

230

void destroy_object(void* obj);

231

""")

232

233

lib = ffi.dlopen("mylib.so")

234

235

# Create object managed by C library

236

obj = lib.create_object(1024)

237

238

# Attach cleanup function

239

managed_obj = ffi.gc(obj, lib.destroy_object)

240

```

241

242

## Common Pitfalls and Solutions

243

244

### Dangling Pointers

245

246

```python

247

# WRONG: pointer becomes invalid

248

def get_pointer():

249

data = ffi.new("int *", 42)

250

return ffi.addressof(data[0]) # Danger: data may be freed

251

252

# CORRECT: return the data object itself

253

def get_data():

254

data = ffi.new("int *", 42)

255

return data # Safe: data stays alive

256

```

257

258

### Memory Sharing

259

260

```python

261

# Share memory between Python and C

262

source = bytearray(b"Hello, World!")

263

c_buffer = ffi.from_buffer("char[]", source)

264

265

# Modifications to c_buffer affect source

266

c_buffer[0] = ord('h')

267

print(source) # b"hello, World!"

268

```

269

270

### Array Bounds

271

272

```python

273

# CFFI doesn't check array bounds - be careful!

274

arr = ffi.new("int[5]")

275

# arr[10] = 42 # DANGER: out of bounds access

276

277

# Safe pattern: check bounds manually

278

def safe_set(arr, index, value, size):

279

if 0 <= index < size:

280

arr[index] = value

281

else:

282

raise IndexError("Array index out of range")

283

```