mirror of
https://github.com/curl/curl.git
synced 2026-07-26 06:57:16 +03:00
bufref: buffer reference support
A struct bufref holds a buffer pointer, a data size and a destructor. When freed or its contents are changed, the previous buffer is implicitly released by the associated destructor. The data size, although not used internally, allows binary data support. A unit test checks its handling methods: test 1661 Closes #6654
This commit is contained in:
parent
a2a8f9d730
commit
34cf40321c
9 changed files with 398 additions and 3 deletions
81
docs/BUFREF.md
Normal file
81
docs/BUFREF.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# bufref
|
||||
|
||||
This is an internal module for handling buffer references. A referenced
|
||||
buffer is associated with its destructor function that is implicitly called
|
||||
when the reference is invalidated. Once referenced, a buffer cannot be
|
||||
reallocated.
|
||||
|
||||
A data length is stored within the reference for binary data handling
|
||||
purpose; it is not used by the bufref API.
|
||||
|
||||
The `struct bufref` is used to hold data referencing a buffer. The members of
|
||||
that structure **MUST NOT** be accessed or modified without using the dedicated
|
||||
bufref API.
|
||||
|
||||
## init
|
||||
|
||||
```c
|
||||
void Curl_bufref_init(struct bufref *br);
|
||||
```
|
||||
|
||||
Initialises a `bufref` structure. This function **MUST** be called before any
|
||||
other operation is performed on the structure.
|
||||
|
||||
Upon completion, the referenced buffer is `NULL` and length is zero.
|
||||
|
||||
This function may also be called to bypass referenced buffer destruction while
|
||||
invalidating the current reference.
|
||||
|
||||
## free
|
||||
|
||||
```c
|
||||
void Curl_bufref_free(struct bufref *br);
|
||||
```
|
||||
|
||||
Destroys the previously referenced buffer using its destructor and
|
||||
reinitialises the structure for a possible subsequent reuse.
|
||||
|
||||
## set
|
||||
|
||||
```c
|
||||
void Curl_bufref_set(struct bufref *br, const void *buffer, size_t length,
|
||||
void (*destructor)(void *));
|
||||
```
|
||||
|
||||
Releases the previouly referenced buffer, then assigns the new `buffer` to
|
||||
the structure, associated with its `destructor` function. The later can be
|
||||
specified as `NULL`: this will be the case when the referenced buffer is
|
||||
static.
|
||||
|
||||
if `buffer` is NULL, `length`must be zero.
|
||||
|
||||
## memdup
|
||||
|
||||
```c
|
||||
CURLcode Curl_bufref_memdup(struct bufref *br, const void *data, size_t length);
|
||||
```
|
||||
|
||||
Releases the previouly referenced buffer, then duplicates the `length`-byte
|
||||
`data` into a buffer allocated via `malloc()` and references the later
|
||||
associated with destructor `curl_free()`.
|
||||
|
||||
An additional trailing byte is allocated and set to zero as a possible
|
||||
string zero-terminator; it is not counted in the stored length.
|
||||
|
||||
Returns `CURLE_OK` if successful, else `CURLE_OUT_OF_MEMORY`.
|
||||
|
||||
## ptr
|
||||
|
||||
```c
|
||||
const unsigned char *Curl_bufref_ptr(const struct bufref *br);
|
||||
```
|
||||
|
||||
Returns a `const unsigned char *` to the referenced bufffer.
|
||||
|
||||
## len
|
||||
|
||||
```c
|
||||
size_t Curl_bufref_len(const struct bufref *br);
|
||||
```
|
||||
|
||||
Returns the stored length of the referenced buffer.
|
||||
|
|
@ -44,6 +44,7 @@ EXTRA_DIST = \
|
|||
$(noinst_man_MANS) \
|
||||
ALTSVC.md \
|
||||
BINDINGS.md \
|
||||
BUFREF.md \
|
||||
BUG-BOUNTY.md \
|
||||
BUGS.md \
|
||||
CHECKSRC.md \
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ LIB_CFILES = \
|
|||
asyn-ares.c \
|
||||
asyn-thread.c \
|
||||
base64.c \
|
||||
bufref.c \
|
||||
c-hyper.c \
|
||||
conncache.c \
|
||||
connect.c \
|
||||
|
|
@ -217,6 +218,7 @@ LIB_HFILES = \
|
|||
amigaos.h \
|
||||
arpa_telnet.h \
|
||||
asyn.h \
|
||||
bufref.h \
|
||||
c-hyper.h \
|
||||
conncache.h \
|
||||
connect.h \
|
||||
|
|
|
|||
127
lib/bufref.c
Normal file
127
lib/bufref.c
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
#include "urldata.h"
|
||||
#include "bufref.h"
|
||||
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#define SIGNATURE 0x5c48e9b2 /* Random pattern. */
|
||||
|
||||
/*
|
||||
* Init a bufref struct.
|
||||
*/
|
||||
void Curl_bufref_init(struct bufref *br)
|
||||
{
|
||||
DEBUGASSERT(br);
|
||||
br->dtor = NULL;
|
||||
br->ptr = NULL;
|
||||
br->len = 0;
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
br->signature = SIGNATURE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the buffer and re-init the necessary fields. It doesn't touch the
|
||||
* 'signature' field and thus this buffer reference can be reused.
|
||||
*/
|
||||
|
||||
void Curl_bufref_free(struct bufref *br)
|
||||
{
|
||||
DEBUGASSERT(br);
|
||||
DEBUGASSERT(br->signature == SIGNATURE);
|
||||
DEBUGASSERT(br->ptr || !br->len);
|
||||
|
||||
if(br->ptr && br->dtor)
|
||||
br->dtor((void *) br->ptr);
|
||||
|
||||
br->dtor = NULL;
|
||||
br->ptr = NULL;
|
||||
br->len = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the buffer reference to new values. The previously referenced buffer
|
||||
* is released before assignment.
|
||||
*/
|
||||
void Curl_bufref_set(struct bufref *br, const void *ptr, size_t len,
|
||||
void (*dtor)(void *))
|
||||
{
|
||||
DEBUGASSERT(ptr || !len);
|
||||
DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH);
|
||||
|
||||
Curl_bufref_free(br);
|
||||
br->ptr = (const unsigned char *) ptr;
|
||||
br->len = len;
|
||||
br->dtor = dtor;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a pointer to the referenced buffer.
|
||||
*/
|
||||
const unsigned char *Curl_bufref_ptr(const struct bufref *br)
|
||||
{
|
||||
DEBUGASSERT(br);
|
||||
DEBUGASSERT(br->signature == SIGNATURE);
|
||||
DEBUGASSERT(br->ptr || !br->len);
|
||||
|
||||
return br->ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the length of the referenced buffer data.
|
||||
*/
|
||||
size_t Curl_bufref_len(const struct bufref *br)
|
||||
{
|
||||
DEBUGASSERT(br);
|
||||
DEBUGASSERT(br->signature == SIGNATURE);
|
||||
DEBUGASSERT(br->ptr || !br->len);
|
||||
|
||||
return br->len;
|
||||
}
|
||||
|
||||
CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len)
|
||||
{
|
||||
unsigned char *cpy = NULL;
|
||||
|
||||
DEBUGASSERT(br);
|
||||
DEBUGASSERT(br->signature == SIGNATURE);
|
||||
DEBUGASSERT(br->ptr || !br->len);
|
||||
DEBUGASSERT(ptr || !len);
|
||||
DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH);
|
||||
|
||||
if(ptr) {
|
||||
cpy = malloc(len + 1);
|
||||
if(!cpy)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
if(len)
|
||||
memcpy(cpy, ptr, len);
|
||||
cpy[len] = '\0';
|
||||
}
|
||||
|
||||
Curl_bufref_set(br, cpy, len, curl_free);
|
||||
return CURLE_OK;
|
||||
}
|
||||
46
lib/bufref.h
Normal file
46
lib/bufref.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef HEADER_CURL_BUFREF_H
|
||||
#define HEADER_CURL_BUFREF_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Generic buffer reference.
|
||||
*/
|
||||
struct bufref {
|
||||
void (*dtor)(void *); /* Associated destructor. */
|
||||
const unsigned char *ptr; /* Referenced data buffer. */
|
||||
size_t len; /* The data size in bytes. */
|
||||
#ifdef DEBUGBUILD
|
||||
int signature; /* Detect API use mistakes. */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
void Curl_bufref_init(struct bufref *br);
|
||||
void Curl_bufref_set(struct bufref *br, const void *ptr, size_t len,
|
||||
void (*dtor)(void *));
|
||||
const unsigned char *Curl_bufref_ptr(const struct bufref *br);
|
||||
size_t Curl_bufref_len(const struct bufref *br);
|
||||
CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len);
|
||||
void Curl_bufref_free(struct bufref *br);
|
||||
|
||||
#endif
|
||||
|
|
@ -203,7 +203,7 @@ test1620 test1621 \
|
|||
test1630 test1631 test1632 test1633 test1634 \
|
||||
\
|
||||
test1650 test1651 test1652 test1653 test1654 test1655 \
|
||||
test1660 \
|
||||
test1660 test1661 \
|
||||
\
|
||||
test1700 test1701 test1702 test1703 \
|
||||
\
|
||||
|
|
|
|||
22
tests/data/test1661
Normal file
22
tests/data/test1661
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
unittest
|
||||
bufref
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
none
|
||||
</server>
|
||||
<features>
|
||||
unittest
|
||||
</features>
|
||||
<name>
|
||||
bufref unit tests
|
||||
</name>
|
||||
</client>
|
||||
</testcase>
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
# Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file COPYING, which
|
||||
# you should have received as part of this distribution. The terms
|
||||
|
|
@ -35,7 +35,7 @@ UNITPROGS = unit1300 unit1301 unit1302 unit1303 unit1304 unit1305 unit1307 \
|
|||
unit1608 unit1609 unit1610 unit1611 unit1612 \
|
||||
unit1620 unit1621 \
|
||||
unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 \
|
||||
unit1660
|
||||
unit1660 unit1661
|
||||
|
||||
unit1300_SOURCES = unit1300.c $(UNITFILES)
|
||||
unit1300_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
|
@ -157,3 +157,6 @@ unit1655_CPPFLAGS = $(AM_CPPFLAGS)
|
|||
|
||||
unit1660_SOURCES = unit1660.c $(UNITFILES)
|
||||
unit1660_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
unit1661_SOURCES = unit1661.c $(UNITFILES)
|
||||
unit1661_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
|
|
|||
113
tests/unit/unit1661.c
Normal file
113
tests/unit/unit1661.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curlcheck.h"
|
||||
|
||||
#include "bufref.h"
|
||||
|
||||
static struct bufref bufref;
|
||||
|
||||
static int freecount = 0;
|
||||
|
||||
static void test_free(void *p)
|
||||
{
|
||||
fail_unless(p, "pointer to free may not be NULL");
|
||||
freecount++;
|
||||
free(p);
|
||||
}
|
||||
|
||||
static CURLcode unit_setup(void)
|
||||
{
|
||||
Curl_bufref_init(&bufref);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void unit_stop(void)
|
||||
{
|
||||
}
|
||||
|
||||
UNITTEST_START
|
||||
{
|
||||
char *buffer = NULL;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
/**
|
||||
* testing Curl_bufref_init.
|
||||
* @assumptions:
|
||||
* 1: data size will be 0
|
||||
* 2: reference will be NULL
|
||||
* 3: destructor will be NULL
|
||||
*/
|
||||
|
||||
fail_unless(!bufref.ptr, "Initial reference must be NULL");
|
||||
fail_unless(!bufref.len, "Initial length must be NULL");
|
||||
fail_unless(!bufref.dtor, "Destructor must be NULL");
|
||||
|
||||
/**
|
||||
* testing Curl_bufref_set
|
||||
*/
|
||||
|
||||
buffer = malloc(13);
|
||||
abort_unless(buffer, "Out of memory");
|
||||
Curl_bufref_set(&bufref, buffer, 13, test_free);
|
||||
|
||||
fail_unless((char *) bufref.ptr == buffer, "Referenced data badly set");
|
||||
fail_unless(bufref.len == 13, "Data size badly set");
|
||||
fail_unless(bufref.dtor == test_free, "Destructor badly set");
|
||||
|
||||
/**
|
||||
* testing Curl_bufref_ptr
|
||||
*/
|
||||
|
||||
fail_unless((char *) Curl_bufref_ptr(&bufref) == buffer,
|
||||
"Wrong pointer value returned");
|
||||
|
||||
/**
|
||||
* testing Curl_bufref_len
|
||||
*/
|
||||
|
||||
fail_unless(Curl_bufref_len(&bufref) == 13, "Wrong data size returned");
|
||||
|
||||
/**
|
||||
* testing Curl_bufref_memdup
|
||||
*/
|
||||
|
||||
result = Curl_bufref_memdup(&bufref, "1661", 3);
|
||||
abort_unless(result == CURLE_OK, curl_easy_strerror(result));
|
||||
fail_unless(freecount == 1, "Destructor not called");
|
||||
fail_unless((char *) bufref.ptr != buffer, "Returned pointer not set");
|
||||
buffer = (char *) Curl_bufref_ptr(&bufref);
|
||||
fail_unless(buffer, "Allocated pointer is NULL");
|
||||
fail_unless(bufref.len == 3, "Wrong data size stored");
|
||||
fail_unless(!buffer[3], "Duplicated data should have been truncated");
|
||||
fail_unless(!strcmp(buffer, "166"), "Bad duplicated data");
|
||||
|
||||
/**
|
||||
* testing Curl_bufref_free
|
||||
*/
|
||||
|
||||
Curl_bufref_free(&bufref);
|
||||
fail_unless(freecount == 1, "Wrong destructor called");
|
||||
fail_unless(!bufref.ptr, "Initial reference must be NULL");
|
||||
fail_unless(!bufref.len, "Initial length must be NULL");
|
||||
fail_unless(!bufref.dtor, "Destructor must be NULL");
|
||||
}
|
||||
UNITTEST_STOP
|
||||
Loading…
Add table
Add a link
Reference in a new issue