Commit Graph

9191 Commits

Author SHA1 Message Date
Philip Withnall
a40a33dfe0
tests: Rework a mainloop test to use an explicit termination condition
And to not assume that every main context iteration will provide
progress on the sources that the test is interested in. It’s possible
that other sources may be attached to the `GMainContext` which get
dispatched instead of the pipe sources on an iteration.

I don’t know if this will fix #3483, but it will certainly make this
test a little tidier. It doesn’t affect test run time.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Fixes: #3483
2024-10-01 13:32:29 +01:00
Christian Hergert
4db378a739 gvariant: Add portable alignment fix for GVariant suffix
We want to keep the suffix aligned to 8 bytes on 32-bit too. This makes
sure we do that in a way that is portable across our supported compilers.

Fixes: #3486
2024-10-01 12:19:26 +01:00
Chun-wei Fan
1b9d3964f5 gvariant-core.c: Fix suffix alignment on 32-bit MSVC builds
With a similar rationale to commit d50102f2, this avoids the static
assert from failing on 32-bit Visual Studio builds.
2024-10-01 17:25:37 +08:00
Philip Withnall
d50102f2d8
gvariant: Fix suffix alignment on 32-bit machines
This fixes commit 0b083e3d8c. The static assertion added in that commit
fails on 32-bit machines.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-29 13:12:31 +01:00
Philip Withnall
d3e0d4fbde
gpoll: Remove unused variable
Fixes commit 3baf1f1a73.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-29 12:30:53 +01:00
James Tirta
e8517e7776 remove quadratic behavior in g_string_replace
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.
2024-09-28 21:09:53 +00:00
Philip Withnall
019de2cbbc Merge branch 'wip/chergert/gvariant-inline-suffix-data' into 'main'
glib/gvariant: Inline small gvariant data using C99 flexible arrays

See merge request GNOME/glib!4301
2024-09-27 12:35:05 +00:00
Christian Hergert
0b083e3d8c glib/gvariant: Avoid many GBytes allocation
Previously, all GVariants would allocate a GBytes for the buffered
contents. This presents a challenge for small GVariant type created
during the building process of GVariantBuilder as that results in an
allocation for the GVariant, GBytes, and the byte buffer.

Recent changes for GBytes may reduce those 3 allocations to 2, but even
that is quite substantial overhead for a 32-bit integer.

This changeset switches GVariant to use g_new/g_free allocators instead
of g_slice_new/free. When benchmarked alone, this presented no
measurable difference in overhead with the standard glibc allocator.

With that change in place, allocations may then become variable in size
to contain small allocations at the end of the GVariant reducing things
to a single allocation (plus the GVariantTypeInfo reference).

The size of GVariant is already 1 cacheline @ 64-bytes on x86_64. This
uses that to guarantee our alignment of data maintains the 8-bytes
guarantee of GVariant, and also extends it to match malloc().

On 32-bit systems, we are similarly aligned but reduce the amount we
will inline to 32 bytes so we have a total of 1 cacheline.

This is all asserted at compile-time to enforce the guarantee.

In the end, this changeset reduces the wallclock time of building many
GVariant in a loop using GVariantBuilder by 10% beyond the 10% already
gained through GBytes doing the same thing.
2024-09-26 14:28:41 -07:00
Philip Withnall
c2a5bd2c65 Merge branch 'wip/chergert/no-copy-gvarianttype-stack-builder' into 'main'
glib/gvariant: avoid GVariantType copy for stack builders

See merge request GNOME/glib!4286
2024-09-26 11:57:26 +00:00
Philip Withnall
80e8bc7c0b Merge branch 'wip/chergert/reduce-copies-for-gvarianttype-cache' into 'main'
gvarianttypeinfo: reduce caching overhead

