This affects the new `g_string_replace()` code which landed on `main` a
few days ago. It does not affect the old implementation of
`g_string_replace()`.
The code for the `f_len == 0` (needle is an empty string) case was
modifying `string` in the loop, without updating any of the string
pointers into it. If the replacement was long enough (or inserted enough
times), this would trigger a realloc of `string->str` and cause all the
string pointers to be dangling.
Fix this by pulling the `f_len == 0` code out into a separate branch and
loop, rather than trying to integrate it into the main loop. This
simplifies the main loop significantly, and makes both easier to verify.
An alternative approach, which doesn’t involve splitting the
`f_len == 0` case out, might have been to track the positions using
indexes rather than string pointers. I think the approach in this commit
is better, though, as it removes the possibility of `f_len == 0`
entirely from the loop, which makes it much easier to verify termination
of the loop.
Add more tests to validate this, including the test from oss-fuzz which
triggered the realloc and found the heap buffer overflow.
The new tests have also been run against the _old_ implementation of
`g_string_replace()` to ensure its behaviour (particularly around `f_len
== 0 && limit > 0`) has not changed.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
oss-fuzz#371043019
Current implementation replaces find in string with replace
one-at-a-time and replacement is done in O(n^2) time. The new
implementation is O(n). Memory allocation is done once instead of
incrementally.
In the old implementation, every replacement will move the whole
rest of the string from the current position to make space for
the replace string and then insert the replace string.
In the new implementation, when the replace string is shorter or equal
to the find string, it will move the characters in-place and requires no
additional memory. When the replace string is longer, find the required
size needed for the new string and preallocate a new string to copy the
original string to with its replacements. When the replace string is an
empty string use the old implementation to handle the special case.
Basically various trivial instances of the following MSVC compiler
warning:
```
../gio/gio-tool-set.c(50): warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data
```
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
It was previously possible for this to silently fail, which isn’t great
for program correctness. Instead, raise a critical warning so the
programmer knows to either validate their Unicode inputs, or fix their
format placeholders.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: #3187
...much like g_string_free_and_steal () does; by redirecting
g_string_free (_, FALSE) calls (when we can detect them) to
g_string_free_and_steal ().
This relies on some unpretty macros, but should be entirely transparent
to any users of g_string_free (). In particular, the macro only
evaluates its arguments once, no matter which branch ends up being
taken. The ternary operator the macro expands to always gets optimized
out, even at -O0: there is only one call to either g_string_free () or
g_string_free_and_steal () in the compiled code, with no run-time
branching.
Add a test for ensuring this works as expected in C++ too.
Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
Add static inline versions of these functions
that boil down to just an memcpy. ag_string_append_len
is used quite a bit in GMarkup and GTK's css parser.
Add SPDX license (but not copyright) headers to all files which follow a
certain pattern in their existing non-machine-readable header comment.
This commit was entirely generated using the command:
```
git ls-files glib/*.[ch] | xargs perl -0777 -pi -e 's/\n \*\n \* This library is free software; you can redistribute it and\/or\n \* modify it under the terms of the GNU Lesser General Public/\n \*\n \* SPDX-License-Identifier: LGPL-2.1-or-later\n \*\n \* This library is free software; you can redistribute it and\/or\n \* modify it under the terms of the GNU Lesser General Public/igs'
```
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #1415
This matches the behaviour of Python `str.replace()`, and avoids carrying
out 2**32 replacements before n wraps around, which is almost certainly
not what we want.
Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/2452
Signed-off-by: Simon McVittie <smcv@collabora.com>
glib/gstring.c: In function ‘g_string_replace’:
glib/gstring.c:998:13: warning: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘guint’ {aka ‘unsigned int’}
998 | if (n == limit)
| ^~
This adds g_string_replace(), a function that replaces instances of one string
with another in a GString. It allows the caller to specify the maximum number
of replacements to perform, and returns the number of replacements performed
to the caller.
Fixes: #225
Add a set of new URI parsing and generating functions, including a new
parsed-URI type GUri. Move all the code from gurifuncs.c into guri.c,
reimplementing some of those functions (and
g_string_append_uri_encoded()) in terms of the new code.
Fixes:
https://gitlab.gnome.org/GNOME/glib/issues/110
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Document that g_vasprintf and g_strdup_printf are guaranteed to return a
non-NULL string, unless the format string contains the locale sensitive
conversions %lc or %ls.
Further annotate that the output parameter for g_vasprintf and the
format string for all functions must be non-NULL.
Fixes#1622
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
In file included from glib/glibconfig.h:9,
from glib/gtypes.h:32,
from glib/gstring.h:32,
from glib/gstring.c:37:
glib/gstring.c: In function ‘g_string_insert_len’:
glib/gstring.c:441:31: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’} [-Werror=sign-compare]
g_return_val_if_fail (pos <= string->len, string);
^~
glib/gmacros.h:455:25: note: in definition of macro ‘G_LIKELY’
#define G_LIKELY(expr) (expr)
^~~~
glib/gstring.c:441:5: note: in expansion of macro ‘g_return_val_if_fail’
g_return_val_if_fail (pos <= string->len, string);
^~~~~~~~~~~~~~~~~~~~
glib/gstring.c:458:15: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’} [-Werror=sign-compare]
if (pos < string->len)
^
glib/gstring.c:462:18: error: comparison of integer expressions of different signedness: ‘gsize’ {aka ‘long unsigned int’} and ‘gssize’ {aka ‘long int’} [-Werror=sign-compare]
if (offset < pos)
^
In file included from glib/glibconfig.h:9,
from glib/gtypes.h:32,
from glib/gstring.h:32,
from glib/gstring.c:37:
glib/gmacros.h:351:26: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘long unsigned int’ [-Werror=sign-compare]
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
^
glib/gstring.c:464:22: note: in expansion of macro ‘MIN’
precount = MIN (len, pos - offset);
^~~
glib/gmacros.h:351:35: error: operand of ?: changes signedness from ‘gssize’ {aka ‘long int’} to ‘long unsigned int’ due to unsignedness of other operand [-Werror=sign-compare]
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
^~~
glib/gstring.c:464:22: note: in expansion of macro ‘MIN’
precount = MIN (len, pos - offset);
^~~
glib/gstring.c:469:15: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’} [-Werror=sign-compare]
if (len > precount)
^
glib/gstring.c:481:15: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’} [-Werror=sign-compare]
if (pos < string->len)
^
In file included from glib/glibconfig.h:9,
from glib/gtypes.h:32,
from glib/gstring.h:32,
from glib/gstring.c:37:
glib/gstring.c: In function ‘g_string_insert_c’:
glib/gstring.c:782:31: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’} [-Werror=sign-compare]
g_return_val_if_fail (pos <= string->len, string);
^~
glib/gmacros.h:455:25: note: in definition of macro ‘G_LIKELY’
#define G_LIKELY(expr) (expr)
^~~~
glib/gstring.c:782:5: note: in expansion of macro ‘g_return_val_if_fail’
g_return_val_if_fail (pos <= string->len, string);
^~~~~~~~~~~~~~~~~~~~
glib/gstring.c:785:11: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’} [-Werror=sign-compare]
if (pos < string->len)
^
In file included from glib/glibconfig.h:9,
from glib/gtypes.h:32,
from glib/gstring.h:32,
from glib/gstring.c:37:
glib/gstring.c: In function ‘g_string_insert_unichar’:
glib/gstring.c:857:31: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’} [-Werror=sign-compare]
g_return_val_if_fail (pos <= string->len, string);
^~
glib/gmacros.h:455:25: note: in definition of macro ‘G_LIKELY’
#define G_LIKELY(expr) (expr)
^~~~
glib/gstring.c:857:5: note: in expansion of macro ‘g_return_val_if_fail’
g_return_val_if_fail (pos <= string->len, string);
^~~~~~~~~~~~~~~~~~~~
glib/gstring.c:860:11: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’} [-Werror=sign-compare]
if (pos < string->len)
^
In file included from glib/glibconfig.h:9,
from glib/gtypes.h:32,
from glib/gstring.h:32,
from glib/gstring.c:37:
glib/gstring.c: In function ‘g_string_erase’:
glib/gstring.c:969:29: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’} [-Werror=sign-compare]
g_return_val_if_fail (pos <= string->len, string);
^~
glib/gmacros.h:455:25: note: in definition of macro ‘G_LIKELY’
#define G_LIKELY(expr) (expr)
^~~~
glib/gstring.c:969:3: note: in expansion of macro ‘g_return_val_if_fail’
g_return_val_if_fail (pos <= string->len, string);
^~~~~~~~~~~~~~~~~~~~
glib/gstring.c:975:39: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’} [-Werror=sign-compare]
g_return_val_if_fail (pos + len <= string->len, string);
^~
glib/gmacros.h:455:25: note: in definition of macro ‘G_LIKELY’
#define G_LIKELY(expr) (expr)
^~~~
glib/gstring.c:975:7: note: in expansion of macro ‘g_return_val_if_fail’
g_return_val_if_fail (pos + len <= string->len, string);
^~~~~~~~~~~~~~~~~~~~
glib/gstring.c:977:21: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’} [-Werror=sign-compare]
if (pos + len < string->len)
^
The g_string_insert_len method accepts '-1' for its len parameter,
as a shorthand for strlen(val). Likewise the various convenience
wrappers around it also accept -1. This was not documented, leaving
developers to wonder why len is a gssize, instead of gsize.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
All glib/*.{c,h} files have been processed, as well as gtester-report.
12 of those files are not licensed under LGPL:
gbsearcharray.h
gconstructor.h
glibintl.h
gmirroringtable.h
gscripttable.h
gtranslit-data.h
gunibreak.h
gunichartables.h
gunicomp.h
gunidecomp.h
valgrind.h
win_iconv.c
Some of them are generated files, some are licensed under a BSD-style
license and win_iconv.c is in the public domain.
Sub-directories inside glib/:
deprecated/: processed in a previous commit
glib-mirroring-tab/: already LGPLv2.1+
gnulib/: not modified, the code is copied from gnulib
libcharset/: a copy
pcre/: a copy
tests/: processed in a previous commit
https://bugzilla.gnome.org/show_bug.cgi?id=776504
Add various (nullable) and (optional) annotations which were missing
from a variety of functions. Also port a couple of existing (allow-none)
annotations in the same files to use (nullable) and (optional) as
appropriate instead.
Secondly, add various (not nullable) annotations as needed by the new
default in gobject-introspection of marking gpointers as (nullable). See
https://bugzilla.gnome.org/show_bug.cgi?id=729660.
This includes adding some stub documentation comments for the
assertion macro error functions, which weren’t previously documented.
The new comments are purely to allow for annotations, and hence are
marked as (skip) to prevent the symbols appearing in the GIR file.
https://bugzilla.gnome.org/show_bug.cgi?id=719966
Many of the append and prepend variants are just thin wrappers
around another one. Remove parameter checking in the wrapper
for these cases. The wrapped function is checking them anyway.
It’s NULL iff free_segment is TRUE, so the annotation doesn’t quite
capture all the function definition, but is a safe over-estimate of the
return value’s nullability.
https://bugzilla.gnome.org/show_bug.cgi?id=719966
- GSubprocessLauncher exists since 2.40, not 2.36
- more logical order for g_markup functions
- fix short description of GMarkup
- GMarkupParser: specify that some parameters are NULL-terminated.
- g_string_new (NULL); is possible.
- other trivial fixes.
https://bugzilla.gnome.org/show_bug.cgi?id=728983
In Windows development environments that have it, <unistd.h> is mostly
just a wrapper around several other native headers (in particular,
<io.h>, which contains read(), close(), etc, and <process.h>, which
contains getpid()). But given that some Windows dev environments don't
have <unistd.h>, everything that uses those functions on Windows
already needed to include the correct Windows header as well, and so
there is never any point to including <unistd.h> on Windows.
Also, remove some <unistd.h> includes (and a few others) that were
unnecessary even on unix.
https://bugzilla.gnome.org/show_bug.cgi?id=710519
Assume all supported platforms implement C90, and therefore they
(correctly) implement atexit(), memmove(), setlocale(), strerror(),
and vprintf(), and have <float.h> and <limits.h>.
(Also remove the configure check testing that "do ... while (0)" works
correctly; the non-do/while-based version of G_STMT_START and
G_STMT_END was removed years ago, but the check remained. Also, remove
some checks that configure.ac claimed were needed for libcharset, but
aren't actually used.)
Note that removing the g_memmove() function is not an ABI break even
on systems where g_memmove() was previously not a macro, because it
was never marked GLIB_AVAILABLE_IN_ALL or listed in glib.symbols, so
it would have been glib-internal since 2004.
https://bugzilla.gnome.org/show_bug.cgi?id=710519
The docs for GString should really mention GByteArray, and what makes
it different. Drop the comparison to Java which is dated and actually
inaccurate (because StringBuffer operates on Unicode).
While we're here, add g_string_free_to_bytes(), which further
complements the spread of GBytes-based API. For example, one can
create a buffer using GString, then send it off via
g_output_stream_write_bytes().
https://bugzilla.gnome.org/show_bug.cgi?id=677064
This is the same as what we were already doing with 2 changes:
- use an initial value of 5381 instead of 0
- multiply by 33 in each round instead of 31