Skip to content

Commit fb8c529

Browse files
authored
Fix a memory leak in BuildNodesArrayValues. (#693)
1 parent b70982e commit fb8c529

1 file changed

Lines changed: 55 additions & 21 deletions

File tree

src/bin/pg_autoctl/pgsql.c

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,12 +1491,30 @@ pgsql_drop_replication_slot(PGSQL *pgsql, const char *slotName)
14911491
* We return how many parameters we filled in paramTypes and paramValues from
14921492
* the nodeArray.
14931493
*/
1494-
static int
1494+
#define NODEID_MAX_LENGTH 20 /* should allow for bigint digits */
1495+
1496+
typedef struct nodesArraysValuesParams
1497+
{
1498+
int count;
1499+
Oid types[NODE_ARRAY_MAX_COUNT * 2];
1500+
char *values[NODE_ARRAY_MAX_COUNT * 2];
1501+
1502+
/*
1503+
* Pre-allocate arrays for the data separately from the values array, which
1504+
* needs to be a (const char **) thing rather than a (char [][]) thing,
1505+
* because of the pgsql_execute_with_params and libpq APIs.
1506+
*/
1507+
char nodeIds[NODE_ARRAY_MAX_COUNT][NODEID_MAX_LENGTH];
1508+
char lsns[NODE_ARRAY_MAX_COUNT][PG_LSN_MAXLENGTH];
1509+
} nodesArraysValuesParams;
1510+
1511+
1512+
static bool
14951513
BuildNodesArrayValues(NodeAddressArray *nodeArray,
1496-
Oid *paramTypes, char **paramValues,
1514+
nodesArraysValuesParams *sqlParams,
14971515
char *values, int size)
14981516
{
1499-
char buffer[BUFSIZE];
1517+
char buffer[BUFSIZE] = { 0 };
15001518
int nodeIndex = 0;
15011519
int paramIndex = 0;
15021520
int valuesIndex = 0;
@@ -1509,16 +1527,22 @@ BuildNodesArrayValues(NodeAddressArray *nodeArray,
15091527
for (nodeIndex = 0; nodeIndex < nodeArray->count; nodeIndex++)
15101528
{
15111529
NodeAddress *node = &(nodeArray->nodes[nodeIndex]);
1512-
IntString nodeIdString = intToString(node->nodeId);
1530+
char *nodeIdString = intToString(node->nodeId).strValue;
15131531

15141532
int idParamIndex = paramIndex;
15151533
int lsnParamIndex = paramIndex + 1;
15161534

1517-
paramTypes[idParamIndex] = INT4OID;
1518-
paramValues[idParamIndex] = strdup(nodeIdString.strValue);
1535+
sqlParams->types[idParamIndex] = INT4OID;
1536+
strlcpy(sqlParams->nodeIds[nodeIndex], nodeIdString, NODEID_MAX_LENGTH);
1537+
1538+
/* store the (char *) pointer to the data in values */
1539+
sqlParams->values[idParamIndex] = sqlParams->nodeIds[nodeIndex];
15191540

1520-
paramTypes[lsnParamIndex] = LSNOID;
1521-
paramValues[lsnParamIndex] = node->lsn;
1541+
sqlParams->types[lsnParamIndex] = LSNOID;
1542+
strlcpy(sqlParams->lsns[nodeIndex], node->lsn, PG_LSN_MAXLENGTH);
1543+
1544+
/* store the (char *) pointer to the data in values */
1545+
sqlParams->values[lsnParamIndex] = sqlParams->lsns[nodeIndex];
15221546

15231547
valuesIndex += sformat(buffer + valuesIndex, BUFSIZE - valuesIndex,
15241548
"%s($%d, $%d%s)",
@@ -1542,6 +1566,9 @@ BuildNodesArrayValues(NodeAddressArray *nodeArray,
15421566
paramIndex += 2;
15431567
}
15441568

1569+
/* count how many parameters where appended to the VALUES() parts */
1570+
sqlParams->count = paramIndex;
1571+
15451572
/* when we didn't find any node to process, return our empty set */
15461573
if (paramIndex == 0)
15471574
{
@@ -1563,7 +1590,8 @@ BuildNodesArrayValues(NodeAddressArray *nodeArray,
15631590
return false;
15641591
}
15651592
}
1566-
return paramIndex;
1593+
1594+
return true;
15671595
}
15681596

15691597

@@ -1615,13 +1643,14 @@ pgsql_replication_slot_create_and_drop(PGSQL *pgsql, NodeAddressArray *nodeArray
16151643
"SELECT 'drop', slot_name, NULL::pg_lsn FROM dropped";
16161644
/* *INDENT-ON* */
16171645

1618-
Oid paramTypes[NODE_ARRAY_MAX_COUNT * 2] = { 0 };
1619-
const char *paramValues[NODE_ARRAY_MAX_COUNT * 2] = { 0 };
1646+
nodesArraysValuesParams sqlParams = { 0 };
16201647
ReplicationSlotMaintainContext context = { 0 };
16211648

1622-
int paramCount = BuildNodesArrayValues(nodeArray,
1623-
paramTypes, (char **) paramValues,
1624-
values, BUFSIZE);
1649+
if (!BuildNodesArrayValues(nodeArray, &sqlParams, values, BUFSIZE))
1650+
{
1651+
/* errors have already been logged */
1652+
return false;
1653+
}
16251654

16261655
/* add the computed ($1,$2), ... string to the query "template" */
16271656
int bytes = sformat(sql, 2 * BUFSIZE, sqlTemplate, values);
@@ -1635,7 +1664,9 @@ pgsql_replication_slot_create_and_drop(PGSQL *pgsql, NodeAddressArray *nodeArray
16351664
}
16361665

16371666
return pgsql_execute_with_params(pgsql, sql,
1638-
paramCount, paramTypes, paramValues,
1667+
sqlParams.count,
1668+
sqlParams.types,
1669+
(const char **) sqlParams.values,
16391670
&context,
16401671
parseReplicationSlotMaintain);
16411672
}
@@ -1686,13 +1717,14 @@ pgsql_replication_slot_maintain(PGSQL *pgsql, NodeAddressArray *nodeArray)
16861717
"SELECT 'advance', slot_name, end_lsn FROM advanced ";
16871718
/* *INDENT-ON* */
16881719

1689-
Oid paramTypes[NODE_ARRAY_MAX_COUNT * 2] = { 0 };
1690-
const char *paramValues[NODE_ARRAY_MAX_COUNT * 2] = { 0 };
1720+
nodesArraysValuesParams sqlParams = { 0 };
16911721
ReplicationSlotMaintainContext context = { 0 };
16921722

1693-
int paramCount = BuildNodesArrayValues(nodeArray,
1694-
paramTypes, (char **) paramValues,
1695-
values, BUFSIZE);
1723+
if (!BuildNodesArrayValues(nodeArray, &sqlParams, values, BUFSIZE))
1724+
{
1725+
/* errors have already been logged */
1726+
return false;
1727+
}
16961728

16971729
/* add the computed ($1,$2), ... string to the query "template" */
16981730
int bytes = sformat(sql, 2 * BUFSIZE, sqlTemplate, values);
@@ -1706,7 +1738,9 @@ pgsql_replication_slot_maintain(PGSQL *pgsql, NodeAddressArray *nodeArray)
17061738
}
17071739

17081740
return pgsql_execute_with_params(pgsql, sql,
1709-
paramCount, paramTypes, paramValues,
1741+
sqlParams.count,
1742+
sqlParams.types,
1743+
(const char **) sqlParams.values,
17101744
&context,
17111745
parseReplicationSlotMaintain);
17121746
}

0 commit comments

Comments
 (0)