Add three classes of test case for which g_utf8_normalize() should
safely return NULL:
- Strings ending with a truncated multibyte character which would
extend past the NUL terminator
- Strings ending with a multibyte character which extends past the
length limit provided by the max_len argument
- Strings containing an invalid multibyte character in any position
_g_utf8_normalize_wc() could read past the end of the provided buffer if
it ends with a truncated multibyte character. If max_len is -1, it can
continue reading until it encounters either a NUL or unreadable
memory. Avoid this with extra bounds checks prior to g_utf8_get_char()
to ensure that it does not read past either max_len or a NUL
terminator.
The ref on the timeout source owned by `SendMessageData` was being
dropped just after attaching the source to the main context, leaving it
unowned in that struct. That meant the only ref on the source was held
by the `GMainContext` it was attached to.
This ref was dropped when returning `G_SOURCE_REMOVE` from
`send_message_with_reply_timeout_cb()`. Before that happens,
`send_message_data_deliver_error()` is called, which normally calls
`send_message_with_reply_cleanup()` and destroys the source.
However, if `send_message_data_deliver_error()` is called when the
message has already been delivered, calling
`send_message_with_reply_cleanup()` will be skipped. This leaves the
source pointer in `SendMessageData` dangling, which will cause problems
when `g_source_destroy()` is subsequently called on it.
I’m not sure if it’s possible in practice for this situation to occur,
but the code certainly does nothing to prevent it, and it’s easy enough
to avoid by keeping a strong ref on the source in `SendMessageData`.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #1264
It already implicitly held a strong ref on its `GTask` values, but
didn’t have a free function set so that they would be automatically
unreffed on removal from the map.
This meant that the functions handling removals from the map,
`on_worker_closed()` (via `cancel_method_on_close()`) and
`send_message_with_reply_cleanup()` had to call unref once more than
they would otherwise.
In `send_message_with_reply_cleanup()`, this behaviour depended on
whether it was called with `remove == TRUE`. If not, it was `(transfer
none)` not `(transfer full)`. This led to bugs in its callers.
For example, this led to a direct leak in `cancel_method_on_close()`, as
it needed to remove tasks from `map_method_serial_to_task`, but called
`send_message_with_reply_cleanup(remove = FALSE)` and erroneously didn’t
call unref an additional time.
Try and simplify it all by setting a `GDestroyNotify` on
`map_method_serial_to_task`’s values, and making the refcount handling
of `send_message_with_reply_cleanup()` not be conditional on its
arguments.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #1264
This is equivalent to the current behaviour, but a little clearer in its
meaning.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #1264
The ownership transfers in this code are a bit complex, so adding some
extra documentation and `g_steal_pointer()` calls should hopefully help
clarify things.
This doesn’t introduce any functional changes, just code documentation.
Another drive-by improvement in the quest for #1264.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #1264
The existing comment in the code was correct that `data` is freed when
the task callback is called, because `data` is also pointed to by the
`user_data` for the task, and that’s freed at the end of the callback.
So the existing code was correct to take a copy of `data->task` before
calling `g_task_return_*()`.
After calling `g_task_return_*()`, the existing code unreffed the task
(which is correct), but then didn’t clear the `data->task` pointer,
leaving `data->task` dangling. That could cause a use-after-free or a
double-unref.
Avoid that risk by explicitly clearing `data->task` before calling
`g_task_return_*()`.
After some testing, it turns out this doesn’t actually fix any bugs, but
it’s still a good robustness improvement.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #1264
Calling g_signal_handlers_block/unblock/disconnect_matched with only G_SIGNAL_MATCH_ID
do not match any handlers and return 0.
Fixes: #2980
Signed-off-by: Przemyslaw Gorszkowski <pgorszkowski@igalia.com>
The use of ‘OR’ in the existing documentation suggests that the matching
is disjunctive, but it’s actually conjunctive. Clarify that in the
documentation and add a test.
Spotted while reviewing
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3376.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
The documentation previously implicitly said in a few places that
interfaces are classed, but reading through the implementation of
`GType`, I don’t think they are. If they were, the registration of the
fundamental `G_TYPE_INTERFACE` in `gobject_init()` would specify
`G_TYPE_FLAG_CLASSED`. It only specifies `G_TYPE_FLAG_DERIVABLE`.
I think this makes sense, because you can’t subclass an interface.
Subclassing is a key property of being classed.
Tweak the `GType` tutorial to remove that implicit statement, and expand
the documentation for `G_TYPE_IS_CLASSED`.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #252
‘returns TRUE on success’ is misleading for a lot of these macros, as
they are checking whether a type has a certain property. Such a check
could be successful but return `FALSE`, by the normal meaning of the
word ‘success’.
Instead, reword the docs to spell out when `TRUE` will be returned.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
The generated gir file marks the size parameter as "out" by default. This is wrong in the context of a caller allocated buffer with a given size. Explicitly marking the size parameter as (in) fixes the issue.
See issue GNOME/glib#2861. Even though (hopefully!) few people are
actually running kernels this old, some build frameworks use very old
kernel headers to try to maximize the portability of their binary
artifacts.
As explained in the previous commit, GNU Coreutils 9.2 changes the behaviour
of `du --bytes` to only count regular files and symlinks.
The previous commit makes the test pass with GNU Coreutils >=9.2, but the
machine running the tests may have an older version, or perhaps even a
reimplementation such as uutils. So we can't rely on the size returned by `du`
to be the consistent across systems any more.
However, the plus side of the new behaviour is that the size reported by `du`
/ `G_FILE_MEASURE_APPARENT_SIZE` is now well-defined across filesystems
(as the sum of the sizes of regular files & symlinks), so we can hardcode it.
Fixes: https://gitlab.gnome.org/GNOME/glib/-/issues/2965
Since GNU Coreutils 9.2 (commit 110bcd28386b1f47a4cd876098acb708fdcbbb25),
`du --apparent-size` (including `du --bytes`) no longer counts all kinds of
files (directories, FIFOs, etc.), but only those for which `st_size` in
`struct stat` is defined by POSIX, namely regular files and symlinks
(and also rarely supported memory objects).
This aligns the behaviour of GLib's `G_FILE_MEASURE_APPARENT_SIZE` flag
with the new GNU Coreutils `du` and correct POSIX use.
Note that this may be a breaking change for some uses.
Link: https://lists.gnu.org/archive/html/bug-coreutils/2023-03/msg00007.html
Fixes: https://gitlab.gnome.org/GNOME/glib/-/issues/2965
Warn when the boolean return isn't used, since we may not initialize
the out arguments in the FALSE case. Update all internal callers to
use the return value. They were already safe, but users outside GLib
may not be.