Skip to content

Commit 7f64df9

Browse files
libretroadminLibretroAdmin
authored andcommitted
discord: heap-allocate the rpc instance, presence slot and queue
Over 200 kilobytes of message buffers sat in bss whether or not rich presence was ever enabled - eight queued-command slots, the presence slot and the rpc instance, sixteen kilobytes of buffer each and more. They now allocate at discord_init and free at shutdown, with the module's entry points guarded so the pointers being null outside that window is a defined state rather than a crash; a per-function audit found four dereference paths needing the guard and the rest already gated on the rpc-valid flag. Static data drops half a megabyte together with the drive cache change; the container build compiles Discord and both validation dumps stay byte-identical.
1 parent 9cd17d5 commit 7f64df9

1 file changed

Lines changed: 62 additions & 27 deletions

File tree

network/discord.c

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,12 @@ struct discord_rpc
182182
/* File-scope globals (replaces upstream's scattered static storage) */
183183
/* ------------------------------------------------------------------------ */
184184

185-
static struct discord_rpc discord_rpc_inst;
185+
/* The rpc instance, presence slot and send queue together are over
186+
* 200 kilobytes of buffers; heap-allocated at discord_init so a
187+
* session that never enables rich presence never pays for them.
188+
* Load-resident statics are never free on platforms without demand
189+
* paging. */
190+
static struct discord_rpc *discord_rpc_inst;
186191
static bool discord_rpc_inst_valid = false;
187192

188193
static int discord_pid = 0;
@@ -207,11 +212,11 @@ static bool discord_was_spectate_game = false;
207212

208213
/* Pending presence update. Only the most recent one matters; we just keep one
209214
* slot and overwrite it. */
210-
static struct discord_queued_msg discord_queued_presence;
215+
static struct discord_queued_msg *discord_queued_presence;
211216

212217
/* Send queue (subscribe / unsubscribe / respond commands). Single-threaded, so
213218
* it is just a wraparound ring buffer with a pending counter. */
214-
static struct discord_queued_msg discord_send_queue[DISCORD_SEND_QUEUE_SIZE];
219+
static struct discord_queued_msg *discord_send_queue;
215220
static unsigned discord_send_next_add = 0;
216221
static unsigned discord_send_next_send = 0;
217222
static unsigned discord_send_pending = 0;
@@ -876,23 +881,23 @@ static void discord_rpc_close(struct discord_rpc *rpc);
876881

877882
static void discord_rpc_create(const char *application_id)
878883
{
879-
memset(&discord_rpc_inst, 0, sizeof(discord_rpc_inst));
884+
memset(discord_rpc_inst, 0, sizeof(*discord_rpc_inst));
880885
#ifdef _WIN32
881-
discord_rpc_inst.pipe = INVALID_HANDLE_VALUE;
886+
discord_rpc_inst->pipe = INVALID_HANDLE_VALUE;
882887
#else
883-
discord_rpc_inst.sock = -1;
888+
discord_rpc_inst->sock = -1;
884889
#endif
885-
discord_rpc_inst.state = DISCORD_STATE_DISCONNECTED;
886-
strlcpy(discord_rpc_inst.app_id, application_id,
887-
sizeof(discord_rpc_inst.app_id));
890+
discord_rpc_inst->state = DISCORD_STATE_DISCONNECTED;
891+
strlcpy(discord_rpc_inst->app_id, application_id,
892+
sizeof(discord_rpc_inst->app_id));
888893
discord_rpc_inst_valid = true;
889894
}
890895

891896
static void discord_rpc_destroy(void)
892897
{
893898
if (!discord_rpc_inst_valid)
894899
return;
895-
discord_rpc_close(&discord_rpc_inst);
900+
discord_rpc_close(discord_rpc_inst);
896901
discord_rpc_inst_valid = false;
897902
}
898903