See merge request GNOME/glib!4293
2024-09-26 11:11:52 +00:00
Yash Trivedi
3baf1f1a73 gpoll windows: use a threadpool when polling large number of fds 2024-09-26 10:27:19 +00:00
Christian Hergert
c50e44a6e0 glib/gvariant: add g_variant_builder_init_static()
This adds another form of stack building which allows avoiding the rather
expensive GVariantType malloc/memcpy/free. In a tight loop this reduced
wallclock time by about 4-5% for cases where you do not need to further
open using g_variant_builder_open() which still require a copy at this
time.

New API is provided instead of modifying g_variant_type_init() because
previously it was possible (though misguided) to use g_variant_type_init()
which a dynamically allocated GVariantType which could be freed before
g_variant_builder_end() or g_variant_builder_clear() was called.

# Conflicts:
#	glib/gvariant.c
2024-09-25 11:13:58 -07:00
Christian Hergert
2deb5dcfc0 glib/gvariant: add test for g_variant_type_hash() 2024-09-25 10:05:36 -07:00
Christian Hergert
1850b5c1ab gvarianttypeinfo: avoid string copy for cache lookup
When trying to locate a GVariantTypeInfo from the cache we were copying
the string so that we can use g_str_hash, as that requires a \0 terminated
string.

However, we have hash and equal functions which can be used without the
extra copy. Additionally, these were moved to headers in previous commits
so they can be used without having to re-check GVariantType we already
know to be valid.
2024-09-25 10:05:33 -07:00
Philip Withnall
fd9c00179f Merge branch 'wip/chergert/gvariant-use-proper-macros-conditions' into 'main'
Fix incorrect use of assert/debug/check macros

See merge request GNOME/glib!4292
2024-09-25 15:06:10 +00:00
Philip Withnall
267342420f Merge branch 'wip/chergert/fix-ganalyzer-use' into 'main'
glib/gvariant: Fix check for G_ANALYZER_ANALYZING

Closes #3480

See merge request GNOME/glib!4291
2024-09-25 13:43:02 +00:00
Philip Withnall
04e45e3cef Merge branch 'wip/chergert/gvariant-transfer-gbyte-ownership' into 'main'
glib/gvariant: Avoid extraneous GBytes ref counting

See merge request GNOME/glib!4299
2024-09-25 13:42:57 +00:00
Philip Withnall
5ac765689c Merge branch 'wip/chergert/g_variant_ref_sink-perf' into 'main'
glib/gvariant: skip bitlock for g_variant_ref_sink()

See merge request GNOME/glib!4302
2024-09-25 13:21:56 +00:00
Philip Withnall
765eea0a78 Merge branch 'wip/chergert/gvarianttype-proper-const' into 'main'
gvarianttype: mark const functions as such

See merge request GNOME/glib!4294
2024-09-25 13:11:11 +00:00
Philip Withnall
e071e1bfc0 Merge branch 'wip/chergert/avoid-malloc-in-format-string-validation' into 'main'
gvariant: Avoid malloc/free in valid_format_string()

See merge request GNOME/glib!4295
2024-09-25 13:10:34 +00:00
Philip Withnall
5d40bc448e Merge branch 'wip/chergert/g_variant_type_is_subtype_of-fastpath' into 'main'
glib/gvarianttype: g_variant_type_is_subtype_of() fastpath

See merge request GNOME/glib!4297
2024-09-25 13:08:52 +00:00
Philip Withnall
4596bd819d Merge branch 'wip/chergert/gvariantbuilder-avoid-g_renew-for-known-children-length' into 'main'
glib/gvariant: avoid g_renew() for definite tuples

See merge request GNOME/glib!4298
2024-09-25 13:03:22 +00:00
Christian Hergert
9a380ee918 glib/gvariant: Avoid extraneous GBytes ref counting
Right now we create a bunch of GBytes which then get their reference count
incremented and immediately decremented. This causes quite a bit of
disruption for cacheline re-use.

Instead, this change creates an internal helper to transfer ownership of
GBytes to the new GVariant directly.

