Skip to content

Define CAMLunreachable in GCC < 10#13331

Merged
gasche merged 1 commit intoocaml:trunkfrom
MisterDA:fix-gcc-9-unreachable-return
Jul 24, 2024
Merged

Define CAMLunreachable in GCC < 10#13331
gasche merged 1 commit intoocaml:trunkfrom
MisterDA:fix-gcc-9-unreachable-return

Conversation

@MisterDA
Copy link
Copy Markdown
Contributor

@MisterDA MisterDA commented Jul 24, 2024

This also reverts commit 034f273.

Tested in Ubuntu 20.04 with GCC 9 in a Docker image.

$ cd ocaml
$ git checkout XXX # this branch or trunk
$ docker run --pull=missing --rm -v .:/mnt gcc:9 sh -c \
    'cd /mnt && git clean -fdX && ./configure --disable-ocamldoc && make -j$(nproc) runtime/ocamlrun'

Reported by @nojb in #13242 (comment).
cc @gasche

Comment thread runtime/bigarray.c Outdated
@shindere
Copy link
Copy Markdown
Contributor

shindere commented Jul 24, 2024 via email

@gasche
Copy link
Copy Markdown
Member

gasche commented Jul 24, 2024

I would like to understand a bit more what is going on here:

  • there are many versions of CAMLunreachable depending on conditional tests, which one is gcc 9 using?
  • is the problem that this version always aborts, but gcc 9 does not notice this, or that this version sometimes does not abort?

@MisterDA MisterDA force-pushed the fix-gcc-9-unreachable-return branch from f50fbc6 to b782724 Compare July 24, 2024 09:15
@gasche
Copy link
Copy Markdown
Member

gasche commented Jul 24, 2024

I had a look myself:

  • the definition used for gcc 9 is CAMLassert(0), which indeed does not always abort the program (only in debug mode)
  • the reason why gcc 9 uses this definition is that it does not support __has_builtin, but it in fact has __builtin_trap available, it was introduced in gcc 4.3 released in march 2008.

@MisterDA
Copy link
Copy Markdown
Contributor Author

GCC 9 doesn't have __builtin_trap, so CAMLunreachable defaults to CAMLassert(0). The problem is that CAMLassert(0) defaults to an empty expression ((void)0) in the default runtime, which doesn't stop the program execution. GCC then errors because either the function ends without a return, or because some values are left uninitialized as the control flows continues out of the switch.
This PR returns to the default behavior before #13242 of using dummy return values in case the compiler doesn't support trap. One of the first iterations of #13242 used abort() in this case.

@MisterDA
Copy link
Copy Markdown
Contributor Author

the reason why gcc 9 uses this definition is that it does not support __has_builtin, but it in fact has __builtin_trap available, it was introduced in gcc 4.3 released in march 2008.

oh, missed that, thanks

@gasche
Copy link
Copy Markdown
Member

gasche commented Jul 24, 2024

This suggests the following:

  • the specific issue with gcc could be fixed by checking that (gcc >= 4.3), if we are not already assuming this, as an alternative to the __has_builtin(__builtin_trap) check
  • or we could check for __builtin_trap at configure-time, which is more portable
  • I wonder if there is an alternative fallback case that always interrupts evaluation. One way to do this would be to define CAMLunreachable1(x) instead of CAMLunreachable(), where x is (evaluated and) returned only in the fallback case. Maybe there exists a C-friendly way to do this without asking the user for a dummy value?

@MisterDA
Copy link
Copy Markdown
Contributor Author

We're already using __has_builtin(XXX) || defined(__GNUC__) in other places, I think that's the simplest.

GCC 10 introduced support for __has_builtin. GCC 9 needs a return in
all (switch) branches. GCC 4.3 introduced support for __builtin_trap.
As for other builtins, we need a fallback to use them with GCC < 10.
@gasche
Copy link
Copy Markdown
Member

gasche commented Jul 24, 2024

Yep, our configure requires (gcc >= 4.9), so it would suffice to check __GNUC__ to enable the __builtin_trap version, as an alternative to the __has_builtin check.

@MisterDA MisterDA force-pushed the fix-gcc-9-unreachable-return branch from b782724 to 26e1886 Compare July 24, 2024 09:27
@MisterDA MisterDA changed the title GCC 9 needs a return in all (switch) branches Define CAMLunreachable in GCC < 10 Jul 24, 2024
@gasche
Copy link
Copy Markdown
Member

gasche commented Jul 24, 2024

This looks good, do I correctly understand that you tested the new approach on gcc 9?

@gasche
Copy link
Copy Markdown
Member

gasche commented Jul 24, 2024

We may still have an issue with older compilers or compilers that do not have __builtin_trap(), where the current fallback definition is incorrect outside debug mode. Maybe the fallback should be abort() instead?

@gasche
Copy link
Copy Markdown
Member

gasche commented Jul 24, 2024

(Note: I'm fine with merging the PR as-is, which fixes the immediate issue with gcc 9, and letting you cook up a longer-term fix for the fallback case separately.)

@MisterDA
Copy link
Copy Markdown
Contributor Author

We may still have an issue with older compilers or compilers that do not have __builtin_trap(), where the current fallback definition is incorrect outside debug mode. Maybe the fallback should be abort() instead?

From LLVM llvm.trap Intrinsic docs:

This intrinsic is lowered to the target dependent trap instruction. If the target does not have a trap instruction, this intrinsic will be lowered to a call of the abort() function.

Older compilers are less of a problem because they tend not to support C11 atomics. For compilers not supporting __builtin_trap() I'm also in favor of using abort().

@gasche gasche merged commit 7c79323 into ocaml:trunk Jul 24, 2024
@gasche
Copy link
Copy Markdown
Member

gasche commented Jul 24, 2024

I merged the current PR because it is well-scoped, and presumably this will make @nojb's life easier.

I would be interested in experiments with abort() instead of CAMLassert(0) for the fallback. (I am also curious to know about how it is when you actually run this code in practice: CAMLassert shows line numbers for example, does abort() also do this in practice? Or maybe we should use assert(0); abort(); to get the best of both words, even in the non-debug runtime?)

@MisterDA MisterDA deleted the fix-gcc-9-unreachable-return branch July 24, 2024 11:47
@nojb
Copy link
Copy Markdown
Contributor

nojb commented Jul 25, 2024

I merged the current PR because it is well-scoped, and presumably this will make @nojb's life easier.

Thanks!

@nojb
Copy link
Copy Markdown
Contributor

nojb commented Jul 25, 2024

I merged the current PR because it is well-scoped, and presumably this will make @nojb's life easier.

Thanks!

(and I confirm that OCaml is again buildable on Ubuntu 20.04)

gasche added a commit to gasche/ocaml that referenced this pull request Jul 30, 2024
gasche added a commit to gasche/ocaml that referenced this pull request Sep 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants