fix: prevent IPC slot reuse during object teardown
This commit is contained in:
@@ -12,4 +12,4 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MONTAUK_BUILD_NUMBER 24
|
#define MONTAUK_BUILD_NUMBER 27
|
||||||
|
|||||||
+49
-9
@@ -44,6 +44,7 @@ namespace Ipc {
|
|||||||
struct Object {
|
struct Object {
|
||||||
HandleType type;
|
HandleType type;
|
||||||
bool active;
|
bool active;
|
||||||
|
bool destroying;
|
||||||
uint32_t refs;
|
uint32_t refs;
|
||||||
kcp::Mutex lock;
|
kcp::Mutex lock;
|
||||||
};
|
};
|
||||||
@@ -267,9 +268,38 @@ namespace Ipc {
|
|||||||
static void InitObject(Object& object, HandleType type) {
|
static void InitObject(Object& object, HandleType type) {
|
||||||
object.type = type;
|
object.type = type;
|
||||||
object.active = true;
|
object.active = true;
|
||||||
|
object.destroying = false;
|
||||||
object.refs = 0;
|
object.refs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static kcp::Mutex* PoolLockForType(HandleType type) {
|
||||||
|
switch (type) {
|
||||||
|
case HandleType::Stream: return &g_streamPoolLock;
|
||||||
|
case HandleType::Mailbox: return &g_mailboxPoolLock;
|
||||||
|
case HandleType::File: return &g_filePoolLock;
|
||||||
|
case HandleType::Socket: return &g_socketPoolLock;
|
||||||
|
case HandleType::Surface: return &g_surfacePoolLock;
|
||||||
|
case HandleType::Process: return &g_processPoolLock;
|
||||||
|
case HandleType::Waitset: return &g_waitsetPoolLock;
|
||||||
|
default: return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// An object is hidden from users as soon as its last reference disappears,
|
||||||
|
// but its pool slot must not become reusable until the type-specific
|
||||||
|
// destructor has finished. Otherwise a concurrent allocator can install a
|
||||||
|
// new backend in the slot and the old destructor will tear down the new
|
||||||
|
// object (observed as open() succeeding immediately before getsize() saw
|
||||||
|
// an invalid file handle).
|
||||||
|
static void FinishDestroy(Object* object, HandleType type) {
|
||||||
|
kcp::Mutex* poolLock = PoolLockForType(type);
|
||||||
|
if (poolLock) poolLock->Acquire();
|
||||||
|
object->lock.Acquire();
|
||||||
|
object->destroying = false;
|
||||||
|
object->lock.Release();
|
||||||
|
if (poolLock) poolLock->Release();
|
||||||
|
}
|
||||||
|
|
||||||
static void RetainRawObject(Object* object) {
|
static void RetainRawObject(Object* object) {
|
||||||
if (object == nullptr) return;
|
if (object == nullptr) return;
|
||||||
object->lock.Acquire();
|
object->lock.Acquire();
|
||||||
@@ -376,6 +406,7 @@ namespace Ipc {
|
|||||||
destroy = true;
|
destroy = true;
|
||||||
type = object->type;
|
type = object->type;
|
||||||
object->active = false;
|
object->active = false;
|
||||||
|
object->destroying = true;
|
||||||
}
|
}
|
||||||
object->lock.Release();
|
object->lock.Release();
|
||||||
|
|
||||||
@@ -405,6 +436,7 @@ namespace Ipc {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
FinishDestroy(object, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t CurrentSignalsForSnapshot(HandleType type, Object* object, uint32_t rights);
|
static uint32_t CurrentSignalsForSnapshot(HandleType type, Object* object, uint32_t rights);
|
||||||
@@ -540,11 +572,15 @@ namespace Ipc {
|
|||||||
if (stream->refs == 0) {
|
if (stream->refs == 0) {
|
||||||
destroy = true;
|
destroy = true;
|
||||||
stream->active = false;
|
stream->active = false;
|
||||||
|
stream->destroying = true;
|
||||||
}
|
}
|
||||||
stream->lock.Release();
|
stream->lock.Release();
|
||||||
|
|
||||||
if (notify) NotifyObjectChanged((Object*)stream);
|
if (notify) NotifyObjectChanged((Object*)stream);
|
||||||
if (destroy) DestroyStream(stream);
|
if (destroy) {
|
||||||
|
DestroyStream(stream);
|
||||||
|
FinishDestroy((Object*)stream, HandleType::Stream);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HandleType::Mailbox: {
|
case HandleType::Mailbox: {
|
||||||
@@ -562,11 +598,15 @@ namespace Ipc {
|
|||||||
if (mailbox->refs == 0) {
|
if (mailbox->refs == 0) {
|
||||||
destroy = true;
|
destroy = true;
|
||||||
mailbox->active = false;
|
mailbox->active = false;
|
||||||
|
mailbox->destroying = true;
|
||||||
}
|
}
|
||||||
mailbox->lock.Release();
|
mailbox->lock.Release();
|
||||||
|
|
||||||
if (notify) NotifyObjectChanged((Object*)mailbox);
|
if (notify) NotifyObjectChanged((Object*)mailbox);
|
||||||
if (destroy) DestroyMailbox(mailbox);
|
if (destroy) {
|
||||||
|
DestroyMailbox(mailbox);
|
||||||
|
FinishDestroy((Object*)mailbox, HandleType::Mailbox);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -660,7 +700,7 @@ namespace Ipc {
|
|||||||
|
|
||||||
g_streamPoolLock.Acquire();
|
g_streamPoolLock.Acquire();
|
||||||
for (int i = 0; i < MaxStreams; i++) {
|
for (int i = 0; i < MaxStreams; i++) {
|
||||||
if (g_streams[i].active) continue;
|
if (g_streams[i].active || g_streams[i].destroying) continue;
|
||||||
InitObject(g_streams[i], HandleType::Stream);
|
InitObject(g_streams[i], HandleType::Stream);
|
||||||
g_streams[i].buffer = (uint8_t*)buffer;
|
g_streams[i].buffer = (uint8_t*)buffer;
|
||||||
g_streams[i].capacity = (uint32_t)numPages * 0x1000u;
|
g_streams[i].capacity = (uint32_t)numPages * 0x1000u;
|
||||||
@@ -841,7 +881,7 @@ namespace Ipc {
|
|||||||
Mailbox* CreateMailbox() {
|
Mailbox* CreateMailbox() {
|
||||||
g_mailboxPoolLock.Acquire();
|
g_mailboxPoolLock.Acquire();
|
||||||
for (int i = 0; i < MaxMailboxes; i++) {
|
for (int i = 0; i < MaxMailboxes; i++) {
|
||||||
if (g_mailboxes[i].active) continue;
|
if (g_mailboxes[i].active || g_mailboxes[i].destroying) continue;
|
||||||
InitObject(g_mailboxes[i], HandleType::Mailbox);
|
InitObject(g_mailboxes[i], HandleType::Mailbox);
|
||||||
g_mailboxes[i].head = 0;
|
g_mailboxes[i].head = 0;
|
||||||
g_mailboxes[i].tail = 0;
|
g_mailboxes[i].tail = 0;
|
||||||
@@ -1106,7 +1146,7 @@ namespace Ipc {
|
|||||||
|
|
||||||
g_filePoolLock.Acquire();
|
g_filePoolLock.Acquire();
|
||||||
for (int i = 0; i < MaxFiles; i++) {
|
for (int i = 0; i < MaxFiles; i++) {
|
||||||
if (g_files[i].active) continue;
|
if (g_files[i].active || g_files[i].destroying) continue;
|
||||||
InitObject(g_files[i], HandleType::File);
|
InitObject(g_files[i], HandleType::File);
|
||||||
g_files[i].backend = backend;
|
g_files[i].backend = backend;
|
||||||
g_filePoolLock.Release();
|
g_filePoolLock.Release();
|
||||||
@@ -1173,7 +1213,7 @@ namespace Ipc {
|
|||||||
static Socket* AllocateSocketObject(int type) {
|
static Socket* AllocateSocketObject(int type) {
|
||||||
g_socketPoolLock.Acquire();
|
g_socketPoolLock.Acquire();
|
||||||
for (int i = 0; i < MaxSockets; i++) {
|
for (int i = 0; i < MaxSockets; i++) {
|
||||||
if (g_sockets[i].active) continue;
|
if (g_sockets[i].active || g_sockets[i].destroying) continue;
|
||||||
InitObject(g_sockets[i], HandleType::Socket);
|
InitObject(g_sockets[i], HandleType::Socket);
|
||||||
g_sockets[i].socketType = type;
|
g_sockets[i].socketType = type;
|
||||||
g_sockets[i].tcpConn = nullptr;
|
g_sockets[i].tcpConn = nullptr;
|
||||||
@@ -1505,7 +1545,7 @@ namespace Ipc {
|
|||||||
g_surfacePoolLock.Acquire();
|
g_surfacePoolLock.Acquire();
|
||||||
int slot = -1;
|
int slot = -1;
|
||||||
for (int i = 0; i < MaxSurfaces; i++) {
|
for (int i = 0; i < MaxSurfaces; i++) {
|
||||||
if (!g_surfaces[i].active) {
|
if (!g_surfaces[i].active && !g_surfaces[i].destroying) {
|
||||||
slot = i;
|
slot = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1927,7 +1967,7 @@ namespace Ipc {
|
|||||||
|
|
||||||
g_processPoolLock.Acquire();
|
g_processPoolLock.Acquire();
|
||||||
for (int i = 0; i < MaxProcessObjects; i++) {
|
for (int i = 0; i < MaxProcessObjects; i++) {
|
||||||
if (g_processObjects[i].active) continue;
|
if (g_processObjects[i].active || g_processObjects[i].destroying) continue;
|
||||||
InitObject(g_processObjects[i], HandleType::Process);
|
InitObject(g_processObjects[i], HandleType::Process);
|
||||||
g_processObjects[i].pid = pid;
|
g_processObjects[i].pid = pid;
|
||||||
g_processObjects[i].exited = false;
|
g_processObjects[i].exited = false;
|
||||||
@@ -2127,7 +2167,7 @@ namespace Ipc {
|
|||||||
|
|
||||||
g_waitsetPoolLock.Acquire();
|
g_waitsetPoolLock.Acquire();
|
||||||
for (int i = 0; i < MaxWaitsets; i++) {
|
for (int i = 0; i < MaxWaitsets; i++) {
|
||||||
if (g_waitsets[i].active) continue;
|
if (g_waitsets[i].active || g_waitsets[i].destroying) continue;
|
||||||
InitObject(g_waitsets[i], HandleType::Waitset);
|
InitObject(g_waitsets[i], HandleType::Waitset);
|
||||||
for (int j = 0; j < MaxWaitsetEntries; j++) {
|
for (int j = 0; j < MaxWaitsetEntries; j++) {
|
||||||
g_waitsets[i].entries[j].used = false;
|
g_waitsets[i].entries[j].used = false;
|
||||||
|
|||||||
@@ -121,8 +121,13 @@ struct TrueTypeFont {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
montauk::read(fd, data, 0, size);
|
int read_result = montauk::read(fd, data, 0, size);
|
||||||
montauk::close(fd);
|
montauk::close(fd);
|
||||||
|
if (read_result < 0 || (uint64_t)read_result != size) {
|
||||||
|
montauk::free(data);
|
||||||
|
data = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// stbtt_GetFontOffsetForIndex returns -1 for non-font data; passing
|
// stbtt_GetFontOffsetForIndex returns -1 for non-font data; passing
|
||||||
// that into stbtt_InitFont makes it dereference data + (uint32)-1.
|
// that into stbtt_InitFont makes it dereference data + (uint32)-1.
|
||||||
|
|||||||
Reference in New Issue
Block a user