fix UAF in grow
Grow needs to allocate and might fail midway. It tries to handle this using "undo" pattern, and restoring old state on error. But this is exactly what steps into UAF, as, on error, both errdefer and defer are run, and the old data is freed. Instead, use a more robust "reservation" pattern, where we first fallibly resrve all the resources we need, without applying any changes, and than do the actual change once we are sure that cannot fail.pull/8249/head
parent
0930b2daff
commit
4c4d3cfc3f
|
|
@ -287,22 +287,19 @@ pub fn grow(self: *Atlas, alloc: Allocator, size_new: u32) Allocator.Error!void
|
||||||
assert(size_new >= self.size);
|
assert(size_new >= self.size);
|
||||||
if (size_new == self.size) return;
|
if (size_new == self.size) return;
|
||||||
|
|
||||||
|
try self.nodes.ensureUnusedCapacity(alloc, 1);
|
||||||
|
const data_new = try alloc.alloc(u8, size_new * size_new * self.format.depth());
|
||||||
|
errdefer comptime unreachable; // End resource reservation phase.
|
||||||
|
|
||||||
// Preserve our old values so we can copy the old data
|
// Preserve our old values so we can copy the old data
|
||||||
const data_old = self.data;
|
const data_old = self.data;
|
||||||
const size_old = self.size;
|
const size_old = self.size;
|
||||||
|
|
||||||
// Allocate our new data
|
self.data = data_new;
|
||||||
self.data = try alloc.alloc(u8, size_new * size_new * self.format.depth());
|
|
||||||
defer alloc.free(data_old);
|
defer alloc.free(data_old);
|
||||||
errdefer {
|
|
||||||
alloc.free(self.data);
|
|
||||||
self.data = data_old;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add our new rectangle for our added righthand space. We do this
|
// Add our new rectangle for our added righthand space.
|
||||||
// right away since its the only operation that can fail and we want
|
self.nodes.appendAssumeCapacity(alloc, .{
|
||||||
// to make error cleanup easier.
|
|
||||||
try self.nodes.append(alloc, .{
|
|
||||||
.x = size_old - 1,
|
.x = size_old - 1,
|
||||||
.y = 1,
|
.y = 1,
|
||||||
.width = size_new - size_old,
|
.width = size_new - size_old,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue