GFortran broken after f23bac62f46fc296a4d0526ef54824d406c3756c
Patrick Palka
ppalka@redhat.com
Wed Sep 3 18:40:08 GMT 2025
On Wed, 3 Sep 2025, Tobias Burnus wrote:
>
> Hi Andre, hi all,
>
> Andre Vehreschild wrote:
>
> I am experiencing a strange issue with gfortran. Compiling a simple program:
>
> $ cat end.f90
> end
> $ gfortran end.f90 -o end
> f951: Fatal Error: Cannot open pre-included file '\xe0\xd4\xf2,'
> compilation terminated.
>
> From your description, it sounds as if your Stage 1 compiler
> of Fedora 41 is miscompiling gfortran/f951.
>
> I have not understood whether a normal bootstrap, i.e. where
> gfortran is only build during Stage 2 also fails or only a
> non-bootstrap / --enable-stage1-languages=fortran,... built one.
>
> * * *
>
> Yes, the program is doing nothing, but can not be compiled. The pre-included
> file name changes randomly. Looks like something is either overwritten or
> not initialized properly. I bisected this issue down to
> commit f23bac62f46fc296a4d0526ef54824d406c3756c
> Author: John Ericson <git@JohnEricson.me>
> Date: Fri Aug 22 22:24:56 2025 -0400
>
> driver: Rework for_each_path using C++
>
> but I do not see, why this should affect gfortran's ability to build a simple
> program.
>
> Well, from your valgrind output, the issue is in for_each_path
> and 'pre-included' is also run for empty programs - as the name implies
> And there is also a
> -fpre-include=/usr/include/finclude/math-vector-fortran.h
> in your f951 call, which is used to ensure that GLIBC's vector math
> functions are used.
>
> * * *
>
> I don't feel like checking whether there is a bug in
> commit r16-3354-gf23bac62f46fc2 itself or only an issue in the F41 system
> compiler.
There seems to be a bug in r16-3354 that may be causing what the crash
that you're seeing:
> From f23bac62f46fc296a4d0526ef54824d406c3756c Mon Sep 17 00:00:00 2001
> From: John Ericson <git@JohnEricson.me>
> Date: Fri, 22 Aug 2025 22:24:56 -0400
> Subject: driver: Rework for_each_path using C++
>
> The old C-style was cumbersome make making one responsible for manually
> creating and passing in two parts a closure (separate function and
> *_info class for closed-over variables).
>
> With C++ lambdas, we can just:
>
> - derive environment types implicitly
> - have fewer stray static functions
>
> Also thanks to templates we can
> - make the return type polymorphic, to avoid casting pointee types.
>
> Note that `struct spec_path` was *not* converted because it is used
> multiple times. We could still convert to a lambda, but we would want to
> put the for_each_path call with that lambda inside a separate function
> anyways, to support the multiple callers. Unlike the other two
> refactors, it is not clear that this one would make anything shorter.
> Instead, I define the `operator()` explicitly. Keeping the explicit
> struct gives us some nice "named arguments", versus the wrapper function
> alternative, too.
>
> gcc/ChangeLog:
>
> * gcc.cc (for_each_path): templated, to make passing lambdas
> possible/easy/safe, and to have a polymorphic return type.
> (struct add_to_obstack_info): Deleted, lambda captures replace
> it.
> (add_to_obstack): Moved to lambda in build_search_list.
> (build_search_list): Has above lambda now.
> (struct file_at_path_info): Deleted, lambda captures replace
> it.
> (file_at_path): Moved to lambda in find_a_file.
> (find_a_file): Has above lambda now.
> (struct spec_path_info): Reamed to just struct spec_path.
> (struct spec_path): New name.
> (spec_path): Rnamed to spec_path::operator()
> (spec_path::operator()): New name
> (do_spec_1): Updated for_each_path call sites.
>
> Signed-off-by: John Ericson <git@JohnEricson.me>
> Reviewed-by: Jason Merrill <jason@redhat.com>
> ---
> gcc/gcc.cc | 185 +++++++++++++++++++++++++------------------------------------
> 1 file changed, 77 insertions(+), 108 deletions(-)
>
> diff --git a/gcc/gcc.cc b/gcc/gcc.cc
> index bfa588ee5f04..722d42c69683 100644
> --- a/gcc/gcc.cc
> +++ b/gcc/gcc.cc
> @@ -2774,12 +2774,12 @@ clear_failure_queue (void)
>
> Returns the value returned by CALLBACK. */
>
> -static void *
> +template<typename fun>
> +auto *
> for_each_path (const struct path_prefix *paths,
> bool do_multi,
> size_t extra_space,
> - void *(*callback) (char *, void *),
> - void *callback_info)
> + fun && callback)
> {
> struct prefix_list *pl;
> const char *multi_dir = NULL;
> @@ -2788,7 +2788,7 @@ for_each_path (const struct path_prefix *paths,
> const char *multi_suffix;
> const char *just_multi_suffix;
> char *path = NULL;
> - void *ret = NULL;
> + decltype (callback (nullptr)) ret;
'ret' is no longer initialized here, so presumably some code paths now
use it uninitialized.
> bool skip_multi_dir = false;
> bool skip_multi_os_dir = false;
>
> @@ -2839,7 +2839,7 @@ for_each_path (const struct path_prefix *paths,
> if (!skip_multi_dir)
> {
> memcpy (path + len, multi_suffix, suffix_len + 1);
> - ret = callback (path, callback_info);
> + ret = callback (path);
> if (ret)
> break;
> }
> @@ -2850,7 +2850,7 @@ for_each_path (const struct path_prefix *paths,
> && pl->require_machine_suffix == 2)
> {
> memcpy (path + len, just_multi_suffix, just_suffix_len + 1);
> - ret = callback (path, callback_info);
> + ret = callback (path);
> if (ret)
> break;
> }
> @@ -2860,7 +2860,7 @@ for_each_path (const struct path_prefix *paths,
> && !pl->require_machine_suffix && multiarch_dir)
> {
> memcpy (path + len, multiarch_suffix, multiarch_len + 1);
> - ret = callback (path, callback_info);
> + ret = callback (path);
> if (ret)
> break;
> }
> @@ -2888,7 +2888,7 @@ for_each_path (const struct path_prefix *paths,
> else
> path[len] = '\0';
>
> - ret = callback (path, callback_info);
> + ret = callback (path);
> if (ret)
> break;
> }
> @@ -2934,31 +2934,6 @@ for_each_path (const struct path_prefix *paths,
> return ret;
> }
>
> -/* Callback for build_search_list. Adds path to obstack being built. */
> -
> -struct add_to_obstack_info {
> - struct obstack *ob;
> - bool check_dir;
> - bool first_time;
> -};
> -
> -static void *
> -add_to_obstack (char *path, void *data)
> -{
> - struct add_to_obstack_info *info = (struct add_to_obstack_info *) data;
> -
> - if (info->check_dir && !is_directory (path))
> - return NULL;
> -
> - if (!info->first_time)
> - obstack_1grow (info->ob, PATH_SEPARATOR);
> -
> - obstack_grow (info->ob, path, strlen (path));
> -
> - info->first_time = false;
> - return NULL;
> -}
> -
> /* Add or change the value of an environment variable, outputting the
> change to standard error if in verbose mode. */
> static void
> @@ -2979,16 +2954,26 @@ static char *
> build_search_list (const struct path_prefix *paths, const char *prefix,
> bool check_dir, bool do_multi)
> {
> - struct add_to_obstack_info info;
> -
> - info.ob = &collect_obstack;
> - info.check_dir = check_dir;
> - info.first_time = true;
> + struct obstack *const ob = &collect_obstack;
> + bool first_time = true;
>
> obstack_grow (&collect_obstack, prefix, strlen (prefix));
> obstack_1grow (&collect_obstack, '=');
>
> - for_each_path (paths, do_multi, 0, add_to_obstack, &info);
> + /* Callback adds path to obstack being built. */
> + for_each_path (paths, do_multi, 0, [&](char *path) -> void*
> + {
> + if (check_dir && !is_directory (path))
> + return NULL;
> +
> + if (!first_time)
> + obstack_1grow (ob, PATH_SEPARATOR);
> +
> + obstack_grow (ob, path, strlen (path));
> +
> + first_time = false;
> + return NULL;
> + });
>
> obstack_1grow (&collect_obstack, '\0');
> return XOBFINISH (&collect_obstack, char *);
> @@ -3022,42 +3007,6 @@ access_check (const char *name, int mode)
> return access (name, mode);
> }
>
> -/* Callback for find_a_file. Appends the file name to the directory
> - path. If the resulting file exists in the right mode, return the
> - full pathname to the file. */
> -
> -struct file_at_path_info {
> - const char *name;
> - const char *suffix;
> - int name_len;
> - int suffix_len;
> - int mode;
> -};
> -
> -static void *
> -file_at_path (char *path, void *data)
> -{
> - struct file_at_path_info *info = (struct file_at_path_info *) data;
> - size_t len = strlen (path);
> -
> - memcpy (path + len, info->name, info->name_len);
> - len += info->name_len;
> -
> - /* Some systems have a suffix for executable files.
> - So try appending that first. */
> - if (info->suffix_len)
> - {
> - memcpy (path + len, info->suffix, info->suffix_len + 1);
> - if (access_check (path, info->mode) == 0)
> - return path;
> - }
> -
> - path[len] = '\0';
> - if (access_check (path, info->mode) == 0)
> - return path;
> -
> - return NULL;
> -}
>
> /* Search for NAME using the prefix list PREFIXES. MODE is passed to
> access to check permissions. If DO_MULTI is true, search multilib
> @@ -3068,8 +3017,6 @@ static char *
> find_a_file (const struct path_prefix *pprefix, const char *name, int mode,
> bool do_multi)
> {
> - struct file_at_path_info info;
> -
> /* Find the filename in question (special case for absolute paths). */
>
> if (IS_ABSOLUTE_PATH (name))
> @@ -3080,15 +3027,38 @@ find_a_file (const struct path_prefix *pprefix, const char *name, int mode,
> return NULL;
> }
>
> - info.name = name;
> - info.suffix = (mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "";
> - info.name_len = strlen (info.name);
> - info.suffix_len = strlen (info.suffix);
> - info.mode = mode;
> + const char *suffix = (mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "";
> + const int name_len = strlen (name);
> + const int suffix_len = strlen (suffix);
>
> - return (char*) for_each_path (pprefix, do_multi,
> - info.name_len + info.suffix_len,
> - file_at_path, &info);
> +
> + /* Callback appends the file name to the directory path. If the
> + resulting file exists in the right mode, return the full pathname
> + to the file. */
> + return for_each_path (pprefix, do_multi,
> + name_len + suffix_len,
> + [=](char *path) -> char*
> + {
> + size_t len = strlen (path);
> +
> + memcpy (path + len, name, name_len);
> + len += name_len;
> +
> + /* Some systems have a suffix for executable files.
> + So try appending that first. */
> + if (suffix_len)
> + {
> + memcpy (path + len, suffix, suffix_len + 1);
> + if (access_check (path, mode) == 0)
> + return path;
> + }
> +
> + path[len] = '\0';
> + if (access_check (path, mode) == 0)
> + return path;
> +
> + return NULL;
> + });
> }
>
> /* Specialization of find_a_file for programs that also takes into account
> @@ -6008,25 +5978,26 @@ do_self_spec (const char *spec)
>
> /* Callback for processing %D and %I specs. */
>
> -struct spec_path_info {
> +struct spec_path {
> const char *option;
> const char *append;
> size_t append_len;
> bool omit_relative;
> bool separate_options;
> bool realpaths;
> +
> + void *operator() (char *path);
> };
>
> -static void *
> -spec_path (char *path, void *data)
> +void *
> +spec_path::operator() (char *path)
> {
> - struct spec_path_info *info = (struct spec_path_info *) data;
> size_t len = 0;
> char save = 0;
>
> /* The path must exist; we want to resolve it to the realpath so that this
> can be embedded as a runpath. */
> - if (info->realpaths)
> + if (realpaths)
> path = lrealpath (path);
>
> /* However, if we failed to resolve it - perhaps because there was a bogus
> @@ -6034,23 +6005,23 @@ spec_path (char *path, void *data)
> if (!path)
> return NULL;
>
> - if (info->omit_relative && !IS_ABSOLUTE_PATH (path))
> + if (omit_relative && !IS_ABSOLUTE_PATH (path))
> return NULL;
>
> - if (info->append_len != 0)
> + if (append_len != 0)
> {
> len = strlen (path);
> - memcpy (path + len, info->append, info->append_len + 1);
> + memcpy (path + len, append, append_len + 1);
> }
>
> if (!is_directory (path))
> return NULL;
>
> - do_spec_1 (info->option, 1, NULL);
> - if (info->separate_options)
> + do_spec_1 (option, 1, NULL);
> + if (separate_options)
> do_spec_1 (" ", 0, NULL);
>
> - if (info->append_len == 0)
> + if (append_len == 0)
> {
> len = strlen (path);
> save = path[len - 1];
> @@ -6062,7 +6033,7 @@ spec_path (char *path, void *data)
> do_spec_1 (" ", 0, NULL);
>
> /* Must not damage the original path. */
> - if (info->append_len == 0)
> + if (append_len == 0)
> path[len - 1] = save;
>
> return NULL;
> @@ -6250,7 +6221,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
> that we search for startfiles. */
> case 'D':
> {
> - struct spec_path_info info;
> + struct spec_path info;
>
> info.option = "-L";
> info.append_len = 0;
> @@ -6267,13 +6238,13 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
> info.separate_options = false;
> info.realpaths = false;
>
> - for_each_path (&startfile_prefixes, true, 0, spec_path, &info);
> + for_each_path (&startfile_prefixes, true, 0, info);
> }
> break;
>
> case 'P':
> {
> - struct spec_path_info info;
> + struct spec_path info;
>
> info.option = RUNPATH_OPTION;
> info.append_len = 0;
> @@ -6282,7 +6253,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
> /* We want to embed the actual paths that have the libraries. */
> info.realpaths = true;
>
> - for_each_path (&startfile_prefixes, true, 0, spec_path, &info);
> + for_each_path (&startfile_prefixes, true, 0, info);
> }
> break;
>
> @@ -6561,7 +6532,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
>
> case 'I':
> {
> - struct spec_path_info info;
> + struct spec_path info;
>
> if (multilib_dir)
> {
> @@ -6609,8 +6580,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
> info.separate_options = true;
> info.realpaths = false;
>
> - for_each_path (&include_prefixes, false, info.append_len,
> - spec_path, &info);
> + for_each_path (&include_prefixes, false, info.append_len, info);
>
> info.append = "include-fixed";
> if (*sysroot_hdrs_suffix_spec)
> @@ -6623,14 +6593,13 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
> info.append = concat (info.append, dir_separator_str,
> multiarch_dir, NULL);
> info.append_len = strlen (info.append);
> - for_each_path (&include_prefixes, false, info.append_len,
> - spec_path, &info);
> + for_each_path (&include_prefixes, false,
> + info.append_len, info);
>
> info.append = "include-fixed";
> }
> info.append_len = strlen (info.append);
> - for_each_path (&include_prefixes, false, info.append_len,
> - spec_path, &info);
> + for_each_path (&include_prefixes, false, info.append_len, info);
> }
> break;
>
> --
> cgit
More information about the Fortran
mailing list