llist: remove direct struct accesses, use only functions

- Turned them all into functions to also do asserts etc.

- The llist related structs got all their fields renamed in order to make
  sure no existing code remains using direct access.

- Each list node struct now points back to the list it "lives in", so
  Curl_node_remove() no longer needs the list pointer.

- Rename the node struct and some of the access functions.

- Added lots of ASSERTs to verify API being used correctly

- Fix some cases of API misuse

Add docs/LLIST.md documenting the internal linked list API.

Closes #14485
This commit is contained in:
Daniel Stenberg 2024-08-10 23:27:25 +02:00
parent 6f00a05e89
commit ba235ab269
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
27 changed files with 725 additions and 428 deletions

View file

@ -42,7 +42,7 @@
static void copy_header_external(struct Curl_header_store *hs,
size_t index,
size_t amount,
struct Curl_llist_element *e,
struct Curl_llist_node *e,
struct curl_header *hout)
{
struct curl_header *h = hout;
@ -66,8 +66,8 @@ CURLHcode curl_easy_header(CURL *easy,
int request,
struct curl_header **hout)
{
struct Curl_llist_element *e;
struct Curl_llist_element *e_pick = NULL;
struct Curl_llist_node *e;
struct Curl_llist_node *e_pick = NULL;
struct Curl_easy *data = easy;
size_t match = 0;
size_t amount = 0;
@ -85,8 +85,8 @@ CURLHcode curl_easy_header(CURL *easy,
request = data->state.requests;
/* we need a first round to count amount of this header */
for(e = data->state.httphdrs.head; e; e = e->next) {
hs = e->ptr;
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
hs = Curl_node_elem(e);
if(strcasecompare(hs->name, name) &&
(hs->type & type) &&
(hs->request == request)) {
@ -104,8 +104,8 @@ CURLHcode curl_easy_header(CURL *easy,
/* if the last or only occurrence is what's asked for, then we know it */
hs = pick;
else {
for(e = data->state.httphdrs.head; e; e = e->next) {
hs = e->ptr;
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
hs = Curl_node_elem(e);
if(strcasecompare(hs->name, name) &&
(hs->type & type) &&
(hs->request == request) &&
@ -131,8 +131,8 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
struct curl_header *prev)
{
struct Curl_easy *data = easy;
struct Curl_llist_element *pick;
struct Curl_llist_element *e;
struct Curl_llist_node *pick;
struct Curl_llist_node *e;
struct Curl_header_store *hs;
size_t amount = 0;
size_t index = 0;
@ -147,18 +147,18 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
if(!pick)
/* something is wrong */
return NULL;
pick = pick->next;
pick = Curl_node_next(pick);
}
else
pick = data->state.httphdrs.head;
pick = Curl_llist_head(&data->state.httphdrs);
if(pick) {
/* make sure it is the next header of the desired type */
do {
hs = pick->ptr;
hs = Curl_node_elem(pick);
if((hs->type & type) && (hs->request == request))
break;
pick = pick->next;
pick = Curl_node_next(pick);
} while(pick);
}
@ -166,12 +166,12 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
/* no more headers available */
return NULL;
hs = pick->ptr;
hs = Curl_node_elem(pick);
/* count number of occurrences of this name within the mask and figure out
the index for the currently selected entry */
for(e = data->state.httphdrs.head; e; e = e->next) {
struct Curl_header_store *check = e->ptr;
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
struct Curl_header_store *check = Curl_node_elem(e);
if(strcasecompare(hs->name, check->name) &&
(check->request == request) &&
(check->type & type))
@ -247,7 +247,7 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value,
/* since this header block might move in the realloc below, it needs to
first be unlinked from the list and then re-added again after the
realloc */
Curl_llist_remove(&data->state.httphdrs, &hs->node, NULL);
Curl_node_remove(&hs->node);
/* new size = struct + new value length + old name+value length */
newhs = Curl_saferealloc(hs, sizeof(*hs) + vlen + oalloc + 1);
@ -405,12 +405,12 @@ CURLcode Curl_headers_init(struct Curl_easy *data)
*/
CURLcode Curl_headers_cleanup(struct Curl_easy *data)
{
struct Curl_llist_element *e;
struct Curl_llist_element *n;
struct Curl_llist_node *e;
struct Curl_llist_node *n;
for(e = data->state.httphdrs.head; e; e = n) {
struct Curl_header_store *hs = e->ptr;
n = e->next;
for(e = Curl_llist_head(&data->state.httphdrs); e; e = n) {
struct Curl_header_store *hs = Curl_node_elem(e);
n = Curl_node_next(e);
free(hs);
}
headers_reset(data);