If when calling g_cancellable_connect() the cancellable was already
cancelled we could have ended up in calling the data cleanup
function while the cancellable lock was held.
This is likely not an issue, but it's still better not to do it,
so protect the code against it
We had wrong comments, in particular:
@callback is called exactly once each time @cancellable is cancelled,
either directly at the time of the connect if @cancellable is already
cancelled, or when @cancellable is cancelled in some thread.
In case the cancellable is reset via [method@Gio.Cancellable.reset]
then the callback can be called again if the @cancellable is cancelled
This is not true if `@cancellable` is already cancelled because then the
callback will be thrown away, and will not be called for subsequent
cancellations.
Since GLib 2.40, the lock protecting @cancellable is not held when
@callback is invoked. This lifts a restriction in place for
earlier GLib versions which now makes it easier to write cleanup
code that unconditionally invokes e.g. g_cancellable_cancel().
As per commit 3a07b2abd4006 this section needs some amending since
it's not true anymore, as the GCancellable's mutex is held when `@callback` is
invoked. However this happens in a way that it's still safe to call most
of the GCancellable API.
Closes: #3642
When a non-cancelled cancellable ::cancelled signal callback is called
the cancellable has enough references so that it can be unreferenced on
the callback itself. However this doesn't happen if the cancellable has
been already cancelled at the moment we connect to it.
To prevent this, add a temporary reference before calling the signal
callback.
Note that we do this also if the callback has not been already cancelled
to prevent that we may end up calling a toggle-notify callback while we
are locked.
Add tests
Closes: #3643
See the previous commit. Clarify these variable names so it’s more
obvious they contain a size in bytes rather than a length in wide-chars.
This introduces no functional changes.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: #3649
It can be confusing otherwise when getting string values: is the size in
bytes or wide-characters?
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: #3649
`value_size` is in bytes, whereas `ms_resource_prefix_len` is in wide
characters, so they cannot be compared directly. This meant that if
12 ≤ `value_size` < 24 then the call to `memcmp()` would read off the
end of `value`.
Fix it by using a wide-character and nul-aware comparison function and
operating only on wide-lengths. This is safe because
`g_win32_registry_key_get_value_w()` guarantees that string-typed return
values are nul-terminated.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Fixes: #3649
Rather than creating files in the current directory. This is a bit
neater, and avoids races between parallel invocations of the unit tests
if the file names aren’t guaranteed to be unique (e.g. by using
`g_mkstemp()`).
Add `G_TEST_OPTION_ISOLATE_DIRS` too, to make sure we use a unique
subdirectory of `g_get_tmp_dir()`. This means that paths like
`g_get_tmp_dir() / some-file` are guaranteed to be race-free even if the
filename is not unique, because the test tmp dir now is.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
In the `g-file-info-filesystem-readonly` test.
This doesn’t introduce any functional changes, but makes the code a
little easier to read (because the parts of the path are now in
hierarchical order) and makes it a bit clearer that we’re building a
path rather than an arbitrary string.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
It’s not entirely clear from the documentation, but `g_mkstemp()` (and
`g_mkdtemp()`) operate in the current directory, rather than the system
temporary directory.
This meant these tests were all writing files to the build directory.
This is messy, though thankfully not a correctness issue or a race
because `g_mkstemp()` guarantees to return a unique file for each
caller.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Like many things I touch, I broke this in
fd8ede0b661aa67032bbc3e7afc88aff22d7984a.
Spotted by Sebastian Wilhelmi in
fd8ede0b66 (note_2385263).
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Previously, we were getting the string representation. However, this
representation gets escaped, which breaks non-ascii characters, because we
were counting on the path being the original path, which was not true in
these cases.
Retrieve it rather as the byte string which it is.
Fixes#3636.
Apparently it’s possible for `netlink/netlink.h` to be available on
Linux, when we expected it to only be available on FreeBSD, but for
`netlink/netlink_route.h` to not exist. So add a check for the latter.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Fixes: #3630
Otherwise it looks a bit like calls to `delay()` and `apply()` need to
be paired, like calls to `g_object_freeze_notify()` and
`g_object_thaw_notify()`.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Since the docs are saying what type a key must be in the schema to be
able to call that method, it makes sense to give the type in the same
format used in the schema, i.e. a GVariant type string.
Also link to the `GVariantType` documentation so the user can read up on
it further if needed.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
The array was declared one byte too short to contain the trailing nul
byte for the string literal. Spotted by gcc 15.
Fix it by allowing the compiler to work out the array length.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
GUnixFDList actually comes *after* the GDBusMethodInvocation, but this
was mistakenly putting it first.
Signed-off-by: Ryan Gonzalez <ryan.gonzalez@collabora.com>
Three of the four GApplicationCommandLine examples contained this line:
g_application_set_inactivity_timeout (app, 10000);
It is not explained (which could be confusing for readers trying to
understand the examplese), or necessary. Worse, it causes two of the
examples to pause for ten seconds if they are invoked with no command-line
arguments, which makes them seem broken (and would presumably be reported
as a bug in any real application).
So, remove these calls.
Fixes#3615
During "as-installed" testing, we should search the GIR_DIR for GIR XML,
instead of hard-coding that it is `${prefix}/share/gir-1.0`. This is
not the case on at least Debian, in order to make it possible to
install more than one architecture's flavour of `GLib-2.0.gir`,
which contains some architecture-specific `#define`s.
Also search GOBJECT_INTROSPECTION_DATADIR/GIR_SUFFIX (in practice
something like `/usr/share/gir-1.0` in all cases) to accommodate
distributions like Debian that move the architecture-independent
majority of GIR XML into /usr/share to avoid duplication, leaving
only the architecture-specific minority of files like `GLib-2.0.gir`
in the GIR_DIR.
Signed-off-by: Simon McVittie <smcv@collabora.com>
It is easy to overlook that unreffing a GVolumeMonitor doesn't
disconnect signal handlers, this can lead to segfaults from dangling
user data pointers.
The documentation for g_spawn_async_with_pipes_and_fds() states:
> If an error occurs, child_pid, stdin_pipe_out, stdout_pipe_out, and
> stderr_pipe_out will not be filled with valid values.
Before 2dc3a6f0c80e5a8f786369eee0c45bfe19b55f4f, the `child_pid`
argument was `self->pid`, and GObject zero-initializes structs. So
the pid field was properly initialized to zero.
After 2dc3a6f0c80e5a8f786369eee0c45bfe19b55f4f, however, the out
variable is now declared inside initable_init(), and it's unitialized.
So if g_spawn_async_with_pipes_and_fds() errors out, `pid` will have
trash value in it, and the following assertion will fail:
```
g_assert (success == (pid != 0));
```
Fix that by initializing the `pid` variable to zero. Add a test to
exercise the fail code path, and prevent errors like this in the
future.
The process PID is initialized by the initable vfunc, while
g_subprocess_exited sets it again, when we're protecting it via a lock.
The status is set when the process exits instead, again while locking.
This makes the thread sanitizer unhappy (even if it shouldn't really be
a race for the PID init case), but still locking during initialization is
not a bad thing to do.
At the same time g_subprocess_wait() and friends were using the pid and status
values without any protection, so let's ensure this is not the case anymore.
WARNING: ThreadSanitizer: data race (pid=8213)
Write of size 4 at 0x7b200000084c by thread T1:
#0 g_subprocess_exited ../gio/gsubprocess.c:284
#1 g_child_watch_dispatch ../glib/gmain.c:5963
#2 g_main_dispatch ../glib/gmain.c:3373
#3 g_main_context_dispatch_unlocked ../glib/gmain.c:4224
#4 g_main_context_iterate_unlocked ../glib/gmain.c:4289
#5 g_main_context_iteration ../glib/gmain.c:4354
#6 glib_worker_main ../glib/gmain.c:6553
#7 g_thread_proxy ../glib/gthread.c:892
Previous read of size 4 at 0x7b200000084c by main thread:
#0 g_subprocess_wait ../gio/gsubprocess.c:908
#1 g_subprocess_wait_check ../gio/gsubprocess.c:939
#2 end_element ../gio/glib-compile-resources.c:342
#3 emit_end_element ../glib/gmarkup.c:1045
#4 g_markup_parse_context_parse ../glib/gmarkup.c:1603
#5 parse_resource_file ../gio/glib-compile-resources.c:578
#6 main ../gio/glib-compile-resources.c:967
Location is heap block of size 120 at 0x7b2000000800 allocated by main
thread:
#0 calloc <null>
#1 g_malloc0 ../glib/gmem.c:133
#2 g_type_create_instance ../gobject/gtype.c:1933
#3 g_object_new_internal ../gobject/gobject.c:2621
#4 g_object_new_valist ../gobject/gobject.c:2960
#5 g_initable_new_valist ../gio/ginitable.c:245
#6 g_initable_new ../gio/ginitable.c:163
#7 g_subprocess_newv ../gio/gsubprocess.c:619
#8 g_subprocess_new ../gio/gsubprocess.c:590
#9 end_element ../gio/glib-compile-resources.c:334
#10 emit_end_element ../glib/gmarkup.c:1045
#11 g_markup_parse_context_parse ../glib/gmarkup.c:1603
#12 parse_resource_file ../gio/glib-compile-resources.c:578
#13 main ../gio/glib-compile-resources.c:967
Thread T1 'gmain' (tid=8228, running) created by main thread at:
#0 pthread_create <null>
#1 g_system_thread_new ../glib/gthread-posix.c:762
#2 g_thread_new_internal ../glib/gthread.c:996
#3 g_thread_new ../glib/gthread.c:949
#4 g_get_worker_context ../glib/gmain.c:6580
#5 initable_init ../gio/gsubprocess.c:443
#6 g_initable_init ../gio/ginitable.c:129
#7 g_initable_new_valist ../gio/ginitable.c:249
#8 g_initable_new ../gio/ginitable.c:163
#9 g_subprocess_newv ../gio/gsubprocess.c:619
#10 g_subprocess_new ../gio/gsubprocess.c:590
#11 end_element ../gio/glib-compile-resources.c:334
#12 emit_end_element ../glib/gmarkup.c:1045
#13 g_markup_parse_context_parse ../glib/gmarkup.c:1603
#14 parse_resource_file ../gio/glib-compile-resources.c:578
#15 main ../gio/glib-compile-resources.c:967
SUMMARY: ThreadSanitizer: data race ../gio/gsubprocess.c:284 in
g_subprocess_exited
======================================
WARNING: ThreadSanitizer: data race (pid=15959)
Read of size 4 at 0x7b200000084c by main thread:
#0 g_subprocess_wait ../gio/gsubprocess.c:913
#1 g_subprocess_wait_check ../gio/gsubprocess.c:944
#2 test_cat_utf8 ../gio/tests/gsubprocess.c:489
#3 test_case_run ../glib/gtestutils.c:3115
#4 g_test_run_suite_internal ../glib/gtestutils.c:3210
#5 g_test_run_suite_internal ../glib/gtestutils.c:3229
#6 g_test_run_suite ../glib/gtestutils.c:3310
#7 g_test_run ../glib/gtestutils.c:2379
#8 main ../gio/tests/gsubprocess.c:2266
Previous write of size 4 at 0x7b200000084c by thread T1:
#0 g_subprocess_exited ../gio/gsubprocess.c:284
#1 g_child_watch_dispatch ../glib/gmain.c:5963
#2 g_main_dispatch ../glib/gmain.c:3373
#3 g_main_context_dispatch_unlocked ../glib/gmain.c:4224
#4 g_main_context_iterate_unlocked ../glib/gmain.c:4289
#5 g_main_context_iteration ../glib/gmain.c:4354
#6 glib_worker_main ../glib/gmain.c:6553
#7 g_thread_proxy ../glib/gthread.c:892
This is a minor performance improvement, since the pspec list for the
class now only has to be modified once, rather than twice.
It also means we now have the `GParamSpec` pointers to hand in a `props`
array, which will be used in the upcoming commits.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
This lets the compiler tell us if we’ve accidentally missed a property
implementation from `get_property()` or `set_property()`.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>