curl-curl/lib/curlx/dynbuf.c
Viktor Szakats 0260e8465a
GHA/checksrc: expand spellcheck, fix issues found
- codespell: break logic out into its own runnable script. Allowing
  to run it on local machines.
- codespell: install via `pip`, bump to latest version.
- codespell: show version number in CI log.
- codespell: drop no longer needed word exception: `msdos`.
- codespell: include all curl source tree, except `packages` and
  `winbuild`. Drop an obsolete file exclusion.
- add new spellchecker job using the `typos` tool. It includes
  the codespell dictionary and a couple more. Use linuxbrew to install
  it. This takes 10 seconds, while installing via `cargo` from source
  would take over a minute.
- codespell: introduce an inline ignore filter compatible with `cspell`
  Make `typos` recognize it, too. Move single exceptions inline.

Fix new typos found. Also rename variables and words to keep
spellchecking exceptions at minumum. This involves touching some tests.
Also switch base64 strings to `%b64[]` to avoid false positives.

Ref: https://github.com/crate-ci/typos/blob/master/docs/reference.md
Ref: https://github.com/codespell-project/codespell?tab=readme-ov-file#inline-ignore
Ref: https://github.com/codespell-project/codespell/issues/1212#issuecomment-1721152455
Ref: https://cspell.org/docs/Configuration/document-settings

Closes #17905
2025-07-21 16:09:01 +02:00

299 lines
6.8 KiB
C

/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 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.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "../curl_setup.h"
#include "dynbuf.h"
#include "../curl_printf.h"
#ifdef BUILDING_LIBCURL
#include "../curl_memory.h"
#endif
#include "../memdebug.h"
#define MIN_FIRST_ALLOC 32
#ifdef DEBUGBUILD
#define DYNINIT 0xbee51da /* random pattern */
#endif
/*
* Init a dynbuf struct.
*/
void curlx_dyn_init(struct dynbuf *s, size_t toobig)
{
DEBUGASSERT(s);
DEBUGASSERT(toobig);
DEBUGASSERT(toobig <= MAX_DYNBUF_SIZE); /* catch crazy mistakes */
s->bufr = NULL;
s->leng = 0;
s->allc = 0;
s->toobig = toobig;
#ifdef DEBUGBUILD
s->init = DYNINIT;
#endif
}
/*
* free the buffer and re-init the necessary fields. It does not touch the
* 'init' field and thus this buffer can be reused to add data to again.
*/
void curlx_dyn_free(struct dynbuf *s)
{
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
Curl_safefree(s->bufr);
s->leng = s->allc = 0;
}
/*
* Store/append an chunk of memory to the dynbuf.
*/
static CURLcode dyn_nappend(struct dynbuf *s,
const unsigned char *mem, size_t len)
{
size_t idx = s->leng;
size_t a = s->allc;
size_t fit = len + idx + 1; /* new string + old string + zero byte */
/* try to detect if there is rubbish in the struct */
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(s->toobig);
DEBUGASSERT(idx < s->toobig);
DEBUGASSERT(!s->leng || s->bufr);
DEBUGASSERT(a <= s->toobig);
DEBUGASSERT(!len || mem);
if(fit > s->toobig) {
curlx_dyn_free(s);
return CURLE_TOO_LARGE;
}
else if(!a) {
DEBUGASSERT(!idx);
/* first invoke */
if(MIN_FIRST_ALLOC > s->toobig)
a = s->toobig;
else if(fit < MIN_FIRST_ALLOC)
a = MIN_FIRST_ALLOC;
else
a = fit;
}
else {
while(a < fit)
a *= 2;
if(a > s->toobig)
/* no point in allocating a larger buffer than this is allowed to use */
a = s->toobig;
}
if(a != s->allc) {
/* this logic is not using Curl_saferealloc() to make the tool not have to
include that as well when it uses this code */
void *p = realloc(s->bufr, a);
if(!p) {
curlx_dyn_free(s);
return CURLE_OUT_OF_MEMORY;
}
s->bufr = p;
s->allc = a;
}
if(len)
memcpy(&s->bufr[idx], mem, len);
s->leng = idx + len;
s->bufr[s->leng] = 0;
return CURLE_OK;
}
/*
* Clears the string, keeps the allocation. This can also be called on a
* buffer that already was freed.
*/
void curlx_dyn_reset(struct dynbuf *s)
{
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
if(s->leng)
s->bufr[0] = 0;
s->leng = 0;
}
/*
* Specify the size of the tail to keep (number of bytes from the end of the
* buffer). The rest will be dropped.
*/
CURLcode curlx_dyn_tail(struct dynbuf *s, size_t trail)
{
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
if(trail > s->leng)
return CURLE_BAD_FUNCTION_ARGUMENT;
else if(trail == s->leng)
return CURLE_OK;
else if(!trail) {
curlx_dyn_reset(s);
}
else {
memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail);
s->leng = trail;
s->bufr[s->leng] = 0;
}
return CURLE_OK;
}
/*
* Appends a buffer with length.
*/
CURLcode curlx_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
{
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
return dyn_nappend(s, mem, len);
}
/*
* Append a null-terminated string at the end.
*/
CURLcode curlx_dyn_add(struct dynbuf *s, const char *str)
{
size_t n;
DEBUGASSERT(str);
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
n = strlen(str);
return dyn_nappend(s, (const unsigned char *)str, n);
}
/*
* Append a string vprintf()-style
*/
CURLcode curlx_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
{
#ifdef BUILDING_LIBCURL
int rc;
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
DEBUGASSERT(fmt);
rc = curlx_dyn_vprintf(s, fmt, ap);
if(!rc)
return CURLE_OK;
else if(rc == MERR_TOO_LARGE)
return CURLE_TOO_LARGE;
return CURLE_OUT_OF_MEMORY;
#else
char *str;
str = curl_mvaprintf(fmt, ap); /* this allocs a new string to append */
if(str) {
CURLcode result = dyn_nappend(s, (const unsigned char *)str, strlen(str));
free(str);
return result;
}
/* If we failed, we cleanup the whole buffer and return error */
curlx_dyn_free(s);
return CURLE_OUT_OF_MEMORY;
#endif
}
/*
* Append a string printf()-style
*/
CURLcode curlx_dyn_addf(struct dynbuf *s, const char *fmt, ...)
{
CURLcode result;
va_list ap;
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
va_start(ap, fmt);
result = curlx_dyn_vaddf(s, fmt, ap);
va_end(ap);
return result;
}
/*
* Returns a pointer to the buffer.
*/
char *curlx_dyn_ptr(const struct dynbuf *s)
{
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
return s->bufr;
}
char *curlx_dyn_take(struct dynbuf *s, size_t *plen)
{
char *ptr = s->bufr;
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
*plen = s->leng;
s->bufr = NULL;
s->leng = 0;
s->allc = 0;
return ptr;
}
/*
* Returns an unsigned pointer to the buffer.
*/
unsigned char *curlx_dyn_uptr(const struct dynbuf *s)
{
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
return (unsigned char *)s->bufr;
}
/*
* Returns the length of the buffer.
*/
size_t curlx_dyn_len(const struct dynbuf *s)
{
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
return s->leng;
}
/*
* Set a new (smaller) length.
*/
CURLcode curlx_dyn_setlen(struct dynbuf *s, size_t set)
{
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
if(set > s->leng)
return CURLE_BAD_FUNCTION_ARGUMENT;
s->leng = set;
s->bufr[s->leng] = 0;
return CURLE_OK;
}