Skip to content

Commit a857a26

Browse files
committed
docs(ffi): clarify ownership responsibilities in the C API
Curl had two memory leaks in its usage of the hyper C API. I fixed these in curl/curl#11729. While fixing these, as a hyper newbie I found a lack of clarity in the docs about where the responsibilities lie for allocating and deallocating things. I had to repeatedly look at the `Box::into_raw`/`Box::from_raw` calls in the C API code to properly understand things. This commit extends the docs. - For all functions that allocate things, make it clear which functions can be used to subsequently deallocate. - For all functions that free things, make it clear if there are (or aren't) other functions that may have otherwise consumed the thing, thus removing the need for explicit freeing. - Clarify some functions that consume things. This is the documentation I wished was present when I was fixing the leaks in curl.
1 parent e4b9fef commit a857a26

File tree

7 files changed

+182
-24
lines changed

7 files changed

+182
-24
lines changed

capi/include/hyper.h

Lines changed: 91 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ extern "C" {
191191
- `HYPER_TASK_ERROR`: An error retrieving the data.
192192
- `HYPER_TASK_EMPTY`: The body has finished streaming data.
193193
194+
To avoid a memory leak, the task must eventually be consumed by
195+
`hyper_task_free`, or taken ownership of by `hyper_executor_push`
196+
without subsequently being given back by `hyper_executor_poll`.
197+
194198
This does not consume the `hyper_body *`, so it may be used to again.
195199
However, it MUST NOT be used or freed until the related task completes.
196200
*/
@@ -200,6 +204,10 @@ hyper_task *hyper_body_data(hyper_body *body);
200204
Return a task that will poll the body and execute the callback with each
201205
body chunk that is received.
202206
207+
To avoid a memory leak, the task must eventually be consumed by
208+
`hyper_task_free`, or taken ownership of by `hyper_executor_push`
209+
without subsequently being given back by `hyper_executor_poll`.
210+
203211
The `hyper_buf` pointer is only a borrowed reference, it cannot live outside
204212
the execution of the callback. You must make a copy to retain it.
205213
@@ -211,14 +219,20 @@ hyper_task *hyper_body_data(hyper_body *body);
211219
hyper_task *hyper_body_foreach(hyper_body *body, hyper_body_foreach_callback func, void *userdata);
212220

213221
/*
214-
Free a `hyper_body *`.
222+
Free a body.
223+
224+
This should only be used if the request isn't consumed by
225+
`hyper_body_foreach` or `hyper_request_set_body`.
215226
*/
216227
void hyper_body_free(hyper_body *body);
217228

218229
/*
219230
Create a new "empty" body.
220231
221232
If not configured, this body acts as an empty payload.
233+
234+
To avoid a memory leak, the body must eventually be consumed by
235+
`hyper_body_free`, `hyper_body_foreach`, or `hyper_request_set_body`.
222236
*/
223237
hyper_body *hyper_body_new(void);
224238

@@ -265,14 +279,19 @@ const uint8_t *hyper_buf_bytes(const hyper_buf *buf);
265279
Create a new `hyper_buf *` by copying the provided bytes.
266280
267281
This makes an owned copy of the bytes, so the `buf` argument can be
268-
freed or changed afterwards.
282+
freed (with `hyper_buf_free`) or changed afterwards.
283+
284+
To avoid a memory leak, the copy must eventually be consumed by
285+
`hyper_buf_free`.
269286
270287
This returns `NULL` if allocating a new buffer fails.
271288
*/
272289
hyper_buf *hyper_buf_copy(const uint8_t *buf, size_t len);
273290

274291
/*
275292
Free this buffer.
293+
294+
This should be used for any buffer once it is no longer needed.
276295
*/
277296
void hyper_buf_free(hyper_buf *buf);
278297

@@ -283,6 +302,8 @@ size_t hyper_buf_len(const hyper_buf *buf);
283302

284303
/*
285304
Free a `hyper_clientconn *`.
305+
306+
This should be used for any connection once it is no longer needed.
286307
*/
287308
void hyper_clientconn_free(hyper_clientconn *conn);
288309

@@ -291,9 +312,14 @@ void hyper_clientconn_free(hyper_clientconn *conn);
291312
and options.
292313
293314
Both the `io` and the `options` are consumed in this function call.
315+
They should not be used or freed afterwards.
294316
295-
The returned `hyper_task *` must be polled with an executor until the
296-
handshake completes, at which point the value can be taken.
317+
The returned task must be polled with an executor until the handshake
318+
completes, at which point the value can be taken.
319+
320+
To avoid a memory leak, the task must eventually be consumed by
321+
`hyper_task_free`, or taken ownership of by `hyper_executor_push`
322+
without subsequently being given back by `hyper_executor_poll`.
297323
*/
298324
hyper_task *hyper_clientconn_handshake(hyper_io *io, hyper_clientconn_options *options);
299325

@@ -305,7 +331,10 @@ hyper_task *hyper_clientconn_handshake(hyper_io *io, hyper_clientconn_options *o
305331
void hyper_clientconn_options_exec(hyper_clientconn_options *opts, const hyper_executor *exec);
306332

307333
/*
308-
Free a `hyper_clientconn_options *`.
334+
Free a set of HTTP clientconn options.
335+
336+
This should only be used if the options aren't consumed by
337+
`hyper_clientconn_handshake`.
309338
*/
310339
void hyper_clientconn_options_free(hyper_clientconn_options *opts);
311340

@@ -328,6 +357,9 @@ hyper_code hyper_clientconn_options_http2(hyper_clientconn_options *opts, int en
328357

329358
/*
330359
Creates a new set of HTTP clientconn options to be used in a handshake.
360+
361+
To avoid a memory leak, the options must eventually be consumed by
362+
`hyper_clientconn_options_free` or `hyper_clientconn_handshake`.
331363
*/
332364
hyper_clientconn_options *hyper_clientconn_options_new(void);
333365

@@ -349,13 +381,23 @@ void hyper_clientconn_options_set_preserve_header_order(hyper_clientconn_options
349381
/*
350382
Send a request on the client connection.
351383
384+
This consumes the request. You should not use or free the request
385+
afterwards.
386+
352387
Returns a task that needs to be polled until it is ready. When ready, the
353388
task yields a `hyper_response *`.
389+
390+
To avoid a memory leak, the task must eventually be consumed by
391+
`hyper_task_free`, or taken ownership of by `hyper_executor_push`
392+
without subsequently being given back by `hyper_executor_poll`.
354393
*/
355394
hyper_task *hyper_clientconn_send(hyper_clientconn *conn, hyper_request *req);
356395

357396
/*
358397
Copies a waker out of the task context.
398+
399+
To avoid a memory leak, the waker must eventually be consumed by
400+
`hyper_waker_free` or `hyper_waker_wake`.
359401
*/
360402
hyper_waker *hyper_context_waker(hyper_context *cx);
361403

@@ -366,6 +408,8 @@ hyper_code hyper_error_code(const hyper_error *err);
366408

367409
/*
368410
Frees a `hyper_error`.
411+
412+
This should be used for any error once it is no longer needed.
369413
*/
370414
void hyper_error_free(hyper_error *err);
371415

@@ -381,11 +425,16 @@ size_t hyper_error_print(const hyper_error *err, uint8_t *dst, size_t dst_len);
381425

382426
/*
383427
Frees an executor and any incomplete tasks still part of it.
428+
429+
This should be used for any executor once it is no longer needed.
384430
*/
385431
void hyper_executor_free(const hyper_executor *exec);
386432

387433
/*
388434
Creates a new task executor.
435+
436+
To avoid a memory leak, the executor must eventually be consumed by
437+
`hyper_executor_free`.
389438
*/
390439
const hyper_executor *hyper_executor_new(void);
391440

@@ -395,14 +444,18 @@ const hyper_executor *hyper_executor_new(void);
395444
396445
If ready, returns a task from the executor that has completed.
397446
447+
To avoid a memory leak, the task must eventually be consumed by
448+
`hyper_task_free`, or taken ownership of by `hyper_executor_push`
449+
without subsequently being given back by `hyper_executor_poll`.
450+
398451
If there are no ready tasks, this returns `NULL`.
399452
*/
400453
hyper_task *hyper_executor_poll(const hyper_executor *exec);
401454

402455
/*
403456
Push a task onto the executor.
404457
405-
The executor takes ownership of the task, it should not be accessed
458+
The executor takes ownership of the task, which should not be accessed
406459
again unless returned back to the user with `hyper_executor_poll`.
407460
*/
408461
hyper_code hyper_executor_push(const hyper_executor *exec, hyper_task *task);
@@ -443,10 +496,10 @@ hyper_code hyper_headers_set(hyper_headers *headers,
443496
size_t value_len);
444497

445498
/*
446-
Free an unused `hyper_io *`.
499+
Free an IO handle.
447500
448-
This is typically only useful if you aren't going to pass ownership
449-
of the IO handle to hyper, such as with `hyper_clientconn_handshake()`.
501+
This should only be used if the request isn't consumed by
502+
`hyper_clientconn_handshake`.
450503
*/
451504
void hyper_io_free(hyper_io *io);
452505

@@ -455,6 +508,9 @@ void hyper_io_free(hyper_io *io);
455508
456509
The read and write functions of this transport should be set with
457510
`hyper_io_set_read` and `hyper_io_set_write`.
511+
512+
To avoid a memory leak, the IO handle must eventually be consumed by
513+
`hyper_io_free` or `hyper_clientconn_handshake`.
458514
*/
459515
hyper_io *hyper_io_new(void);
460516

@@ -503,7 +559,10 @@ void hyper_io_set_userdata(hyper_io *io, void *data);
503559
void hyper_io_set_write(hyper_io *io, hyper_io_write_callback func);
504560

505561
/*
506-
Free an HTTP request if not going to send it on a client.
562+
Free an HTTP request.
563+
564+
This should only be used if the request isn't consumed by
565+
`hyper_clientconn_send`.
507566
*/
508567
void hyper_request_free(hyper_request *req);
509568

@@ -517,6 +576,9 @@ hyper_headers *hyper_request_headers(hyper_request *req);
517576

518577
/*
519578
Construct a new HTTP request.
579+
580+
To avoid a memory leak, the request must eventually be consumed by
581+
`hyper_request_free` or `hyper_clientconn_send`.
520582
*/
521583
hyper_request *hyper_request_new(void);
522584

@@ -605,11 +667,16 @@ hyper_code hyper_request_set_version(hyper_request *req, int version);
605667
Take ownership of the body of this response.
606668
607669
It is safe to free the response even after taking ownership of its body.
670+
671+
To avoid a memory leak, the body must eventually be consumed by
672+
`hyper_body_free`, `hyper_body_foreach`, or `hyper_request_set_body`.
608673
*/
609674
hyper_body *hyper_response_body(hyper_response *resp);
610675

611676
/*
612-
Free an HTTP response after using it.
677+
Free an HTTP response.
678+
679+
This should be used for any response once it is no longer needed.
613680
*/
614681
void hyper_response_free(hyper_response *resp);
615682

@@ -662,6 +729,10 @@ int hyper_response_version(const hyper_response *resp);
662729

663730
/*
664731
Free a task.
732+
733+
This should only be used if the task isn't consumed by
734+
`hyper_clientconn_handshake` or taken ownership of by
735+
`hyper_executor_push`.
665736
*/
666737
void hyper_task_free(hyper_task *task);
667738

@@ -690,6 +761,11 @@ void *hyper_task_userdata(hyper_task *task);
690761
this task.
691762
692763
Use `hyper_task_type` to determine the type of the `void *` return value.
764+
765+
To avoid a memory leak, a non-empty return value must eventually be
766+
consumed by a function appropriate for its type, one of
767+
`hyper_error_free`, `hyper_clientconn_free`, `hyper_response_free`, or
768+
`hyper_buf_free`.
693769
*/
694770
void *hyper_task_value(hyper_task *task);
695771

@@ -699,7 +775,10 @@ void *hyper_task_value(hyper_task *task);
699775
const char *hyper_version(void);
700776

701777
/*
702-
Free a waker that hasn't been woken.
778+
Free a waker.
779+
780+
This should only be used if the request isn't consumed by
781+
`hyper_waker_wake`.
703782
*/
704783
void hyper_waker_free(hyper_waker *waker);
705784

src/ffi/body.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,19 @@ ffi_fn! {
3232
/// Create a new "empty" body.
3333
///
3434
/// If not configured, this body acts as an empty payload.
35+
///
36+
/// To avoid a memory leak, the body must eventually be consumed by
37+
/// `hyper_body_free`, `hyper_body_foreach`, or `hyper_request_set_body`.
3538
fn hyper_body_new() -> *mut hyper_body {
3639
Box::into_raw(Box::new(hyper_body(IncomingBody::ffi())))
3740
} ?= ptr::null_mut()
3841
}
3942

4043
ffi_fn! {
41-
/// Free a `hyper_body *`.
44+
/// Free a body.
45+
///
46+
/// This should only be used if the request isn't consumed by
47+
/// `hyper_body_foreach` or `hyper_request_set_body`.
4248
fn hyper_body_free(body: *mut hyper_body) {
4349
drop(non_null!(Box::from_raw(body) ?= ()));
4450
}
@@ -53,6 +59,10 @@ ffi_fn! {
5359
/// - `HYPER_TASK_ERROR`: An error retrieving the data.
5460
/// - `HYPER_TASK_EMPTY`: The body has finished streaming data.
5561
///
62+
/// To avoid a memory leak, the task must eventually be consumed by
63+
/// `hyper_task_free`, or taken ownership of by `hyper_executor_push`
64+
/// without subsequently being given back by `hyper_executor_poll`.
65+
///
5666
/// This does not consume the `hyper_body *`, so it may be used to again.
5767
/// However, it MUST NOT be used or freed until the related task completes.
5868
fn hyper_body_data(body: *mut hyper_body) -> *mut hyper_task {
@@ -81,6 +91,10 @@ ffi_fn! {
8191
/// Return a task that will poll the body and execute the callback with each
8292
/// body chunk that is received.
8393
///
94+
/// To avoid a memory leak, the task must eventually be consumed by
95+
/// `hyper_task_free`, or taken ownership of by `hyper_executor_push`
96+
/// without subsequently being given back by `hyper_executor_poll`.
97+
///
8498
/// The `hyper_buf` pointer is only a borrowed reference, it cannot live outside
8599
/// the execution of the callback. You must make a copy to retain it.
86100
///
@@ -194,7 +208,10 @@ ffi_fn! {
194208
/// Create a new `hyper_buf *` by copying the provided bytes.
195209
///
196210
/// This makes an owned copy of the bytes, so the `buf` argument can be
197-
/// freed or changed afterwards.
211+
/// freed (with `hyper_buf_free`) or changed afterwards.
212+
///
213+
/// To avoid a memory leak, the copy must eventually be consumed by
214+
/// `hyper_buf_free`.
198215
///
199216
/// This returns `NULL` if allocating a new buffer fails.
200217
fn hyper_buf_copy(buf: *const u8, len: size_t) -> *mut hyper_buf {
@@ -227,6 +244,8 @@ ffi_fn! {
227244

228245
ffi_fn! {
229246
/// Free this buffer.
247+
///
248+
/// This should be used for any buffer once it is no longer needed.
230249
fn hyper_buf_free(buf: *mut hyper_buf) {
231250
drop(unsafe { Box::from_raw(buf) });
232251
}

0 commit comments

Comments
 (0)