Merge pull request #1213 from xexyl/1986-marshall-compilers

This commit is contained in:
Landon Curt Noll authored and GitHub committed 2023-10-29 09:59:07 -07:00
commit 6b9e8da9c3
2 files changed
+115 -86

No files matched your search

+22 -86
View File
@@ -8,13 +8,13 @@ Eric Marshall
make all
```
There is an alternate version. See the [Alternate code](#alternate-code) section
for the commentary on why this is: there was a funny problem in modern systems
where depending on the compiler and the optimiser it would work with one
compiler with the optimiser but it would not work with the other; and if the
optimiser state is changed the previous problematic compiler might work but the
other one would not. We describe this in more detail below and we encourage you
to read it for entertainment if nothing else.
There is an [alternate version](#alternate-code). The reason is a funny problem:
in modern systems, depending on the platform, compiler and the optimiser, it
would work with one compiler with the optimiser but it would not work with the
other; and if the optimiser state is changed the previous problematic compiler
might work but the other one would not. We describe this in more detail in
[compilers.md](compilers.md) and we encourage you to read it for entertainment
if nothing else.
## Try:
@@ -25,93 +25,29 @@ to read it for entertainment if nothing else.
## Alternate code:
As some changes had to be made due to the problem of conflicting compiler
options briefly noted above we provide the code that demonstrates the problem so
you can see if your compiler has the problem as described below.
Due to the different [conflicting problems](compilers.md) with gcc and clang, we
instead offer the problematic code as an alternate version whereas
[marshall.c](marshall.c) has both the infinite loop and the complicated arg to
`_exit()` commented out, changing the value passed into `_exit()` to `1`.
In some versions of gcc and clang (this was first discovered in fedora linux 38)
if the compiler was enabled one compiler would generate code that segfaulted but
the other one would not. However, when then disabling the optimiser the compiler
that had no problem suddenly did and the one that did suddenly did not.
### Alternate build:
Another problem was that depending on the optimiser an infinite loop would be
entered.
To see if your compiler has the problems noted:
The alternate code has the original fix for clang which works with some
compilers depending on the optimiser. When we refer to the code below we refer
to the alternate code.
#### The conflicting compiler problems:
Below we describe the conflicting options that resulted in the need to modify
the original code.
##### Linux
With the optimiser disabled GCC compiled the code to enter an infinite loop.
Enabling the optimiser and it worked fine. But if the optimiser is enabled clang
generates code that first prints the text twice (it should print it once) and
then immediately dumps core!
But then there's that infinite loop. What happens if we remove it?
Once the loop is removed if we compile with clang and the optimiser is disabled
all is okay. If however we compile with gcc and the optimiser is disabled the
string is printed once and then the program dumps core! Why is this? It is
because of the call to `_exit()` (see below). Clang works fine with the loop
removed and the optimiser disabled. If however we enable the optimiser clang
will generate code that prints the string twice and dumps core just like before!
What about the call to `_exit()`?
The call was:
```c
_exit(argv[(int)*argc-2/cc[1*(int)*argc]|-1<<4]);
```
Changing it to not refer to these variables and just exit 1 and the problems
disappear!
##### macOS
But as noted just because it works one way in linux does not mean it works the
same way in macOS.
If the infinite loop is not removed/commented out and the optimiser is enabled
it works fine but if it's disabled it prints out the string and then enters an
infinite loop.
After we fix the infinite loop if we change the `_exit()` call in macOS and
disable the optimiser we might get something like:
```sh
$ ./marshall
choo choo
Segmentation fault: 11
```
Observe how it doesn't print it twice. But of course it segfaults so it's not
right either.
If the optimiser is enabled, however, we will see that it works fine before the
change to `_exit()`.
### Alternate use:
Due to the different conflicting problems with gcc and clang, we instead offer
the problematic code as an alternate version whereas [marshall.c](marshall.c)
has both the infinite loop and the complicated arg to `_exit()` commented out,
changing the value passed into `_exit()` to `1`.
To try out the alternate version:
```sh
make alt
```
Use `marshall.alt` as you would `marshall` above.
### Alternate run:
```sh
./marshall.alt
```
Does it work in your system? That is does it not segfault, does it print it only
once and does it not enter an infinite loop? Or more generally does it print the
text exactly once and then exit?
## Judges' remarks:
+93
View File
@@ -0,0 +1,93 @@
# Conflicting compilers and optimisers that broke this entry in 2023
As briefly noted in the [README.md](README.md) gcc and clang caused different
problems with this entry depending on the optimiser being enabled or not, where
if the optimiser was enabled it would work with one compiler and not the other.
But if you then disabled the optimiser the opposite problem would occur: the
working compiler would no longer work and the non-functional one would start to
work! And then there's the problem of linux versus macOS causing problems.
The [alternate code](marshall.alt.c) (source code) demonstrates the problem so
you can see if your compiler has the problem as described below.
In some versions of gcc and clang (this was first discovered in fedora linux 38)
if the compiler was enabled one compiler would generate code that segfaulted but
the other one would not. However, when then disabling the optimiser the compiler
that had no problem suddenly did and the one that did suddenly did not. But
segfaulting was not by any means the only problem.
Another problem was that depending on the optimiser an infinite loop would be
entered. But then removing it would cause other problems as well, including a
segfault.
It was not only one compiler that dumped core. Both dumped core with other
behaviour, depending on what changes in code were made and the optimiser being
on or off. Clang in macOS also dumped core!
The [alternate code](README.md#alternate-code) (README.md) has the original fix
for clang which works with some compilers depending on the optimiser. When we
refer to the code below we refer to the alternate code.
## The conflicting compiler problems:
Below we describe the conflicting options that resulted in the need to modify
the original code.
### Linux
With the optimiser disabled GCC compiled the code to enter an infinite loop.
Enabling the optimiser and it worked fine. But if the optimiser is enabled clang
generates code that first prints the text twice (it should print it once) and
then immediately dumps core!
But then there's that infinite loop. What happens if we remove it?
Once the loop is removed if we compile with clang and the optimiser is disabled
all is okay. If however we compile with gcc and the optimiser is disabled the
string is printed once and then the program dumps core! Why is this? It is
because of the call to `_exit()` (see below).
Clang works fine with the loop removed and the optimiser disabled. If however we
enable the optimiser clang will generate code that prints the string twice and
dumps core just like before! What about the call to `_exit()`?
The call was:
```c
_exit(argv[(int)*argc-2/cc[1*(int)*argc]|-1<<4]);
```
Changing it to not refer to these variables and just exit 1 and the problems
disappear!
### macOS
But then there was macOS which had another problem!
If the infinite loop is not removed/commented out and the optimiser is enabled
it works fine but if it's disabled it prints out the string and then enters an
infinite loop!
After we fix the infinite loop if we change the `_exit()` call in macOS and
disable the optimiser we might get something like:
```sh
$ ./marshall
choo choo
Segmentation fault: 11
```
Observe how it doesn't print it twice. But of course it segfaults so it's not
right either.
If the optimiser is enabled, however, we will see that it works fine before the
change to `_exit()`.
## Summary
And that is the tale of a little <strike>engine</strike> train that
could...eventually! Or perhaps it's the compilers, optimisers and OSes that
eventually could?
Whichever you wish it to be, it now works with both clang and gcc! Choo choo!