Surprisingly, this reduced wallclock time by about 6% for a contrived
benchmark of building "as" variant with GVariantBuilder.
2024-09-25 13:09:17 +01:00
Philip Withnall
842c828535 Merge branch 'wip/chergert/use-utf8-validate-for-strlen' into 'main'
glib/gvariant: use g_utf8_validate() for strlen

See merge request GNOME/glib!4296
2024-09-25 12:00:26 +00:00
Philip Withnall
4a72791181
tests: Add tests for UTF-8 checks for g_variant_new_string()
Brings the test coverage from the previous commit back up to 100% of
lines of those functions.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-25 12:24:22 +01:00
Christian Hergert
1e3b010af8 glib/gbytes: save small byte buffers inline
When dealing with small allocations it can save considerable cycles to
do a single allocation for both the GBytes and the data by tacking it
onto the end of the GBytes.

Care is taken to preserve the glibc expectation of 2*sizeof(void*)
alignment of allocations at the expense of some padding bytes.

The degenerate case here is when you want to steal the bytes afterwards
but that amounts to the same overhead as the status-quo.

Where this can help considerably is in GVariant building such as
g_variant_new_int32() which allocates for the GVariant, the GBytes, and
the int32 within the GBytes.

In a simple benchmark of using GVariantBuilder to create "(ii)" variants
this saved about 10% in wallclock time.
2024-09-25 10:49:19 +00:00
Christian Hergert
3566aeb079 glib/gvariant: skip bitlock for g_variant_ref_sink()
In almost all cases, the variant is sunk shortly after creation and
certainly before other threads get a view of it.

This skips the bitlock for STATE_FLOATING, which is also done in
g_variant_take_ref(). We can do this because STATE_FLOATING may only
be set up-front, never after being cleared.

That allows us to do a relaxed read of the value once (which if it is
zero means no additional atomics beyond our ref count increment) as well
as a single atomic if we do in fact steal the floating reference.

Without any other GVariant performance changes, this is in the 2% range
of benchmarking a tight loop using GVariantBuilder. However, after the
rest of them are applied, the percentage is greater due to reduced
runtime overhead and lands in the 4.5% range.
2024-09-24 18:24:55 -07:00
Christian Hergert
bd0f462729 glib/gvariant: avoid g_renew() for definite tuples
If you have a definite-tuple type such as (iiii) then the number of
children that are allocated will match the offset when a GVariantBuilder
has completed.

That means we can avoid an expensive call into the allocator which is
normally done to shrink memory use by releasing it back to the allocator.

This saves about 5% of wallclock time when building such variants in a
tight loop.
2024-09-24 11:23:54 -07:00
Christian Hergert
7d4ea04ee2 glib/gvarianttype: g_variant_type_is_subtype_of() fastpath
This adds a fastpath for the extremely common case of checking if a
GVariant type is a subtype of itself _and_ a definite basic type. For
example, checking 'i' against 'i' or 's' against 's'.

In a loop using GVariantBuilder this can cut the cost of this function
alone in half on profiles from 3.3% of samples to 1.7% of samples.
2024-09-24 11:13:56 -07:00
Christian Hergert
db77480d97 glib/gvariant: use g_utf8_validate() for strlen
We can get the length of the string if we provide an out argument to
g_utf8_validate(). This avoids an extra strlen() when creating GVariant
for UTF-8 strings.

This is good for nearly 7% reduction of CPU samples when building
heavily string-based GVariant using GVariantBuilder as a benchmark.
2024-09-24 11:06:15 -07:00
Christian Hergert
7e362048a3 gvariant: Avoid malloc/free in valid_format_string()
Any extremely common use-case of valid_format_string() is validation
when using GVariantBuilder. The optimal-case there is that there is
no programming error and thus the fast path should match.

This creates a fast path for that case without substantial change to the
GVariant type-checking case by checking for a non-NULL GVariant. It then
proceeds to hoist the actual scan directly without type allocation.

