Skip to content

Commit ade63e9

Browse files
committed
Fix WASM memory bugs
1 parent 60bad33 commit ade63e9

File tree

4 files changed

+34
-34
lines changed

4 files changed

+34
-34
lines changed

coinlib/lib/src/common/checks.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
void _checkInt(int i, int min, int max, String type, String name) {
32
if (i < min || i > max) {
43
throw ArgumentError.value(i, name, "must be a $type");
Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:typed_data';
22
import 'heap.dart';
3+
import 'wasm.dart';
34

45
typedef MallocFunction = int Function(int);
56
typedef FreeFunction = int Function(int);
@@ -14,52 +15,56 @@ class HeapWasm implements Heap<int> {
1415
(free) => free(),
1516
);
1617

18+
final Wasm _wasm;
19+
1720
@override
1821
final int ptr;
1922

20-
HeapWasm._(this.ptr, FreeFunction free) {
21-
_finalizer.attach(this, () => free(ptr));
23+
HeapWasm._(this._wasm, this.ptr, FreeFunction free) {
24+
// Copy avoids reference to object by finalizer ensuring that the object is
25+
// indeed freed.
26+
final ptrCopy = ptr;
27+
_finalizer.attach(this, () => free(ptrCopy));
2228
}
2329

30+
Uint8List get memory => _wasm.memory;
31+
2432
}
2533

2634
/// Encapsulates a WASM heap-allocated unsigned char array, accessible as a
2735
/// Uint8List. Must be created through [HeapFactory].
2836
class HeapBytesWasm extends HeapWasm implements HeapBytes<int> {
2937

3038
final int size;
31-
final Uint8List _view;
3239

33-
HeapBytesWasm._(this.size, super.ptr, this._view, super.free) : super._();
40+
HeapBytesWasm._(super._wasm, this.size, super.ptr, super.free) : super._();
3441

3542
@override
36-
Uint8List get copy => _view.sublist(0);
43+
Uint8List get copy => memory.sublist(ptr, ptr+size);
3744

3845
@override
39-
Uint8List copyNBytes(int n) => _view.sublist(0, n);
46+
Uint8List copyNBytes(int n) => memory.sublist(ptr, ptr+n);
4047

4148
@override
42-
load(Uint8List data) => _view.setAll(0, data);
49+
load(Uint8List data) => memory.setAll(ptr, data);
4350

4451
}
4552

4653
class HeapIntWasm extends HeapWasm implements HeapInt<int> {
4754

48-
final ByteData _data;
55+
HeapIntWasm._(super._wasm, super.ptr, super.free) : super._();
4956

50-
HeapIntWasm._(this._data, super.ptr, super.free) : super._();
51-
HeapIntWasm._withMemory(Uint8List memory, super.ptr, super.free)
52-
: _data = ByteData.view(memory.buffer), super._();
57+
ByteData get _view => ByteData.view(memory.buffer);
5358

5459
@override
55-
set value(int i) => _data.setUint32(ptr, i, Endian.little);
60+
set value(int i) => _view.setUint32(ptr, i, Endian.little);
5661

5762
@override
58-
int get value => _data.getUint32(ptr, Endian.little);
63+
int get value => _view.getUint32(ptr, Endian.little);
5964

6065
/// If this represents an integer array, get the integer at the [i] position.
6166
HeapIntWasm operator[](int i)
62-
=> HeapIntWasm._(_data, ptr+_intBytes*i, (_) => 0);
67+
=> HeapIntWasm._(_wasm, ptr+_intBytes*i, (_) => 0);
6368

6469
}
6570

@@ -71,8 +76,8 @@ implements HeapPointerArray<int, int> {
7176
final List<HeapWasm> _objs;
7277

7378
HeapPointerArrayWasm._(
74-
super.memory, super.ptr, super.free, this._objs,
75-
) : super._withMemory() {
79+
super._wasm, super.ptr, super.free, this._objs,
80+
) : super._() {
7681
// Set pointers of array
7782
for (int i = 0; i < _objs.length; i++) {
7883
this[i].value = _objs[i].ptr;
@@ -88,38 +93,33 @@ implements HeapPointerArray<int, int> {
8893
/// functions.
8994
class HeapFactory {
9095

91-
final Uint8List _memory;
96+
final Wasm _wasm;
9297
final MallocFunction _malloc;
9398
final FreeFunction _free;
9499

95-
HeapFactory(this._memory, this._malloc, this._free);
100+
HeapFactory(this._wasm, this._malloc, this._free);
96101

97102
/// Allocate a byte array of [size].
98-
HeapBytesWasm bytes(int size) {
99-
final ptr = _malloc(size);
100-
final list = Uint8List.view(_memory.buffer, ptr, size);
101-
return HeapBytesWasm._(size, ptr, list, _free);
102-
}
103+
HeapBytesWasm bytes(int size)
104+
=> HeapBytesWasm._(_wasm, size, _malloc(size), _free);
103105

104106
/// Allocate data for a miscellaneous object with [size] bytes.
105107
/// If [copyFrom] is specified, data shall be copied from this pointer.
106108
HeapWasm alloc(int size, { int? copyFrom }) {
107-
final heap = HeapWasm._(_malloc(size), _free);
109+
final heap = HeapWasm._(_wasm, _malloc(size), _free);
108110
if (copyFrom != null) {
109-
_memory.setRange(heap.ptr, heap.ptr + size, _memory, copyFrom);
111+
heap.memory.setRange(heap.ptr, heap.ptr + size, heap.memory, copyFrom);
110112
}
111113
return heap;
112114
}
113115

114116
/// Allocates an integer on the heap.
115-
HeapIntWasm integer() => HeapIntWasm._withMemory(
116-
_memory, _malloc(_intBytes), _free,
117-
);
117+
HeapIntWasm integer() => HeapIntWasm._(_wasm, _malloc(_intBytes), _free);
118118

119119
/// Creates an array of pointers to the [objs].
120120
HeapPointerArrayWasm assignPointerArray(List<HeapWasm> objs)
121121
=> HeapPointerArrayWasm._(
122-
_memory,
122+
_wasm,
123123
_malloc(objs.length*_intBytes),
124124
_free,
125125
objs,
@@ -129,7 +129,7 @@ class HeapFactory {
129129
/// [objSize].
130130
HeapPointerArrayWasm allocPointerArray(int length, int objSize)
131131
=> assignPointerArray(
132-
List.generate(length, (_) => HeapWasm._(_malloc(objSize), _free)),
132+
List.generate(length, (_) => HeapWasm._(_wasm, _malloc(objSize), _free)),
133133
);
134134

135135
}

coinlib/lib/src/secp256k1/secp256k1_web.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,7 @@ class Secp256k1 extends Secp256k1Base<
9090
final int Function(int, int) contextRandomize
9191
= wasm.field("secp256k1_context_randomize");
9292

93-
final MallocFunction malloc = wasm.field("malloc");
94-
final FreeFunction free = wasm.field("free");
95-
_heapFactory = HeapFactory(wasm.memory, malloc, free);
93+
_heapFactory = HeapFactory(wasm, wasm.field("malloc"), wasm.field("free"));
9694

9795
// Heap arrays
9896
key32Array = _heapFactory.bytes(Secp256k1Base.privkeySize);

coinlib/lib/src/secp256k1/wasm.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ class Wasm {
5252

5353
}
5454

55+
/// This must be used every single time memory access is required. It must not
56+
/// be stored as it can be invalidated at any time.
5557
Uint8List get memory => _exports.memory.buffer.toDart.asUint8List();
58+
5659
T field<T>(String name) => _exports.getProperty(name.toJS).dartify() as T;
5760

5861
}

0 commit comments

Comments
 (0)