This commits adds version_is_valid_versionspec and uses it in
analyze-compare-version.c.
version_is_valid_versionspec differs from version_is_valid in that it acepts
empty strings and since valid characters in a version spec version are all
ASCII letters and digits as well as "-.~^", but ",_+" allowed by
version_is_valid are not.
Also give a more specific warning message on invalid characters.
Cutting off in the middle may leave the terminal in a bad state, breaking
further output. But we don't know what a given ANSI sequence does, e.g.
ANSI_NORMAL should not be skipped. But it is also nice to keep various
sequences intact, so that if we had part of the string in blue, and we cut out
the beginning of the blue part, we still want to keep the remainder in color.
So let's just pass them through, stripping out the characters that take up
actual space.
Also, use memcpy_safe as we may end up copying zero bytes when ellipsizing at
the start/end of a string.
Fixes: #24502
This also fixes an ugliness where we would ellipsize string with ANSI
sequences too much, leading to output that was narrower on screen than the
requested length:
Starting AAAAAAAAAAAAAAAAAAAAA.service
Starting BBBBBBBBBBBBBBBBBBBBB.service
Starting LONG…ER.service
Co-authored-by: Jan Janssen <medhefgo@web.de>
While we are at it, replace the sloppy use of filename_is_valid() by the
less sloppy filename_part_is_valid() (as added by the preceeding
commit), since we don#t want to be too restrictive here. (After all,
version strings invalid as standalone filenames might be valid as part
of filenames, and hence we should allow them).
When closing the FILE handle attached to a memstream, it may attempt to
do a realloc() that may fail during OOM situations, in which case we are
left with the buffer pointer pointing to NULL and buffer size > 0. For
example:
```
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
void *realloc(void *ptr, size_t size) {
return NULL;
}
int main(int argc, char *argv[])
{
FILE *f;
char *buf;
size_t sz = 0;
f = open_memstream(&buf, &sz);
if (!f)
return -ENOMEM;
fputs("Hello", f);
fflush(f);
printf("buf: 0x%lx, sz: %lu, errno: %d\n",
(unsigned long) buf, sz, errno);
fclose(f);
printf("buf: 0x%lx, sz: %lu, errno: %d\n",
(unsigned long) buf, sz, errno);
return 0;
}
```
```
$ gcc -o main main.c
$ ./main
buf: 0x74d4a0, sz: 5, errno: 0
buf: 0x0, sz: 5, errno: 0
```
This might do unexpected things if the underlying code expects a valid
pointer to the memstream buffer after closing the handle.
Found by Nallocfuzz.
This is the function version of STARTSWITH_SET(). We also move
STARTSWITH_SET() to string-util.h as it fits more there than in
strv.h and reimplement it using startswith_strv().
These combine strndup() + strspn()/strcspn() into one.
There are a bunch of strndupa() calls that could use similar treatment
(or should be converted to strdup[c]spn(), but this commit doesn't
bother with that.
We recently started making more use of malloc_usable_size() and rely on
it (see the string_erase() story). Given that we don't really support
sytems where malloc_usable_size() cannot be trusted beyond statistics
anyway, let's go fully in and rework GREEDY_REALLOC() on top of it:
instead of passing around and maintaining the currenly allocated size
everywhere, let's just derive it automatically from
malloc_usable_size().
I am mostly after this for the simplicity this brings. It also brings
minor efficiency improvements I guess, but things become so much nicer
to look at if we can avoid these allocation size variables everywhere.
Note that the malloc_usable_size() man page says relying on it wasn't
"good programming practice", but I think it does this for reasons that
don't apply here: the greedy realloc logic specifically doesn't rely on
the returned extra size, beyond the fact that it is equal or larger than
what was requested.
(This commit was supposed to be a quick patch btw, but apparently we use
the greedy realloc stuff quite a bit across the codebase, so this ends
up touching *a*lot* of code.)
It's a wrapper around malloc_usable_size() that is supposed to be
compatible with _FORTIFY_SOURCES=1, by taking the
__builtin_object_size() data into account, the same way as the
_FORTIFY_SOURCES=1 logic does.
Fixes: #19203
It's not going to be efficient if called in inner loops, but it's oh so
handy, and we have some code that does this:
asprintf(&p, "%s…", b, …);
free(b);
b = TAKE_PTR(p);
which can now be replaced by the quicker and easier to read:
strextendf(&p, "…", …);
sd-boot has a copy of a subset of codes from libbasic. This makes
sd-boot share the code with libbasic, and dedup the code.
Note, startswith_no_case() is dropped from sd-boot, as
- it is not used,
- the previous implementation is not correct,
- gnu-efi does not have StrniCmp() or so.
This uses GREEDY_ALLOC_ROUND_UP() to grow the allocation size
exponentially. This should speed allocation loops up a bit, given
that we often call strextend() repeatedly in a loop on the same
buffer.
The current overflow checking is broken in the corner case of the strings'
combined length being exactly SIZE_MAX: After the loop, l would be SIZE_MAX,
but we're not testing whether the l+1 expression overflows.
Fix it by simply pre-accounting for the final '\0': initialize l to 1 instead
of 0.
The loops over (x, then all varargs, until a NULL is found) can be written much
simpler with an ordinary for loop. Just initialize the loop variable to x, test
that, and in the increment part, fetch the next va_arg(). That removes a level
of indentation, and avoids doing a separate strlen()/stpcpy() call for x.
While touching this code anyway, change (size_t)-1 to the more readable
SIZE_MAX.
I had to move STRV_MAKE to macro.h. There is a circular dependency between
extract-word.h, strv.h, and string-util.h that makes it hard to define the
inline function otherwise.
split() and FOREACH_WORD really should die, and everything be moved to
extract_first_word() and friends, but let's at least make sure that for
the remaining code using it we can't deadlock by not progressing in the
word iteration.
Fixes: #15305