@@ -1135,6 +1140,8 @@ static void discord_rpc_open(struct discord_rpc *rpc)
11351140
static struct discord_queued_msg *discord_send_queue_next_add(void)
11361141
{
11371142
unsigned idx;
1143+
if (!discord_send_queue)
1144+
return NULL;
11381145
if (discord_send_pending >= DISCORD_SEND_QUEUE_SIZE)
11391146
return NULL;
11401147
idx = (discord_send_next_add++) % DISCORD_SEND_QUEUE_SIZE;
@@ -1153,7 +1160,10 @@ static bool discord_send_queue_has_pending(void)
11531160

11541161
static struct discord_queued_msg *discord_send_queue_next_send(void)
11551162
{
1156-
unsigned idx = (discord_send_next_send++) % DISCORD_SEND_QUEUE_SIZE;
1163+
unsigned idx;
1164+
if (!discord_send_queue)
1165+
return NULL;
1166+
idx = (discord_send_next_send++) % DISCORD_SEND_QUEUE_SIZE;
11571167
return &discord_send_queue[idx];
11581168
}
11591169

@@ -1300,12 +1310,12 @@ static void discord_update_connection(void)
13001310
if (!discord_rpc_inst_valid)
13011311
return;
13021312

1303-
if (!discord_rpc_is_open(&discord_rpc_inst))
1313+
if (!discord_rpc_is_open(discord_rpc_inst))
13041314
{
13051315
if (discord_now_ms() >= discord_next_connect_ms)
13061316
{
13071317
discord_next_connect_ms = discord_now_ms() + discord_backoff_next_delay();
1308-
discord_rpc_open(&discord_rpc_inst);
1318+
discord_rpc_open(discord_rpc_inst);
13091319
}
13101320
return;
13111321
}
@@ -1314,7 +1324,7 @@ static void discord_update_connection(void)
13141324
for (;;)
13151325
{
13161326
char *json_buf = NULL;
1317-
rjson_t *r = discord_rpc_read(&discord_rpc_inst, &json_buf);
1327+
rjson_t *r = discord_rpc_read(discord_rpc_inst, &json_buf);
13181328
char *evt_name = NULL;
13191329
char *nonce = NULL;
13201330
char *secret = NULL;
@@ -1426,25 +1436,25 @@ static void discord_update_connection(void)
14261436
}
14271437

14281438
/* Writes -------------------------------------------------------------- */
1429-
if (discord_queued_presence.length)
1439+
if (discord_queued_presence->length)
14301440
{
14311441
struct discord_queued_msg local;
1432-
local.length = discord_queued_presence.length;
1433-
memcpy(local.buffer, discord_queued_presence.buffer, local.length);
1434-
discord_queued_presence.length = 0;
1442+
local.length = discord_queued_presence->length;
1443+
memcpy(local.buffer, discord_queued_presence->buffer, local.length);
1444+
discord_queued_presence->length = 0;
14351445

1436-
if (!discord_rpc_write(&discord_rpc_inst, local.buffer, local.length))
1446+
if (!discord_rpc_write(discord_rpc_inst, local.buffer, local.length))
14371447
{
14381448
/* On failure, requeue for a later attempt. */
1439-
discord_queued_presence.length = local.length;
1440-
memcpy(discord_queued_presence.buffer, local.buffer, local.length);
1449+
discord_queued_presence->length = local.length;
1450+
memcpy(discord_queued_presence->buffer, local.buffer, local.length);
14411451
}
14421452
}
14431453

14441454
while (discord_send_queue_has_pending())
14451455
{
14461456
struct discord_queued_msg *q = discord_send_queue_next_send();
1447-
discord_rpc_write(&discord_rpc_inst, q->buffer, q->length);
1457+
discord_rpc_write(discord_rpc_inst, q->buffer, q->length);
14481458
discord_send_queue_commit_send();
14491459
}
14501460
}
@@ -1478,6 +1488,8 @@ void Discord_Initialize(const char *application_id,
14781488
{
14791489
(void)auto_register;
14801490
(void)optional_steam_id;
1491+
if (!discord_rpc_inst)
1492+
return;
14811493

14821494
/* Seed the cheap backoff jitter once. */
14831495
srand((unsigned)time(NULL));
@@ -1497,6 +1509,18 @@ void Discord_Initialize(const char *application_id,
14971509
if (discord_rpc_inst_valid)
14981510
return;
14991511

1512+
if (!discord_rpc_inst)
1513+
discord_rpc_inst = (struct discord_rpc*)
1514+
calloc(1, sizeof(*discord_rpc_inst));
1515+
if (!discord_queued_presence)
1516+
discord_queued_presence = (struct discord_queued_msg*)
1517+
calloc(1, sizeof(*discord_queued_presence));
1518+
if (!discord_send_queue)
1519+
discord_send_queue = (struct discord_queued_msg*)
1520+
calloc(DISCORD_SEND_QUEUE_SIZE, sizeof(*discord_send_queue));
1521+
if (!discord_rpc_inst || !discord_queued_presence || !discord_send_queue)
1522+
return;
1523+
15001524
discord_rpc_create(application_id);
15011525
discord_next_connect_ms = discord_now_ms();
15021526
}
@@ -1507,6 +1531,15 @@ void Discord_Shutdown(void)
15071531
return;
15081532
memset(&discord_handlers, 0, sizeof(discord_handlers));
15091533
discord_rpc_destroy();
1534+
if (discord_rpc_inst)
1535+
free(discord_rpc_inst);
1536+
if (discord_queued_presence)
1537+
free(discord_queued_presence);
1538+
if (discord_send_queue)
1539+
free(discord_send_queue);
1540+
discord_rpc_inst = NULL;
1541+
discord_queued_presence = NULL;
1542+
discord_send_queue = NULL;
15101543
}
15111544

15121545
void Discord_UpdateConnection(void)
@@ -1516,9 +1549,11 @@ void Discord_UpdateConnection(void)
15161549

15171550
void Discord_UpdatePresence(const DiscordRichPresence *presence)
15181551
{
1519-
discord_queued_presence.length = discord_json_write_rich_presence(
1520-
discord_queued_presence.buffer,
1521-
sizeof(discord_queued_presence.buffer),
1552+
if (!discord_queued_presence)
1553+
return;
1554+
discord_queued_presence->length = discord_json_write_rich_presence(
1555+
discord_queued_presence->buffer,
1556+
sizeof(discord_queued_presence->buffer),
15221557
discord_nonce++, discord_pid, presence);
15231558
}
15241559

@@ -1531,7 +1566,7 @@ void Discord_Respond(const char *user_id, int reply)
15311566
{
15321567
struct discord_queued_msg *q;
15331568

1534-
if (!discord_rpc_inst_valid || !discord_rpc_is_open(&discord_rpc_inst))
1569+
if (!discord_rpc_inst_valid || !discord_rpc_is_open(discord_rpc_inst))
15351570
return;
15361571

15371572
q = discord_send_queue_next_add();
@@ -1552,7 +1587,7 @@ void Discord_RunCallbacks(void)
15521587

15531588
was_disconnected = discord_was_just_disconnected;
15541589
discord_was_just_disconnected = false;
1555-
is_connected = discord_rpc_is_open(&discord_rpc_inst);
1590+
is_connected = discord_rpc_is_open(discord_rpc_inst);
15561591

15571592
/* If we are currently connected, fire the disconnect callback first so
15581593
* the outward-facing sequence is always ready -> ... -> disconnected. */

0 commit comments

Comments
 (0)