Skip to content

Commit 7043fa0

Browse files
authored
Add valgrind to C tests (#216)
Fix some memory leaks. Add clean shutdown to the server test so it can be tested under valgrind. Send the stdout of client tests to /dev/null so they aren't so noisy. Add a client or server prefix to all stderr messages to distinguish which side they came from.
1 parent b731e61 commit 7043fa0

File tree

6 files changed

+104
-77
lines changed

6 files changed

+104
-77
lines changed

.github/workflows/test.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,20 @@ jobs:
3737
override: true
3838
- run: make CC=${{ matrix.cc }} PROFILE=release test
3939

40+
valgrind:
41+
name: Valgrind
42+
runs-on: ubuntu-latest
43+
steps:
44+
- uses: actions/checkout@v2
45+
with:
46+
persist-credentials: false
47+
- name: Install valgrind
48+
run: sudo apt-get install -y valgrind
49+
- run: export VALGRIND="valgrind -q"
50+
- run: make test
51+
4052
test-windows:
53+
name: Windows
4154
runs-on: windows-latest
4255
steps:
4356
- uses: actions/checkout@v2

test.sh

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ kill_server() {
3434
kill "${SERVER_PID}"
3535
}
3636

37+
VALGRIND="${VALGRIND:-}"
38+
3739
run_client_tests() {
38-
CA_FILE=minica.pem ./target/client localhost 8443 /
39-
NO_CHECK_CERTIFICATE='' ./target/client localhost 8443 /
40-
CA_FILE=minica.pem VECTORED_IO='' ./target/client localhost 8443 /
40+
CA_FILE=minica.pem $VALGRIND ./target/client localhost 8443 /
41+
NO_CHECK_CERTIFICATE='' $VALGRIND ./target/client localhost 8443 /
42+
CA_FILE=minica.pem VECTORED_IO='' $VALGRIND ./target/client localhost 8443 /
4143
}
4244

4345
if port_is_open localhost 8443 ; then
@@ -46,19 +48,19 @@ if port_is_open localhost 8443 ; then
4648
fi
4749

4850
# Start server in default config.
49-
./target/server localhost/cert.pem localhost/key.pem &
51+
$VALGRIND ./target/server localhost/cert.pem localhost/key.pem &
5052
SERVER_PID=$!
5153
trap kill_server EXIT
5254

5355
wait_tcp_port localhost 8443
54-
run_client_tests
56+
run_client_tests > /dev/null
5557

5658
kill_server
5759
sleep 1
5860

5961
# Start server with vectored I/O
60-
VECTORED_IO='' ./target/server localhost/cert.pem localhost/key.pem &
62+
VECTORED_IO='' $VALGRIND ./target/server localhost/cert.pem localhost/key.pem &
6163
SERVER_PID=$!
6264
wait_tcp_port localhost 8443
6365

64-
run_client_tests
66+
run_client_tests > /dev/null

tests/client.c

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ make_conn(const char *hostname, const char *port)
6666
int getaddrinfo_result =
6767
getaddrinfo(hostname, port, &hints, &getaddrinfo_output);
6868
if(getaddrinfo_result != 0) {
69-
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(getaddrinfo_result));
69+
fprintf(stderr, "client: getaddrinfo: %s\n", gai_strerror(getaddrinfo_result));
7070
goto cleanup;
7171
}
7272

@@ -125,18 +125,18 @@ do_read(struct conndata *conn, struct rustls_connection *rconn)
125125

126126
if(err == EAGAIN || err == EWOULDBLOCK) {
127127
fprintf(stderr,
128-
"reading from socket: EAGAIN or EWOULDBLOCK: %s\n",
128+
"client: reading from socket: EAGAIN or EWOULDBLOCK: %s\n",
129129
strerror(errno));
130130
return CRUSTLS_DEMO_AGAIN;
131131
}
132132
else if(err != 0) {
133-
fprintf(stderr, "reading from socket: errno %d\n", err);
133+
fprintf(stderr, "client: reading from socket: errno %d\n", err);
134134
return CRUSTLS_DEMO_ERROR;
135135
}
136136

137137
result = rustls_connection_process_new_packets(rconn);
138138
if(result != RUSTLS_RESULT_OK) {
139-
print_error("in process_new_packets", result);
139+
print_error("server", "in process_new_packets", result);
140140
return CRUSTLS_DEMO_ERROR;
141141
}
142142