Locally this single change reduces wallclock time in a single-threaded
benchmark using GVariantBuilder by 17%.
2024-09-24 11:02:22 -07:00
Christian Hergert
49bfa7b9cf gvarianttype: mark const functions as such
These functions only rely on their input parameter and no globals, thus
are candidates for sub-expression elimination.
2024-09-24 10:59:20 -07:00
Christian Hergert
72f217e25a gvarianttype: avoid walking type string twice to hash
We already need to walk the string to determine the length of it, so just
hash the string at the same time.
2024-09-24 10:54:32 -07:00
Christian Hergert
9879b7152a gvarianttype: reduce g_variant_type_equal() overhead
Previously, g_variant_type_equal() would walk the strings multiple times.
In debug builds, you initially have the type checks for validity. But
also you walk the string to determine its length only to memcmp it after.

Instead, this does the comparison while walking the string for length.
2024-09-24 10:54:26 -07:00
Christian Hergert
049149c4b7 glib/gvariant: Fix check for G_ANALYZER_ANALYZING
This is _always_ defined in gmacros.h and therefore the #ifdef will always
be 1 even if were disabled. Just #if instead.

Closes: #3480
2024-09-24 09:34:21 -07:00
Christian Hergert
786a5d364c glib/gvarianttype: use G_DISABLE_CAST_CHECKS
Previously, G_VARIANT_TYPE() would "cast check" the type string unless
G_DISABLE_CHECKS was set. We very much don't want people to ever set
G_DISABLE_CHECKS but it is extremely normal to turn of cast-checks using
G_DISASABLE_CAST_CHECKS in stable releases.

This allows disabling the expensive type checking without catastrophically
disabling g_return_if_fail() macros.
2024-09-24 09:27:25 -07:00
Christian Hergert
9eb9df2396 glib/gvarianttypeinfo: use G_ENABLE_DEBUG not !G_DISABLE_ASSERT
Distributions are directed to disable G_ENABLE_DEBUG in stable builds.
Many do not currently disable assertion checks with G_DISABLE_ASSERT.

However this code is very much meant for debugging implementation details
rather than runtime validation. Use G_ENABLE_DEBUG instead of
!G_DISABLE_ASSERT to get the intended behavior.
2024-09-24 09:27:25 -07:00
Philip Withnall
2842e4a86f
gvariant-parser: Assert that pattern lengths don’t overflow
I can’t see it being possible for this to be hit in practice, as it
would require two very long GVariant text format inputs, which would
probably hit input limits earlier on somewhere else.

But in order to avoid a silent integer overflow, let’s check that the
addition won’t overflow before going ahead with it.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Helps: #3469
2024-09-19 17:49:10 +01:00
Philip Withnall
785b61cfcb
gvariant-parser: Add additional buffer byte for nul terminator
In `pattern_coalesce()`.

I am fairly sure this byte is never needed, as the most extreme case of
`max (strlen (left), strlen (right)` vs `strlen (left) + strlen (right)`
I can think of still gives 1 byte left in the buffer (without the need
for this commit).

However, the proof we have of how much space is needed in the buffer
only goes far enough to show that the number of bytes needed before the
nul terminator is at most `strlen (left) + strlen (right)`. That means
we still technically need to add an additional byte for the nul
terminator.

The need for this could be eliminated by coming up with a stronger proof
to show that the number of bytes needed is strictly less than `strlen
(left) + strlen (right)`, but I can’t do that, and adding one byte is
easy to do. Type strings are short and we’re nowhere near making a large
allocation here.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Helps: #3469
2024-09-19 17:44:28 +01:00
Philip Withnall
c7e3512902
tests: Add some additional pattern_coalesce() tests
The first of these tests is to cover the extreme case where the number
of bytes written out by `pattern_coalesce()` is as close to `strlen
(left) + strlen (right)` as we can manage, due to both inputs being
really small and hence `max (strlen (left), strlen (right))` being only
1 less than `strlen (left) + strlen (right)`, which is as close as we
can get to triggering an off-by-one error.

