Skip to content

Commit 10fff47

Browse files
committed
Support custom allocators
And hook Ruby's allocator in the Ruby extension. This is largely copied from how prism do it. We had several bugs in the past where we were freeing memory allocated by Ruby with the system allocator and vice-versa. It is much simpler if we only use one allocator, and it also has the benefit of feeding Ruby GC with malloc statistics.
1 parent 894e2a6 commit 10fff47

File tree

8 files changed

+103
-53
lines changed

8 files changed

+103
-53
lines changed

contrib/ruby/ext/trilogy-ruby/cext.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@ static void buffer_pool_free(void *data)
4141
buffer_pool *pool = (buffer_pool *)data;
4242
if (pool->capa) {
4343
for (size_t index = 0; index < pool->len; index++) {
44-
// NB: buff was allocated by trilogy/buffer.h using raw `malloc`
45-
// hence we must use raw `free`.
46-
free(pool->entries[index].buff);
44+
xfree(pool->entries[index].buff);
4745
}
4846
xfree(pool->entries);
4947
}
@@ -124,7 +122,7 @@ static void buffer_checkout(trilogy_buffer_t *buffer, size_t initial_capacity)
124122
buffer->buff = pool->entries[pool->len].buff;
125123
buffer->cap = pool->entries[pool->len].cap;
126124
} else {
127-
buffer->buff = malloc(initial_capacity);
125+
buffer->buff = xmalloc(initial_capacity);
128126
buffer->cap = initial_capacity;
129127
}
130128
}
@@ -134,7 +132,7 @@ static bool buffer_checkin(trilogy_buffer_t *buffer)
134132
buffer_pool * pool = get_buffer_pool();
135133

136134
if (pool->len >= BUFFER_POOL_MAX_SIZE) {
137-
free(buffer->buff);
135+
xfree(buffer->buff);
138136
buffer->buff = NULL;
139137
buffer->cap = 0;
140138
return false;

example/trilogy_query.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ static int execute_query(trilogy_conn_t *conn, const char *sql)
3838
rc = trilogy_read_full_column(conn, &column);
3939

4040
if (rc < 0) {
41-
free(binary_columns);
41+
xfree(binary_columns);
4242
return rc;
4343
}
4444

@@ -58,7 +58,7 @@ static int execute_query(trilogy_conn_t *conn, const char *sql)
5858

5959
// shut scan-build up
6060
if (column_count == 0) {
61-
free(binary_columns);
61+
xfree(binary_columns);
6262
return TRILOGY_OK;
6363
}
6464

@@ -84,8 +84,8 @@ static int execute_query(trilogy_conn_t *conn, const char *sql)
8484
printf("\n");
8585
}
8686

87-
free(binary_columns);
88-
free(values);
87+
xfree(binary_columns);
88+
xfree(values);
8989