@@ -150,13 +150,13 @@ do_read(struct conndata *conn, struct rustls_connection *rconn)
150150
signed_n = read(conn->fd, buf, sizeof(buf));
151151
if(signed_n > 0) {
152152
fprintf(stderr,
153-
"read returned %ld bytes after receiving close_notify\n",
153+
"client: error: read returned %ld bytes after receiving close_notify\n",
154154
n);
155155
return CRUSTLS_DEMO_ERROR;
156156
}
157157
else if (signed_n < 0 && errno != EWOULDBLOCK) {
158158
fprintf(stderr,
159-
"read returned incorrect error after receiving close_notify: %s\n",
159+
"client: error: read returned incorrect error after receiving close_notify: %s\n",
160160
strerror(errno));
161161
return CRUSTLS_DEMO_ERROR;
162162
}
@@ -208,12 +208,12 @@ send_request_and_read_response(struct conndata *conn,
208208
* us- to the rustls connection. */
209209
result = rustls_connection_write(rconn, (uint8_t *)buf, strlen(buf), &n);
210210
if(result != RUSTLS_RESULT_OK) {
211-
fprintf(stderr, "error writing plaintext bytes to rustls_connection\n");
211+
fprintf(stderr, "client: error writing plaintext bytes to rustls_connection\n");
212212
goto cleanup;
213213
}
214214
if(n != strlen(buf)) {
215215
fprintf(stderr,
216-
"short write writing plaintext bytes to rustls_connection\n");
216+
"client: short write writing plaintext bytes to rustls_connection\n");
217217
goto cleanup;
218218
}
219219

@@ -230,7 +230,7 @@ send_request_and_read_response(struct conndata *conn,
230230
}
231231

232232
if(!rustls_connection_wants_read(rconn) && !rustls_connection_wants_write(rconn)) {
233-
fprintf(stderr, "rustls wants neither read nor write. draining plaintext and exiting.\n");
233+
fprintf(stderr, "client: rustls wants neither read nor write. draining plaintext and exiting.\n");
234234
goto drain_plaintext;
235235
}
236236

@@ -241,11 +241,6 @@ send_request_and_read_response(struct conndata *conn,
241241
}
242242

243243
if(FD_ISSET(sockfd, &read_fds)) {
244-
fprintf(
245-
stderr,
246-
"rustls_connection wants us to read_tls. First we need to pull some "
247-
"bytes from the socket\n");
248-
249244
/* Read all bytes until we get EAGAIN. Then loop again to wind up in
250245
select awaiting the next bit of data. */
251246
for(;;) {
@@ -263,26 +258,26 @@ send_request_and_read_response(struct conndata *conn,
263258
body = body_beginning(&conn->data);
264259
if(body != NULL) {
265260
headers_len = body - conn->data.data;
266-
fprintf(stderr, "body began at %ld\n", headers_len);
261+
fprintf(stderr, "client: body began at %ld\n", headers_len);
267262
content_length_str = get_first_header_value(conn->data.data,
268263
headers_len,
269264
CONTENT_LENGTH,
270265
strlen(CONTENT_LENGTH),
271266
&n);
272267
if(content_length_str == NULL) {
273-
fprintf(stderr, "content length header not found\n");
268+
fprintf(stderr, "client: content length header not found\n");
274269
goto cleanup;
275270
}
276271
content_length =
277272
strtoul(content_length_str, (char **)&content_length_end, 10);
278273
if(content_length_end == content_length_str) {
279274
fprintf(stderr,
280-
"invalid Content-Length '%.*s'\n",
275+
"client: invalid Content-Length '%.*s'\n",
281276
(int)n,
282277
content_length_str);
283278
goto cleanup;
284279
}
285-
fprintf(stderr, "content length %ld\n", content_length);
280+
fprintf(stderr, "client: content length %ld\n", content_length);
286281
}
287282
}
288283
if(headers_len != 0 &&
@@ -292,36 +287,35 @@ send_request_and_read_response(struct conndata *conn,
292287
}
293288
}
294289
if(FD_ISSET(sockfd, &write_fds)) {
295-
fprintf(stderr, "rustls_connection wants us to write_tls.\n");
296290
for(;;) {
297291
/* This invokes rustls_connection_write_tls. We pass a callback to
298292
* that function. Rustls will pass a buffer to that callback with
299293
* encrypted bytes, that we will write to `conn`. */
300294
err = write_tls(rconn, conn, &n);
301295
if(err != 0) {
302296
fprintf(
303-
stderr, "Error in rustls_connection_write_tls: errno %d\n", err);
297+
stderr, "client: error in rustls_connection_write_tls: errno %d\n", err);
304298
goto cleanup;
305299
}
306300
if(result == CRUSTLS_DEMO_AGAIN) {
307301
break;
308302
}
309303
else if(n == 0) {
310-
fprintf(stderr, "write 0 from rustls_connection_write_tls\n");
304+
fprintf(stderr, "client: write returned 0 from rustls_connection_write_tls\n");
311305
break;
312306
}
313307
}
314308
}
315309
}
316310

317-
fprintf(stderr, "send_request_and_read_response: loop fell through");
311+
fprintf(stderr, "client: send_request_and_read_response: loop fell through");
318312

