Skip to content

Commit 82b7fa5

Browse files
nnethercoteseanmonstar
authored andcommitted
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 fced10a commit 82b7fa5

File tree

7 files changed

+182
-24
lines changed

7 files changed

+182
-24
lines changed

capi/include/hyper.h

+91-12
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,17 @@ const char *hyper_version(void);
229229
Create a new "empty" body.
230230
231231
If not configured, this body acts as an empty payload.
232+
233+
To avoid a memory leak, the body must eventually be consumed by
234+
`hyper_body_free`, `hyper_body_foreach`, or `hyper_request_set_body`.
232235
*/
233236
struct hyper_body *hyper_body_new(void);
234237

235238
/*
236-
Free a `hyper_body *`.
239+
Free a body.
240+
241+
This should only be used if the request isn't consumed by
242+
`hyper_body_foreach` or `hyper_request_set_body`.
237243
*/
238244
void hyper_body_free(struct hyper_body *body);
239245

@@ -246,6 +252,10 @@ void hyper_body_free(struct hyper_body *body);
246252
- `HYPER_TASK_ERROR`: An error retrieving the data.
247253
- `HYPER_TASK_EMPTY`: The body has finished streaming data.
248254
255+
To avoid a memory leak, the task must eventually be consumed by
256+
`hyper_task_free`, or taken ownership of by `hyper_executor_push`
257+
without subsequently being given back by `hyper_executor_poll`.
258+
249259
This does not consume the `hyper_body *`, so it may be used to again.
250260
However, it MUST NOT be used or freed until the related task completes.
251261
*/
@@ -255,6 +265,10 @@ struct hyper_task *hyper_body_data(struct hyper_body *body);
255265
Return a task that will poll the body and execute the callback with each
256266
body chunk that is received.
257267
268+
To avoid a memory leak, the task must eventually be consumed by
269+
`hyper_task_free`, or taken ownership of by `hyper_executor_push`
270+
without subsequently being given back by `hyper_executor_poll`.
271+
258272
The `hyper_buf` pointer is only a borrowed reference, it cannot live outside
259273
the execution of the callback. You must make a copy to retain it.
260274
@@ -299,7 +313,10 @@ void hyper_body_set_data_func(struct hyper_body *body, hyper_body_data_callback
299313
Create a new `hyper_buf *` by copying the provided bytes.
300314
301315
This makes an owned copy of the bytes, so the `buf` argument can be
302-
freed or changed afterwards.
316+
freed (with `hyper_buf_free`) or changed afterwards.
317+
318+
To avoid a memory leak, the copy must eventually be consumed by
319+
`hyper_buf_free`.
303320
304321
This returns `NULL` if allocating a new buffer fails.
305322
*/
@@ -323,6 +340,8 @@ size_t hyper_buf_len(const struct hyper_buf *buf);
323340

324341
/*
325342
Free this buffer.
343+
344+
This should be used for any buffer once it is no longer needed.
326345
*/
327346
void hyper_buf_free(struct hyper_buf *buf);
328347

@@ -331,28 +350,45 @@ void hyper_buf_free(struct hyper_buf *buf);
331350
and options.
332351
333352
Both the `io` and the `options` are consumed in this function call.
353+
They should not be used or freed afterwards.
354+
355+
The returned task must be polled with an executor until the handshake
356+
completes, at which point the value can be taken.
334357
335-
The returned `hyper_task *` must be polled with an executor until the
336-
handshake completes, at which point the value can be taken.
358+
To avoid a memory leak, the task must eventually be consumed by
359+
`hyper_task_free`, or taken ownership of by `hyper_executor_push`
360+
without subsequently being given back by `hyper_executor_poll`.
337361
*/
338362
struct hyper_task *hyper_clientconn_handshake(struct hyper_io *io,
339363
struct hyper_clientconn_options *options);
340364

341365
/*
342366
Send a request on the client connection.
343367
368+
This consumes the request. You should not use or free the request
369+
afterwards.
370+
344371
Returns a task that needs to be polled until it is ready. When ready, the
345372
task yields a `hyper_response *`.
373+
374+
To avoid a memory leak, the task must eventually be consumed by
375+
`hyper_task_free`, or taken ownership of by `hyper_executor_push`
376+
without subsequently being given back by `hyper_executor_poll`.
346377
*/
347378
struct hyper_task *hyper_clientconn_send(struct hyper_clientconn *conn, struct hyper_request *req);
348379

349380
/*
350381
Free a `hyper_clientconn *`.
382+
383+
This should be used for any connection once it is no longer needed.
351384
*/
352385
void hyper_clientconn_free(struct hyper_clientconn *conn);
353386

354387
/*
355388
Creates a new set of HTTP clientconn options to be used in a handshake.
389+
390+
To avoid a memory leak, the options must eventually be consumed by
391+
`hyper_clientconn_options_free` or `hyper_clientconn_handshake`.
356392
*/
357393
struct hyper_clientconn_options *hyper_clientconn_options_new(void);
358394

@@ -373,7 +409,10 @@ void hyper_clientconn_options_set_preserve_header_order(struct hyper_clientconn_
373409
int enabled);
374410

375411
/*
376-
Free a `hyper_clientconn_options *`.
412+
Free a set of HTTP clientconn options.
413+
414+
This should only be used if the options aren't consumed by
415+
`hyper_clientconn_handshake`.
377416
*/
378417
void hyper_clientconn_options_free(struct hyper_clientconn_options *opts);
379418

@@ -404,6 +443,8 @@ enum hyper_code hyper_clientconn_options_http1_allow_multiline_headers(struct hy
404443

405444
/*
406445
Frees a `hyper_error`.
446+
447+
This should be used for any error once it is no longer needed.
407448
*/
408449
void hyper_error_free(struct hyper_error *err);
409450

@@ -424,11 +465,17 @@ size_t hyper_error_print(const struct hyper_error *err, uint8_t *dst, size_t dst
424465

425466
/*
426467
Construct a new HTTP request.
468+
469+
To avoid a memory leak, the request must eventually be consumed by
470+
`hyper_request_free` or `hyper_clientconn_send`.
427471
*/
428472
struct hyper_request *hyper_request_new(void);
429473

430474
/*
431-
Free an HTTP request if not going to send it on a client.
475+
Free an HTTP request.
476+
477+
This should only be used if the request isn't consumed by
478+
`hyper_clientconn_send`.
432479
*/
433480
void hyper_request_free(struct hyper_request *req);
434481

@@ -526,7 +573,9 @@ enum hyper_code hyper_request_on_informational(struct hyper_request *req,
526573
void *data);
527574

528575
/*
529-
Free an HTTP response after using it.
576+
Free an HTTP response.
577+
578+
This should be used for any response once it is no longer needed.
530579
*/
531580
void hyper_response_free(struct hyper_response *resp);
532581

@@ -581,6 +630,9 @@ struct hyper_headers *hyper_response_headers(struct hyper_response *resp);
581630
Take ownership of the body of this response.
582631
583632
It is safe to free the response even after taking ownership of its body.
633+
634+
To avoid a memory leak, the body must eventually be consumed by
635+
`hyper_body_free`, `hyper_body_foreach`, or `hyper_request_set_body`.
584636
*/
585637
struct hyper_body *hyper_response_body(struct hyper_response *resp);
586638

@@ -624,14 +676,17 @@ enum hyper_code hyper_headers_add(struct hyper_headers *headers,
624676
625677
The read and write functions of this transport should be set with
626678
`hyper_io_set_read` and `hyper_io_set_write`.
679+
680+
To avoid a memory leak, the IO handle must eventually be consumed by
681+
`hyper_io_free` or `hyper_clientconn_handshake`.
627682
*/
628683
struct hyper_io *hyper_io_new(void);
629684

630685
/*
631-
Free an unused `hyper_io *`.
686+
Free an IO handle.
632687
633-
This is typically only useful if you aren't going to pass ownership
634-
of the IO handle to hyper, such as with `hyper_clientconn_handshake()`.
688+
This should only be used if the request isn't consumed by
689+
`hyper_clientconn_handshake`.
635690
*/
636691
void hyper_io_free(struct hyper_io *io);
637692

@@ -681,18 +736,23 @@ void hyper_io_set_write(struct hyper_io *io, hyper_io_write_callback func);
681736

682737
/*
683738
Creates a new task executor.
739+
740+
To avoid a memory leak, the executor must eventually be consumed by
741+
`hyper_executor_free`.
684742
*/
685743
const struct hyper_executor *hyper_executor_new(void);
686744

687745
/*
688746
Frees an executor and any incomplete tasks still part of it.
747+
748+
This should be used for any executor once it is no longer needed.
689749
*/
690750
void hyper_executor_free(const struct hyper_executor *exec);
691751

692752
/*
693753
Push a task onto the executor.
694754
695-
The executor takes ownership of the task, it should not be accessed
755+
The executor takes ownership of the task, which should not be accessed
696756
again unless returned back to the user with `hyper_executor_poll`.
697757
*/
698758
enum hyper_code hyper_executor_push(const struct hyper_executor *exec, struct hyper_task *task);
@@ -703,12 +763,20 @@ enum hyper_code hyper_executor_push(const struct hyper_executor *exec, struct hy
703763
704764
If ready, returns a task from the executor that has completed.
705765
766+
To avoid a memory leak, the task must eventually be consumed by
767+
`hyper_task_free`, or taken ownership of by `hyper_executor_push`
768+
without subsequently being given back by `hyper_executor_poll`.
769+
706770
If there are no ready tasks, this returns `NULL`.
707771
*/
708772
struct hyper_task *hyper_executor_poll(const struct hyper_executor *exec);
709773

710774
/*
711775
Free a task.
776+
777+
This should only be used if the task isn't consumed by
778+
`hyper_clientconn_handshake` or taken ownership of by
779+
`hyper_executor_push`.
712780
*/
713781
void hyper_task_free(struct hyper_task *task);
714782

@@ -719,6 +787,11 @@ void hyper_task_free(struct hyper_task *task);
719787
this task.
720788
721789
Use `hyper_task_type` to determine the type of the `void *` return value.
790+
791+
To avoid a memory leak, a non-empty return value must eventually be
792+
consumed by a function appropriate for its type, one of
793+
`hyper_error_free`, `hyper_clientconn_free`, `hyper_response_free`, or
794+
`hyper_buf_free`.
722795
*/
723796
void *hyper_task_value(struct hyper_task *task);
724797

@@ -742,11 +815,17 @@ void *hyper_task_userdata(struct hyper_task *task);
742815

743816
/*
744817
Copies a waker out of the task context.
818+
819+
To avoid a memory leak, the waker must eventually be consumed by
820+
`hyper_waker_free` or `hyper_waker_wake`.
745821
*/
746822
struct hyper_waker *hyper_context_waker(struct hyper_context *cx);
747823

748824
/*
749-
Free a waker that hasn't been woken.
825+
Free a waker.
826+
827+
This should only be used if the request isn't consumed by
828+
`hyper_waker_wake`.
750829
*/
751830
void hyper_waker_free(struct hyper_waker *waker);
752831

src/ffi/body.rs

+21-2
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
}

src/ffi/client.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,14 @@ ffi_fn! {
4444
/// and options.
4545
///
4646
/// Both the `io` and the `options` are consumed in this function call.
47+
/// They should not be used or freed afterwards.
4748
///
48-
/// The returned `hyper_task *` must be polled with an executor until the
49-
/// handshake completes, at which point the value can be taken.
49+
/// The returned task must be polled with an executor until the handshake
50+
/// completes, at which point the value can be taken.
51+
///
52+
/// To avoid a memory leak, the task must eventually be consumed by
53+
/// `hyper_task_free`, or taken ownership of by `hyper_executor_push`
54+
/// without subsequently being given back by `hyper_executor_poll`.
5055
fn hyper_clientconn_handshake(io: *mut hyper_io, options: *mut hyper_clientconn_options) -> *mut hyper_task {
5156
let options = non_null! { Box::from_raw(options) ?= ptr::null_mut() };
5257
let io = non_null! { Box::from_raw(io) ?= ptr::null_mut() };
@@ -86,8 +91,15 @@ ffi_fn! {
8691
ffi_fn! {
8792
/// Send a request on the client connection.
8893
///
94+
/// This consumes the request. You should not use or free the request
95+
/// afterwards.
96+
///
8997
/// Returns a task that needs to be polled until it is ready. When ready, the
9098
/// task yields a `hyper_response *`.
99+
///
100+
/// To avoid a memory leak, the task must eventually be consumed by
101+
/// `hyper_task_free`, or taken ownership of by `hyper_executor_push`
102+
/// without subsequently being given back by `hyper_executor_poll`.
91103
fn hyper_clientconn_send(conn: *mut hyper_clientconn, req: *mut hyper_request) -> *mut hyper_task {
92104
let mut req = non_null! { Box::from_raw(req) ?= ptr::null_mut() };
93105

@@ -109,6 +121,8 @@ ffi_fn! {
109121

110122
ffi_fn! {
111123
/// Free a `hyper_clientconn *`.
124+
///
125+
/// This should be used for any connection once it is no longer needed.
112126
fn hyper_clientconn_free(conn: *mut hyper_clientconn) {
113127
drop(non_null! { Box::from_raw(conn) ?= () });
114128
}
@@ -124,6 +138,9 @@ unsafe impl AsTaskType for hyper_clientconn {
124138

125139
ffi_fn! {
126140
/// Creates a new set of HTTP clientconn options to be used in a handshake.
141+
///
142+
/// To avoid a memory leak, the options must eventually be consumed by
143+
/// `hyper_clientconn_options_free` or `hyper_clientconn_handshake`.
127144
fn hyper_clientconn_options_new() -> *mut hyper_clientconn_options {
128145
Box::into_raw(Box::new(hyper_clientconn_options {
129146
http1_allow_obsolete_multiline_headers_in_responses: false,
@@ -156,7 +173,10 @@ ffi_fn! {
156173
}
157174

158175
ffi_fn! {
159-
/// Free a `hyper_clientconn_options *`.
176+
/// Free a set of HTTP clientconn options.
177+
///
178+
/// This should only be used if the options aren't consumed by
179+
/// `hyper_clientconn_handshake`.
160180
fn hyper_clientconn_options_free(opts: *mut hyper_clientconn_options) {
161181
drop(non_null! { Box::from_raw(opts) ?= () });
162182
}

0 commit comments

Comments
 (0)