9090
if (rc == TRILOGY_EOF) {
9191
rc = TRILOGY_OK;
@@ -145,7 +145,7 @@ int main(int argc, char *argv[])
145145
switch (opt) {
146146
case 'h':
147147
if (optarg) {
148-
free(connopt.hostname);
148+
xfree(connopt.hostname);
149149
connopt.hostname = strdup(optarg);
150150
}
151151
break;
@@ -156,25 +156,25 @@ int main(int argc, char *argv[])
156156
break;
157157
case 's':
158158
if (optarg) {
159-
free(sql);
159+
xfree(sql);
160160
sql = strdup(optarg);
161161
}
162162
break;
163163
case 'd':
164164
if (optarg) {
165-
free(connopt.database);
165+
xfree(connopt.database);
166166
connopt.database = strdup(optarg);
167167
}
168168
break;
169169
case 'u':
170170
if (optarg) {
171-
free(connopt.username);
171+
xfree(connopt.username);
172172
connopt.username = strdup(optarg);
173173
}
174174
break;
175175
case 'p':
176176
if (optarg) {
177-
free(connopt.password);
177+
xfree(connopt.password);
178178
connopt.password = strdup(optarg);
179179
connopt.password_len = strlen(optarg);
180180
}
@@ -224,11 +224,11 @@ int main(int argc, char *argv[])
224224
fail_on_error(&conn, err, "closing connection");
225225
fprintf(stderr, "connection closed\n");
226226

227-
free(connopt.hostname);
228-
free(connopt.username);
229-
free(sql);
230-
free(connopt.database);
231-
free(connopt.password);
227+
xfree(connopt.hostname);
228+
xfree(connopt.username);
229+
xfree(sql);
230+
xfree(connopt.database);
231+
xfree(connopt.password);
232232

233233
trilogy_free(&conn);
234234
exit(EXIT_SUCCESS);

inc/trilogy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef TRILOGY_H
22
#define TRILOGY_H
33

4+
#include "trilogy/allocator.h"
45
#include "trilogy/blocking.h"
56
#include "trilogy/client.h"
67
#include "trilogy/error.h"

inc/trilogy/allocator.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#ifndef TRILOGY_INTERNAL_ALLOCATOR_H
2+
#define TRILOGY_INTERNAL_ALLOCATOR_H
3+
4+
/* If you build Trilogy with a custom allocator, configure it with
5+
* "-D TRILOGY_XALLOCATOR" to use your own allocator that defines xmalloc,
6+
* xrealloc, xcalloc, and xfree.
7+
*
8+
* For example, your `trilogy_xallocator.h` file could look like this:
9+
*
10+
* ```
11+
* #ifndef TRILOGY_XALLOCATOR_H
12+
* #define TRILOGY_XALLOCATOR_H
13+
* #define xmalloc my_malloc
14+
* #define xrealloc my_realloc
15+
* #define xcalloc my_calloc
16+
* #define xfree my_free
17+
* #endif
18+
* ```
19+
*/
20+
#ifdef TRILOGY_XALLOCATOR
21+
#include "trilogy_xallocator.h"
22+
#else
23+
#ifndef xmalloc
24+
/* The malloc function that should be used. This can be overridden with
25+
* the TRILOGY_XALLOCATOR define. */
26+
#define xmalloc malloc
27+
#endif
28+
29+
#ifndef xrealloc
30+
/* The realloc function that should be used. This can be overridden with
31+
* the TRILOGY_XALLOCATOR define. */
32+
#define xrealloc realloc
33+
#endif
34+
35+
#ifndef xcalloc
36+
/* The calloc function that should be used. This can be overridden with
37+
* the TRILOGY_XALLOCATOR define. */
38+
#define xcalloc calloc
39+
#endif
40+
41+
#ifndef xfree
42+
/* The free function that should be used. This can be overridden with
43+
* the TRILOGY_XALLOCATOR define. */
44+
#define xfree free
45+
#endif
46+
#endif
47+
48+
#endif

src/buffer.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
#include <stdlib.h>
33
#include <string.h>
44

5+
#include "trilogy/allocator.h"
56
#include "trilogy/buffer.h"
67
#include "trilogy/error.h"
78

89
int trilogy_buffer_init(trilogy_buffer_t *buffer, size_t initial_capacity)
910
{
1011
buffer->len = 0;
1112
buffer->cap = initial_capacity;
12-
buffer->buff = malloc(initial_capacity);
13+
buffer->buff = xmalloc(initial_capacity);
1314

1415
if (buffer->buff == NULL) {
1516
return TRILOGY_SYSERR;
@@ -37,7 +38,7 @@ int trilogy_buffer_expand(trilogy_buffer_t *buffer, size_t needed)
3738
new_cap *= EXPAND_MULTIPLIER;
3839
}
3940

40-
uint8_t *new_buff = realloc(buffer->buff, new_cap);
41+
uint8_t *new_buff = xrealloc(buffer->buff, new_cap);
4142
if (new_buff == NULL)
4243
return TRILOGY_SYSERR;
4344

@@ -77,7 +78,7 @@ int trilogy_buffer_write(trilogy_buffer_t *buffer, const uint8_t *ptr, size_t le
7778
void trilogy_buffer_free(trilogy_buffer_t *buffer)
7879
{
7980
if (buffer->buff) {
80-
free(buffer->buff);
81+
xfree(buffer->buff);
8182
buffer->buff = NULL;
8283
buffer->len = buffer->cap = 0;
8384
}

src/client.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <stdlib.h>
88
#include <string.h>
99

10+
#include "trilogy/allocator.h"
1011
#include "trilogy/client.h"
1112
#include "trilogy/error.h"
1213

@@ -566,7 +567,7 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
566567
return TRILOGY_MEM_ERROR;
567568
}
568569
size_t plaintext_len = password_len + 1;
569-
uint8_t *plaintext = malloc(plaintext_len);
570+
uint8_t *plaintext = xmalloc(plaintext_len);
570571

571572
if (plaintext == NULL) {
572573
return TRILOGY_MEM_ERROR;
@@ -585,7 +586,7 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
585586

586587
BIO *bio = BIO_new_mem_buf((void *)key_data, (int)key_data_len);
587588
if (bio == NULL) {
588-
free(plaintext);
589+
xfree(plaintext);
589590
return TRILOGY_OPENSSL_ERR;
590591
}
591592

@@ -600,7 +601,7 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
600601
if (public_key == NULL) {
601602
ERR_clear_error();
602603
memset(plaintext, 0, plaintext_len);
603-
free(plaintext);
604+
xfree(plaintext);
604605
return TRILOGY_AUTH_PLUGIN_ERROR;
605606
}
606607

@@ -609,7 +610,7 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
609610
if (key_size <= 0) {
610611
EVP_PKEY_free(public_key);
611612
memset(plaintext, 0, plaintext_len);
612-
free(plaintext);
613+
xfree(plaintext);
613614
return TRILOGY_AUTH_PLUGIN_ERROR;
614615
}
615616
ciphertext_len = (size_t)key_size;
@@ -628,11 +629,11 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
628629
RSA_free(public_key);
629630
#endif
630631
memset(plaintext, 0, plaintext_len);
631-
free(plaintext);
632+
xfree(plaintext);
632633
return TRILOGY_AUTH_PLUGIN_ERROR;
633634
}
634635

635-
ciphertext = malloc(ciphertext_len);
636+
ciphertext = xmalloc(ciphertext_len);
636637

637638
if (ciphertext == NULL) {
638639
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
@@ -641,7 +642,7 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
641642
RSA_free(public_key);
642643
#endif
643644
memset(plaintext, 0, plaintext_len);
644-
free(plaintext);
645+
xfree(plaintext);
645646
return TRILOGY_MEM_ERROR;
646647
}
647648

@@ -676,13 +677,13 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
676677
#endif
677678

678679
memset(plaintext, 0, plaintext_len);
679-
free(plaintext);
680+
xfree(plaintext);
680681

681682
if (rc == TRILOGY_OK) {
682683
*encrypted_out = ciphertext;
683684
} else {
684685
memset(ciphertext, 0, ciphertext_len);
685-
free(ciphertext);
686+
xfree(ciphertext);
686687
}
687688

688689
return rc;
@@ -755,7 +756,7 @@ static int handle_fast_auth_fail(trilogy_conn_t *conn, trilogy_handshake_t *hand
755756

756757
rc = send_auth_buffer(conn, encrypted, encrypted_len);
757758
memset(encrypted, 0, encrypted_len);
758-
free(encrypted);
759+
xfree(encrypted);
759760

760761
if (rc < 0) {
761762
return rc;

src/socket.c

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <stdlib.h>
1212
#include <unistd.h>
1313

14+
#include "trilogy/allocator.h"
1415
#include "trilogy/error.h"
1516
#include "trilogy/socket.h"
1617

@@ -111,28 +112,28 @@ static int _cb_raw_close(trilogy_sock_t *_sock)
111112
if (sock->addr) {
112113
if (sock->base.opts.hostname == NULL && sock->base.opts.path != NULL) {
113114
/* We created these with calloc so must free them instead of calling freeaddrinfo */
114-
free(sock->addr->ai_addr);
115-
free(sock->addr);
115+
xfree(sock->addr->ai_addr);
116+
xfree(sock->addr);
116117
} else {
117118
freeaddrinfo(sock->addr);
118119
}
119120
}
120121

121-
free(sock->base.opts.hostname);
122-
free(sock->base.opts.path);
123-
free(sock->base.opts.database);
124-
free(sock->base.opts.username);
125-
free(sock->base.opts.password);
126-
free(sock->base.opts.ssl_ca);
127-
free(sock->base.opts.ssl_capath);
128-
free(sock->base.opts.ssl_cert);
129-
free(sock->base.opts.ssl_cipher);
130-
free(sock->base.opts.ssl_crl);
131-
free(sock->base.opts.ssl_crlpath);
132-
free(sock->base.opts.ssl_key);
133-
free(sock->base.opts.tls_ciphersuites);
122+
xfree(sock->base.opts.hostname);
123+
xfree(sock->base.opts.path);
124+
xfree(sock->base.opts.database);
125+
xfree(sock->base.opts.username);
126+
xfree(sock->base.opts.password);
127+
xfree(sock->base.opts.ssl_ca);
128+
xfree(sock->base.opts.ssl_capath);
129+
xfree(sock->base.opts.ssl_cert);
130+
xfree(sock->base.opts.ssl_cipher);
131+
xfree(sock->base.opts.ssl_crl);
132+
xfree(sock->base.opts.ssl_crlpath);
133+
xfree(sock->base.opts.ssl_key);
134+
xfree(sock->base.opts.tls_ciphersuites);
134135

135-
free(sock);
136+
xfree(sock);
136137
return rc;
137138
}
138139

@@ -311,7 +312,7 @@ static char *strdupnullok(const char *str)
311312

312313
trilogy_sock_t *trilogy_sock_new(const trilogy_sockopt_t *opts)
313314
{
314-
struct trilogy_sock *sock = malloc(sizeof(struct trilogy_sock));
315+
struct trilogy_sock *sock = xmalloc(sizeof(struct trilogy_sock));
315316

316317
sock->base.connect_cb = _cb_raw_connect;
317318
sock->base.read_cb = _cb_raw_read;
@@ -328,7 +329,7 @@ trilogy_sock_t *trilogy_sock_new(const trilogy_sockopt_t *opts)
328329
sock->base.opts.username = strdupnullok(opts->username);
329330

330331
if (sock->base.opts.password) {
331-
sock->base.opts.password = malloc(opts->password_len);
332+
sock->base.opts.password = xmalloc(opts->password_len);
332333
memcpy(sock->base.opts.password, opts->password, opts->password_len);
333334
}
334335

test/builder_test.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ TEST test_builder_write_uint8_split_packet()
6060
const uint8_t expected_header2[] = {0x01, 0x00, 0x00, 0x01};
6161
ASSERT_MEM_EQ(builder.buffer->buff + TRILOGY_MAX_PACKET_LEN + 4, expected_header2, sizeof(expected_header2));
6262

63-
free(bytes);
63+
xfree(bytes);
6464

6565
trilogy_buffer_free(&buff);
6666
PASS();
@@ -123,7 +123,7 @@ TEST test_builder_write_uint8_exceeds_large_max()
123123
err = trilogy_builder_write_uint8(&builder, 0x03);
124124
ASSERT_EQ(TRILOGY_MAX_PACKET_EXCEEDED, err);
125125

126-
free(bytes);
126+
xfree(bytes);
127127

128128
trilogy_buffer_free(&buff);
129129
PASS();
@@ -331,7 +331,7 @@ TEST test_builder_write_large_buffer()
331331
const uint8_t expected_header2[] = {0x0A, 0x00, 0x00, 0x01};
332332
ASSERT_MEM_EQ(builder.buffer->buff + TRILOGY_MAX_PACKET_LEN + 4, expected_header2, sizeof(expected_header2));
333333

334-
free(bytes);
334+
xfree(bytes);
335335

336336
trilogy_buffer_free(&buff);
337337
PASS();

0 commit comments

Comments
 (0)