319313
drain_plaintext:
320314
result = copy_plaintext_to_buffer(conn);
321315
if(result != CRUSTLS_DEMO_OK && result != CRUSTLS_DEMO_EOF) {
322316
goto cleanup;
323317
}
324-
fprintf(stderr, "writing %ld bytes to stdout\n", conn->data.len);
318+
fprintf(stderr, "client: writing %ld bytes to stdout\n", conn->data.len);
325319
if(write(STDOUT_FILENO, conn->data.data, conn->data.len) < 0) {
326320
fprintf(stderr, "error writing to stderr\n");
327321
goto cleanup;
@@ -351,7 +345,7 @@ do_request(const struct rustls_client_config *client_config,
351345
rustls_result result =
352346
rustls_client_connection_new(client_config, hostname, &rconn);
353347
if(result != RUSTLS_RESULT_OK) {
354-
print_error("client_connection_new", result);
348+
print_error("server", "client_connection_new", result);
355349
goto cleanup;
356350
}
357351

@@ -399,20 +393,20 @@ verify(void *userdata, const rustls_verify_server_cert_params *params)
399393
struct conndata *conn = (struct conndata *)userdata;
400394

401395
fprintf(stderr,
402-
"custom certificate verifier called for %.*s\n",
396+
"client: custom certificate verifier called for %.*s\n",
403397
(int)params->dns_name.len,
404398
params->dns_name.data);
405-
fprintf(stderr, "end entity len: %ld\n", params->end_entity_cert_der.len);
406-
fprintf(stderr, "intermediates:\n");
399+
fprintf(stderr, "client: end entity len: %ld\n", params->end_entity_cert_der.len);
400+
fprintf(stderr, "client: intermediates:\n");
407401
for(i = 0; i < intermediates_len; i++) {
408402
bytes = rustls_slice_slice_bytes_get(intermediates, i);
409403
if(bytes.data != NULL) {
410-
fprintf(stderr, " intermediate, len = %ld\n", bytes.len);
404+
fprintf(stderr, "client: intermediate, len = %ld\n", bytes.len);
411405
}
412406
}
413-
fprintf(stderr, "ocsp response len: %ld\n", params->ocsp_response.len);
407+
fprintf(stderr, "client: ocsp response len: %ld\n", params->ocsp_response.len);
414408
if(0 != strcmp(conn->verify_arg, "verify_arg")) {
415-
fprintf(stderr, "invalid argument to verify: %p\n", userdata);
409+
fprintf(stderr, "client: invalid argument to verify: %p\n", userdata);
416410
return RUSTLS_RESULT_GENERAL;
417411
}
418412
return RUSTLS_RESULT_OK;
@@ -454,14 +448,14 @@ main(int argc, const char **argv)
454448
result = rustls_client_config_builder_load_roots_from_file(
455449
config_builder, getenv("CA_FILE"));
456450
if(result != RUSTLS_RESULT_OK) {
457-
print_error("loading trusted certificates", result);
451+
print_error("server", "loading trusted certificates", result);
458452
goto cleanup;
459453
}
460454
} else if(getenv("NO_CHECK_CERTIFICATE")) {
461455
rustls_client_config_builder_dangerous_set_certificate_verifier(
462456
config_builder, verify);
463457
} else {
464-
fprintf(stderr, "must set either CA_FILE or NO_CHECK_CERTIFICATE env var\n");
458+
fprintf(stderr, "client: must set either CA_FILE or NO_CHECK_CERTIFICATE env var\n");
465459
goto cleanup;
466460
}
467461

tests/common.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626
#include "common.h"
2727

2828
void
29-
print_error(char *prefix, rustls_result result)
29+
print_error(const char *program_name, const char *prefix, rustls_result result)
3030
{
3131
char buf[256];
3232
size_t n;
3333
rustls_error(result, buf, sizeof(buf), &n);
34-
fprintf(stderr, "%s: %.*s\n", prefix, (int)n, buf);
34+
fprintf(stderr, "%s: %s: %.*s\n", program_name, prefix, (int)n, buf);
3535
}
3636

3737
#ifdef _WIN32
@@ -140,7 +140,6 @@ write_tls(struct rustls_connection *rconn, struct conndata *conn, size_t *n)
140140
return rustls_connection_write_tls(rconn, write_cb, conn, n);
141141
#else
142142
if(getenv("VECTORED_IO")) {
143-
fprintf(stderr, "(vectored)\n");
144143
return rustls_connection_write_tls_vectored(rconn, write_vectored_cb, conn, n);
145144
} else {
146145
return rustls_connection_write_tls(rconn, write_cb, conn, n);
@@ -231,7 +230,7 @@ copy_plaintext_to_buffer(struct conndata *conn)
231230
return CRUSTLS_DEMO_OK;
232231
}
233232
if(result != RUSTLS_RESULT_OK) {
234-
print_error("Error in rustls_connection_read", result);
233+
print_error(conn->program_name, "Error in rustls_connection_read", result);
235234
return CRUSTLS_DEMO_ERROR;
236235
}
237236
if(n == 0) {

tests/common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct conndata {
2525
};
2626

2727
void
28-
print_error(char *prefix, rustls_result result);
28+
print_error(const char *program_name, const char *prefix, rustls_result result);
2929

3030
int
3131
write_all(int fd, const char *buf, int n);

0 commit comments

Comments
 (0)