Skip to content

Reland "[flang] Avoid undefined behaviour when parsing format expressions (#147539)" #148169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 14, 2025

Conversation

DavidSpickett
Copy link
Collaborator

This reverts commit e8e5d07.

This previously failed because the flang-rt build could not find the
llvm header file. It passed on some machines but only because they
had globally installed copies of older llvm.

To fix this, I've copied the required routines from llvm into flang.

With the following justification:

  • Flang can, and does, use llvm headers.
  • Some Flang headers are also used in Flang-rt.
  • Flang-rt cannot use llvm headers.
  • Therefore any Flang header using in Flang-rt cannot use llvm headers either.

To support that conclusion, https://flang.llvm.org/docs/IORuntimeInternals.html
states:
"The Fortran I/O runtime support library is written in C++17, and uses some C++17 standard library facilities, but it is intended to not have any link-time dependences on the C++ runtime support library or any LLVM libraries."

This talks about libraries but I assume it applies to llvm in general.

Nothing in flang/include/flang/Common, or flang/include/flang/Common
includes any llvm header, and I see some very similar headers there
that duplicate llvm functionality. Like float128.h.

I can only assume this means these files must remain free of dependencies
on LLVM.

I have copied the two routines literally and put them in the flang::common
namespace, for lack of a better place for them. So they don't clash with something.

I have specialised the function to the 1 type flang needs, as it might
save a bit of compile time.

…ions (llvm#147539)"

This reverts commit e8e5d07.

This previously failed because the flang-rt build could not find the
llvm header file. It passed on some machines but only because they
had globally installed copies of older llvm.

To fix this, I've copied the required routines from llvm into flang.

With the following justification:
* Flang can, and does, use llvm headers.
* Some Flang headers are also used in Flang-rt.
* Flang-rt cannot use llvm headers.
* Therefore any Flang header using in Flang-rt cannot use llvm headers either.

To support that conclusion, https://flang.llvm.org/docs/IORuntimeInternals.html
states:
"The Fortran I/O runtime support library is written in C++17, and uses some C++17 standard library facilities, but it is intended to not have any link-time dependences on the C++ runtime support library or any LLVM libraries."

This talks about libraries but I assume it applies to llvm in general.

Nothing in flang/include/flang/Common, or flang/include/flang/Common
includes any llvm header, and I see some very similar headers there
that duplicate llvm functionality. Like float128.h.

I can only assume this means these files must remain free of dependencies
on LLVM.

I have copied the two routines literally and put them in the flang::common
namespace, for lack of a better place for them. So they don't clash with something.

I have specialised the function to the 1 type flang needs, as it might
save a bit of compile time.
@llvmbot llvmbot added the flang Flang issues not falling into any other category label Jul 11, 2025
@DavidSpickett
Copy link
Collaborator Author

The template sepcialisation is in its own commit in case it's easier to check that way.

@tblah
Copy link
Contributor

tblah commented Jul 11, 2025

The intention of the rule is to allow people to run fortran programs on systems that do not have C++ standard libraries installed. A header-only dependency on these LLVM functions should be okay because they don't call anything else. Similarly, header-only dependencies on libc++ are okay (like the use of std::numeric_limits here) because that won't create a runtime dependency between flang-rt and the c++ library.

But now that you mention it, I agree this is a less brittle approach so that we don't accidentally end up with runtime dependencies on libc++ because of a change in an llvm header.

However, currently I am getting "multiple definitions of Fortran::common::AddOverflow" when linking flang-rt with your change. I am linking using /usr/bin/ld, building with gcc, and -DBUILD_SHARED_LIBS=ON. My build did succeed with clang, lld and no shared libs.

Copy link

github-actions bot commented Jul 11, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@DavidSpickett
Copy link
Collaborator Author

@tblah try it again, I think the static I added should fix it. It's that or make them members of the using class, which isn't an awful idea either but harder to find later.

Did not fail in my local build but I see why it could, pure chance that it doesn't I expect.

Copy link
Contributor

@tblah tblah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me, and I have verified that this doesn't lead to fortran executables having new runtime dependencies. Thanks for sticking with this patch.

@DavidSpickett
Copy link
Collaborator Author

Thanks, I'll land this Monday when I am here to catch any fallout.

Works for me, and I have verified that this doesn't lead to fortran executables having new runtime dependencies.

Is this something the build checks? Idk if you can just look at what flang-rt links to, or whether you have to link a fortran program and look at that. If it's not documented how to check that, it would be nice to have written down.

@tblah
Copy link
Contributor

tblah commented Jul 11, 2025

I'm not sure how to check what a static library links to. If it is dynamic you can use ldd. For static libraries I build a Fortran program and see what it links to. I don't want to document that because I wonder if some of the dependencies could get removed from parts of the runtime not being used in that program - it might not be entirely robust.

I dimly remember there being a bot somewhere that kept an eye on these dependencies for flang-rt but whenever I heard about it was a long time ago.

Edit: maybe it would be more robust to objdump the static library and scan for symbols mangled to look like they come from libc++

@DavidSpickett DavidSpickett merged commit 29d8c34 into llvm:main Jul 14, 2025
7 of 9 checks passed
@DavidSpickett DavidSpickett deleted the flang-reland branch July 14, 2025 09:14
@clementval
Copy link
Contributor

This breaks building the flang runtime for the device with the following error:

In file included from /proj/build/llvm/Linux_x86_64-rt/flang-rt/include/flang-rt/runtime/format-implementation.h:18,
                 from /proj/build/llvm/Linux_x86_64-rt/flang-rt/lib/runtime/format.cpp:9:
/proj/build/llvm/Linux_x86_64-rt/flang-rt/../flang/include/flang/Common/format.h:38:18: error: missing binary operator before token "("
   38 | #if __has_builtin(__builtin_add_overflow)
      |                  ^
/proj/build/llvm/Linux_x86_64-rt/flang-rt/../flang/include/flang/Common/format.h:64:18: error: missing binary operator before token "("
   64 | #if __has_builtin(__builtin_mul_overflow)
      |                  ^

Also the flang runtime codebase uses brace initialization.

@clementval
Copy link
Contributor

#148746

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants