After the recent reworking of this code it was possible for `g_close()`
to be called on `fd == -1`, which is invalid. It would have reported an
error, were errors not ignored. So it was harmless, but still best to
fix.
Simplify the error handling by combining both error labels and checking
the state of `fd` dynamically.
Coverity CID: #1450834
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
The variable `gconstructor_code` (which is what’s defined by
`gconstructor_as_data_h`) is not used at all inside
`glib-compile-schemas`.
This looks like a copy/paste error from the build definition for
`glib-compile-resources` below, which does need it.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
In the 2.68 cycle we’d added 3 new enumerator elements. Due to the
preceding commit, they can now be annotated with
`GLIB_AVAILABLE_ENUMERATOR_IN_2_68`, which will make it a bit easier for
third party projects to notice when they’re using these symbols without
having bumped their GLib dependency.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2327
`""` is not a valid path (`stat()` on it returns `ENOENT`). Previously,
a full `GLocalFile` was being created, which ended up resolving to
`$CWD`, through path canonicalisation. That isn’t right.
Fix it by creating a `GDummyFile` instead, and adding a unit test.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2328
Calling `dlopen()` with `libutil.so` makes the installed tests depend on
having glibc's development files installed. To avoid this, we can work
out the runtime library name at build time and `dlopen` that instead.
This approach is [taken from libfprint][1], thanks to Marco Trevisan.
[1]: f401f399a8
`ENXIO` can be returned from `open(2)` for special files (FIFOs, device
files and domain sockets) which are not backed by anything.
This fixes the error returned by `g_file_replace()` when trying to
replace such a file, so that it now matches the documentation.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
These test all the functionality and combinations of flags I can think
of. They do not cover dynamic behaviour (for example, what would happen
if the source file is deleted by another process part-way through a call
to `g_file_replace()`).
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
The `G_FILE_CREATE_REPLACE_DESTINATION` flag is equivalent to unlinking
the destination file and re-creating it from scratch. That did
previously work, but in the process the code would call `open(O_CREAT)`
on the file. If the file was a dangling symlink, this would create the
destination file (empty). That’s not an intended side-effect, and has
security implications if the symlink is controlled by a lower-privileged
process.
Fix that by not opening the destination file if it’s a symlink, and
adjusting the rest of the code to cope with
- the fact that `fd == -1` is not an error iff `is_symlink` is true,
- and that `original_stat` will contain the `lstat()` results for the
symlink now, rather than the `stat()` results for its target (again,
iff `is_symlink` is true).
This means that the target of the dangling symlink is no longer created,
which was the bug. The symlink itself continues to be replaced (as
before) with the new file — this is the intended behaviour of
`g_file_replace()`.
The behaviour for non-symlink cases, or cases where the symlink was not
dangling, should be unchanged.
Includes a unit test.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2325
Since a following commit is going to add a new test which references
Gitlab, so it’s best to move the URI bases inside the test cases.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
When GLib code is checked out with Windows line endings (happens on Windows),
data-to-c.py embedded that line endings into generated string literal. And
then they translated to double newlines in glib-compile-resources output.
clang-cl failed to compile such files because of empty lines in the middle of
multiline macros:
#define G_MSVC_CTOR(_func,_sym_prefix) \
static void _func(void); \
To fix the issue, enable 'universal newlines' mode when reading the input in
data-to-c.py - translate both '\n' and '\r\n' to '\n'.
Fixes https://gitlab.gnome.org/GNOME/glib/-/issues/2340
This will require distributions to ensure they pass
`--localstatedir=/var` correctly to Meson, but they should be doing that
already.
See https://mesonbuild.com/Builtin-options.html#directories for details
about how Meson treats `localstatedir` differently from most other `dir`
variables.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
It’s unlikely that the machine ID will be invalid (it’s system
configuration), but it would be helpful to not propagate invalid IDs
further, since a lot of things rely on it.
It’s not easy to test this (it requires factoring out the code so it can
be used from a test program, or allowing it to load a machine ID from a
custom path), so I haven’t added unit tests. I’ve tested manually by
overriding the loaded machine ID.
Coverity CID: #1430944
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
For non-Linux UNIX systems, the label 'close_libutil:' in
'test_pollable_unix_pty()' will have no statement that goes with that
label. Just do a 'return' on non-Linux UNIX systems.
File monitor creation may fail. We should check for this, rather than
ignoring it and then spewing criticals upon improperly assuming that we
have a valid GFileMonitor rather than NULL.
In practice, creating the GFileMonitors here fail when opening a large
number of tabs in Epiphany. I'm still investigating to see why, but it
doesn't matter for the purposes of this commit.
Expand an existing unit test to check that the target FD of a
`g_subprocess_launcher_take_fd()` call doesn’t get closed when
`g_subprocess_launcher_close()` is called. Only the source FD should be
closed by the parent process.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2332
This is a regression introduced in commit 67a589e505. Previously, the
source/target FD pairs were stored in `needdup_fd_assignments`, in
consecutive entries, so source FDs had even indices and target FDs had
odd indices.
I didn’t notice that the array index was being incremented by 2 when
closing FDs, when porting from the old code. So previously the code was
only closing the source FDs; after the port, it was closing source and
target FDs.
That’s incorrect, as the target FDs are just integers in the parent
process. It’s only in the child process where they are actually FDs —
and `g_subprocess_launcher_close()` is never called in the child
process.
This resulted in some strange misbehaviours in any process which used
`g_subprocess_launcher_take_fd()` with target FDs which could have
possibly aliased with other FDs in the parent process (and which weren’t
equal to their mapped source FDs).
Thanks to Olivier Fourdan for the detailed bug report.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2332
This was correctly annotated for proper return values but in case of out
parameters it was only annotated as (optional) and not additionally as
(nullable).
This improves performance by eliminating the use of a
`GSpawnChildSetupFunc` in the common case (since that setup code has now
moved into `g_spawn*()` itself), and enables the use of the fix to avoid
the child error reporting FD being overwritten by target FD mappings,
introduced via `g_spawn_async_with_pipes_and_fds()`.
It reworks how the source/target FD mapping is stored within
`GSubprocessLauncher` to match what `g_spawn*()` uses. The two
approaches are equivalent.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2097
gio/gmemoryoutputstream.c: In function ‘g_memory_output_stream_seek’:
gio/gmemoryoutputstream.c:792:44: error: comparison of integer expressions of different signedness: ‘goffset’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’}
792 | if (priv->realloc_fn == NULL && absolute > priv->len)
| ^
gio/gdummyfile.c: In function ‘unescape_string’:
gio/gdummyfile.c:485:32: error: comparison of integer expressions of different signedness: ‘long int’ and ‘size_t’ {aka ‘long unsigned int’}
485 | g_warn_if_fail (out - result <= strlen (escaped_string));
| ^~
gio/gapplication-tool.c: In function ‘app_help’:
glib/gmacros.h:806:26: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘size_t’ {aka ‘long unsigned int’}
gio/gapplication-tool.c:121:26: note: in expansion of macro ‘MAX’
121 | maxwidth = MAX(maxwidth, strlen (_(substvars[i].var)));
| ^~~
gio/gapplication-tool.c: In function ‘app_help’:
glib/gmacros.h:806:26: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘size_t’ {aka ‘long unsigned int’}
gio/gapplication-tool.c:140:20: note: in expansion of macro ‘MAX’
140 | maxwidth = MAX(maxwidth, strlen (topics[i].command));
| ^~~
gio/gapplication-tool.c: In function ‘app_help’:
gio/gapplication-tool.c:90:21: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘long unsigned int’
90 | for (i = 0; i < G_N_ELEMENTS (topics); i++)
| ^
gio/gapplication-tool.c:117:25: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘long unsigned int’
117 | for (i = 0; i < G_N_ELEMENTS (substvars); i++)
| ^
gio/gapplication-tool.c:121:25: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘long unsigned int’
121 | for (i = 0; i < G_N_ELEMENTS (substvars); i++)
| ^
gio/gapplication-tool.c:137:21: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘long unsigned int’
137 | for (i = 0; i < G_N_ELEMENTS (topics); i++)
| ^
gio/gapplication-tool.c:140:21: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘long unsigned int’
140 | for (i = 0; i < G_N_ELEMENTS (topics); i++)
| ^
Since the previous commit, the generic `GInputStream` implementation of
`skip()` is now equivalent, and results in the same calls to `lseek()`.
Heavily based on an approach by Dan Winship in
https://bugzilla.gnome.org/show_bug.cgi?id=681374.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #587
The default implementation of `g_input_stream_skip()` can skip off the
end of resizable streams, as that’s the behaviour of `g_seekable_seek()`
for that type of stream.
This has previously been fixed for local file input streams (commit
89f9615835), and a unit test added there.
However, the fix should be more generally made in `GInputStream`.
This commit reworks an old patch by Dan Winship on
https://bugzilla.gnome.org/show_bug.cgi?id=681374, which took that
approach.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #587
This is a workaround for the fact that forking without execing is not
easy to do correctly, and `GTestDBus` doesn’t do it correctly. However,
`GTestDBus` is de-facto deprecated and so putting any more effort in is
a waste.
This fixes an issue where a test would print duplicate output when
outputting to a fully-buffered FD, such as a pipe. This is because the
buffer is non-empty before the `fork()`, and ends up duplicated in the
parent and child processes, both of which later flush the duplicated
buffer contents.
Diagnosed and fix suggested by Simon McVittie.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2322
Swedish as spoken in El Salvador is not listed in
/usr/share/i18n/SUPPORTED, and in any case is probably not what we meant.
A more plausible language code would be Swedish as spoken in Sweden.
Prompted by improving the Debian packaging of GLib to generate most of
the language codes mentioned in the tests, so that we can have better
test coverage.
Signed-off-by: Simon McVittie <smcv@collabora.com>
It’s not feasible to test that the require-same-user flag can cause
authentication to fail, as that would require the build environment to
have two users available. We can, however, test that it passes when
authenticating a client and server running under the same user account.
I have manually tested that the new flag works, by running the following
as user A:
```
`$prefix/gdbus-daemon --print-env &`
gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.ListNames
```
And then running the `gdbus call` command again as user B (with the same
value for `DBUS_SESSION_BUS_ADDRESS` in the environment), which
produces:
```
Error connecting: Unexpected lack of content trying to read a line
```
(an authentication rejection)
Commenting out the use of
`G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER` from
`gdbusdaemon.c`, the `gdbus call` command succeeds for both users.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
This doesn’t change the `GDBusDaemon` behaviour, but does simplify the
code a little.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #1804
This eliminates a common use case for the
`GDBusAuthObserver::authorize-authenticated-peer` signal, which is often
implemented incorrectly by people.
Suggested by Simon McVittie.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #1804
These should never have been allowed; they will result in precondition
failures from the `GKeyFile` later on in the code.
A test will be added for this shortly.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fix an effective regression in commit
7781a9cbd2, which happens when
`convert_path()` is called with a `key` which contains no slashes. In
that case, the `key` is entirely the `basename`.
Prior to commit 7781a9cb, the code worked through a fluke of `i == -1`
cancelling out with the various additions in the `g_memdup()` call, and
effectively resulting in `g_strdup (key)`.
Spotted by Guido Berhoerster.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
gio/glib-compile-resources.c: In function ‘parse_resource_file’:
gio/glib-compile-resources.c:553:3: error: missing initializer for field ‘passthrough’ of ‘GMarkupParser’ {aka ‘struct _GMarkupParser’}
553 | GMarkupParser parser = { start_element, end_element, text };
| ^~~~~~~~~~~~~
gio/gio-tool-tree.c: In function ‘do_tree’:
gio/gio-tool-tree.c:124:22: error: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’
124 | for (n = 0; n < level; n++)
| ^
gio/gio-tool-tree.c:197:21: error: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’
197 | for (n = 0; n < level; n++)
| ^
gio/gio-tool.c: In function ‘attribute_flags_to_string’:
gio/gio-tool.c:171:17: error: comparison of integer expressions of different signedness: ‘int’ and ‘long unsigned int’
171 | for (i = 0; i < G_N_ELEMENTS (flag_descr); i++)
| ^
gio/glib-compile-schemas.c: In function ‘parse_gschema_files’:
gio/glib-compile-schemas.c:1773:3: error: missing initializer for field ‘passthrough’ of ‘GMarkupParser’ {aka ‘struct _GMarkupParser’}
1773 | GMarkupParser parser = { start_element, end_element, text };
| ^~~~~~~~~~~~~
gio/glib-compile-schemas.c: In function ‘main’:
gio/glib-compile-schemas.c:2176:5: error: missing initializer for field ‘arg_description’ of ‘GOptionEntry’ {aka ‘struct _GOptionEntry’}
2176 | { "allow-any-name", 0, 0, G_OPTION_ARG_NONE, &allow_any_name, N_("Do not enforce key name restrictions") },
| ^
gio/glib-compile-schemas.c: In function ‘key_state_set_range’:
gio/glib-compile-schemas.c:376:17: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘long unsigned int’
376 | for (i = 0; i < G_N_ELEMENTS (table); i++)
| ^
gio/glib-compile-schemas.c: In function ‘key_state_serialise’:
gio/glib-compile-schemas.c:714:29: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘long unsigned int’
714 | for (i = 0; i < size / sizeof (guint32); i++)
| ^
gio/gsettings-mapping.c: In function ‘g_settings_set_mapping_int’:
gio/gsettings-mapping.c:65:23: error: comparison of integer expressions of different signedness: ‘gint64’ {aka ‘long int’} and ‘long unsigned int’
65 | if (0 <= l && l <= G_MAXUINT64)
| ^~
gio/gsettings-mapping.c: In function ‘g_settings_set_mapping_float’:
gio/gsettings-mapping.c:120:23: error: comparison of integer expressions of different signedness: ‘gint64’ {aka ‘long int’} and ‘long unsigned int’
120 | if (0 <= l && l <= G_MAXUINT64)
| ^~
gio/gsettings-mapping.c: In function ‘g_settings_get_mapping_int’:
gio/gsettings-mapping.c:224:27: error: comparison of integer expressions of different signedness: ‘gint64’ {aka ‘long int’} and ‘long unsigned int’
224 | return (0 <= l && l <= G_MAXUINT64);
| ^~
gio/gsettings-mapping.c: In function ‘g_settings_get_mapping_float’:
gio/gsettings-mapping.c:269:27: error: comparison of integer expressions of different signedness: ‘gint64’ {aka ‘long int’} and ‘long unsigned int’
269 | return (0 <= l && l <= G_MAXUINT64);
| ^~
The GDBusConnectionFlags and GDBusServerFlags can affect how we carry
out authentication and authorization, either making it more or less
restrictive, so it's desirable to "fail closed" if a program is compiled
against a new version of GLib but run against an old version.
Signed-off-by: Simon McVittie <smcv@collabora.com>
The intention here was to assert that the length of the password fits
in a gssize. Passwords more than half the size of virtual memory are
probably excessive.
Fixes: a8b204ff "gtlspassword: Forbid very long TLS passwords"
Signed-off-by: Simon McVittie <smcv@collabora.com>
gio/gsettingsschema.c: In function ‘parse_into_text_tables’:
gio/gsettingsschema.c:682:3: error: missing initializer for field ‘passthrough’ of ‘GMarkupParser’ {aka ‘struct _GMarkupParser’}
682 | GMarkupParser parser = { start_element, end_element, text };
| ^~~~~~~~~~~~~
gio/gsettingsschema.c:683:3: error: missing initializer for field ‘gettext_domain’ of ‘TextTableParseInfo’ [-Werror=missing-field-initializers]
683 | TextTableParseInfo info = { summaries, descriptions };
| ^~~~~~~~~~~~~~~~~~
gio/gmenu.c: In function ‘g_menu_remove’:
gio/gmenu.c:483:47: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘guint’ {aka ‘unsigned int’}
483 | g_return_if_fail (0 <= position && position < menu->items->len);
| ^
gio/gmenu.c: In function ‘g_menu_insert_item’:
gio/gmenu.c:165:32: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘guint’ {aka ‘unsigned int’}
165 | if (position < 0 || position > menu->items->len)
| ^
gio/glocalfileinfo.c: In function ‘get_access_rights’:
gio/glocalfileinfo.c:932:9: error: comparison of integer expressions of different signedness: ‘uid_t’ {aka ‘unsigned int’} and ‘int’
932 | uid == parent_info->owner ||
| ^~
gio/glocalfileinfo.c: In function ‘read_link’:
gio/glocalfileinfo.c:188:21: error: comparison of integer expressions of different signedness: ‘int’ and ‘guint’ {aka ‘unsigned int’}
188 | if (read_size < size)
| ^
The public API `g_tls_password_set_value_full()` (and the vfunc it
invokes) can only accept a `gssize` length. Ensure that nul-terminated
strings passed to `g_tls_password_set_value()` can’t exceed that length.
Use `g_memdup2()` to avoid an overflow if they’re longer than
`G_MAXUINT` similarly.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2319
Don’t use an `int`, that’s potentially too small. In practical terms,
this is not a problem, since no socket address is going to be that big.
By making these changes we can use `g_memdup2()` without warnings,
though. Fewer warnings is good.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2319
Previously, the code in `convert_path()` could not handle keys longer
than `G_MAXINT`, and would overflow if that was exceeded.
Convert the code to use `gsize` and `g_memdup2()` throughout, and
change from identifying the position of the final slash in the string
using a signed offset `i`, to using a pointer to the character (and
`strrchr()`). This allows the slash to be at any position in a
`G_MAXSIZE`-long string, without sacrificing a bit of the offset for
indicating whether a slash was found.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2319
This allows it to handle strings up to length `G_MAXSIZE` — previously
it would overflow with such strings.
Update the several copies of it identically.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2319
Previously it was handled as a `gssize`, which meant that if the
`stop_chars` string was longer than `G_MAXSSIZE` there would be an
overflow.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2319
The members of `URL_COMPONENTS` (`winhttp_file->url`) are `DWORD`s, i.e.
32-bit unsigned integers. Adding to and multiplying them may cause them
to overflow the unsigned integer bounds, even if the result is passed to
`g_memdup2()` which accepts a `gsize`.
Cast the `URL_COMPONENTS` members to `gsize` first to ensure that the
arithmetic is done in terms of `gsize`s rather than unsigned integers.
Spotted by Sebastian Dröge.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2319
Convert all the call sites which use `g_memdup()`’s length argument
trivially (for example, by passing a `sizeof()`), so that they use
`g_memdup2()` instead.
In almost all of these cases the use of `g_memdup()` would not have
caused problems, but it will soon be deprecated, so best port away from
it.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2319
We're using "setuid" here as shorthand for any elevated privileges
that should make us distrust the caller: setuid, setgid, filesystem
capabilities, more obscure Linux things that set the AT_SECURE flag
(such as certain AppArmor transitions), and their equivalents on
other operating systems. This is fine if we do it consistently, but
I'm about to add a check for whether we are *literally* setuid,
which would be particularly confusing without a rename.
Signed-off-by: Simon McVittie <smcv@collabora.com>
gio/ghttpproxy.c: In function ‘g_http_proxy_connect’:
gio/ghttpproxy.c:245:17: error: comparison of integer expressions of different signedness: ‘gsize’ {aka ‘long unsigned int’} and ‘int’
245 | if (nread == -1)
| ^~
gio/ghttpproxy.c:253:22: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’}
253 | if (bytes_read == buffer_length)
| ^~
Various tests have leaks where it isn't clear whether the data is
intentionally not freed, or leaked due to a bug. If we mark these
tests as TODO, we can skip them under AddressSanitizer and get the
rest to pass, giving us a baseline from which to avoid regressions.
Signed-off-by: Simon McVittie <smcv@collabora.com>
AddressSanitizer, UndefinedBehaviourSanitizer and probably others
involve adding instrumentation into the code under test, which doesn't
go well with LD_PRELOAD modules that absolutely need to be
self-contained.
Signed-off-by: Simon McVittie <smcv@collabora.com>
gio/gapplication.c: In function ‘g_application_parse_command_line’:
gio/gapplication.c:545:11: error: missing initializer for field ‘arg_description’ of ‘GOptionEntry’ {aka ‘struct _GOptionEntry’}
545 | N_("Enter GApplication service mode (use from D-Bus service files)") },
| ^~
gio/gapplication.c:557:11: error: missing initializer for field ‘arg_description’ of ‘GOptionEntry’ {aka ‘struct _GOptionEntry’}
557 | N_("Override the application’s ID") },
| ^~
gio/gapplication.c:569:11: error: missing initializer for field ‘arg_description’ of ‘GOptionEntry’ {aka ‘struct _GOptionEntry’}
569 | N_("Replace the running instance") },
| ^~
gio/gdbusconnection.c: In function ‘g_dbus_connection_register_object_with_closures’:
gio/gdbusconnection.c:5527:5: error: missing initializer for field ‘padding’ of ‘GDBusInterfaceVTable’ {aka ‘struct _GDBusInterfaceVTable’}
5527 | };
| ^