The second of these tests is an attempt to encode the case used in the
proof for correctness of `pattern_coalesce()` not overflowing its buffer
bounds: `(*(iii)) + ((iii)*) = ((iii)(iii))`. I don’t think it’s
actually possible to hit that case, as it’s not possible to generate a
plain `*` in either of the input patterns. `Ma*` is the best we can
manage in practice. See
https://gitlab.gnome.org/GNOME/glib/-/issues/3469#note_2226901 for
reasoning.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Helps: #3469
2024-09-19 17:40:45 +01:00
Philip Withnall
1cb682b320
tests: Fix a minor typo in a comment in gvariant tests
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-19 17:40:24 +01:00
Philip Withnall
3d5ada2689
gvariant-parser: Add a proof for pattern_coalesce()’s safety
This proof backs up the already-present assertion that “the length of
the output is loosely bounded by the sum of the input lengths”.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Helps: #3469
2024-09-19 16:35:27 +01:00
Michael Catanzaro
7f4300c5da gvariant-parser: add assert to ensure we don't write too far
This function is complicated and it's hard to assess whether it is
correct or not, so let's add an assert just to be sure.

Notably, when writing this I initially had an off-by-one error in my
assert, causing the assertion to actually fire when running the unit
tests. So we know it's definitely possible for the function to use the
entirety of the buffer. The upper bound is not loose, and writing one
additional byte would be a security bug.

Note my assertion possibly doesn't protect against security issues
because it will be hit after the bad write rather than before.

Fixes #3469
2024-09-19 09:59:13 -05:00
Michael Catanzaro
7c6b11df2d giochannel: ensure line terminator remains nul-terminated if needed
If the user passes -1 length to g_io_channel_set_line_term() along with
a nul-terminated string, then calls g_io_channel_get_line_term() and
decides to treat the result as nul-terminated rather than checking the
length parameter, then the application will have a problem, because it's
not nul-terminated. That's weird, since the input string was. Let's
ensure the result is consistent: if you pass a nul-terminated string,
the result is nul-terminated. If not, it's not.

Also add a warning to g_io_channel_get_line_term(), since it's very
strange for a gchar * return value to be anything other than a
nul-terminated UTF-8 string. This is an API design bug, but we cannot
fix it.
2024-09-18 01:48:36 +01:00
Michael Catanzaro
a893d622c0 gdatetime: fix double free in format parser
If %#Z is followed by %Z then we accidentally free the tmp variable from
the previous iteration of the loop a second time. Good job to the static
analysis tool (probably Coverity) that found this.

Fortunately it's unlikely that a realistic application would do this.

I've also added a new test that crashes without the fix
2024-09-18 01:48:36 +01:00
Michael Catanzaro
1196ac7af6 gutils: Fix unlikely minor leaks in xdg directory functions
We leak if we have a non-null empty string. This was already fixed for
g_build_user_data_dir() in 1a979ab494
so now fix the others as well.
2024-09-18 01:48:36 +01:00
Michael Catanzaro
f64d4aad6e gvariant-parser: add some comments
I just spent several hours convinced that there was a memory safety
issue in string_parse() and bytestring_parse(). There isn't. (At least,
I think so.) Add some comments to save the next person some time.
2024-09-18 01:48:36 +01:00
Michael Catanzaro
343081becc ggettext: add some comments
Coverity has improperly flagged this code as an instance of CWE-562. The
code is fine, but it's confusing, and humans are likely to wind up
examining it again in the future, so add some comments to explain what's
up.
2024-09-18 01:48:36 +01:00
Philip Withnall
e888e7d497
tests: Add some explicit float → int casts
This avoids some false positive warnings from `-Wfloat-conversion`.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-17 23:54:55 +01:00
Philip Withnall
7a7d8d548a Merge branch 'wfloat-conversion' into 'main'
build: Enable -Wfloat-conversion and fix warnings

See merge request GNOME/glib!4126
2024-09-17 17:57:11 +00:00