Home > Back-end >  Strange behavior about WEXITSTATUS with `G 4.9.4`
Strange behavior about WEXITSTATUS with `G 4.9.4`

Time:05-26

This code snippet below does compiles,

#include<sys/types.h>
#include<sys/wait.h>
#include<iostream>

int main()
{
    int ret = 0xFFFF;
    std::cout << WEXITSTATUS(ret);
}

whereas this code snippet does not compile indeed with G 4.9.4:

#include<sys/types.h>
#include<sys/wait.h>
#include<iostream>

int main()
{
     std::cout << WEXITSTATUS(0xFFFF);
}

Here is what the compiler complains:

In file included from /usr/include/x86_64-linux-gnu/sys/wait.h:77:0,
                 from t.cpp:2:
t.cpp: In function ‘int main()’:
t.cpp:7:22: error: lvalue required as unary ‘&’ operand
         std::cout << WEXITSTATUS(0xFFFF);
                      ^

Here is the detail info about the compiler:

g   --version
g   (Ubuntu 4.9.4-2ubuntu1~16.04) 4.9.4
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

And the compiler is installed on Ubuntu16.04 by the commands below

sudo apt-get install gcc-4.9
sudo apt-get install g  -4.9
sudo update-alterntives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 20
sudo update-alterntives --install /usr/bin/g   g   /usr/bin/g  -4.9 20

Note: I have to use g -4.9, I have no other choice.

And It's strange that I could not reproduce the said phenomenon on godbolt.org. It compiles on godbolt.org with gcc 4.9.3(gcc 4.9.4 is not available).

Here is the output of g -E the_said_code_snippet_does_not_compile.cpp

//omit
# 4 "t.cpp" 2

int main()
{
        std::cout << ((((*(const int *) &(0xFFFF))) & 0xff00) >> 8);
}

Could anybody shed some light on this matter?

UPDATED:

I can reproduce the error now!See this link.

UPDATED:

It's just a simplified example. What am I actually face is WEXITSTATUS(pclose(fp)) does not compile.

CodePudding user response:

The WEXITSTATUS macro is a matter of the C standard library implementation, not the compiler per se. Typically (and in the case of GCC) the compiler doesn't supply the C standard library implementation. It is an independent package.

Most Linux distributions, including Ubuntu, use glibc as C standard library implementation.

In glibc until version 2.23, inclusive, the macro was defined in the following way when using C and __USE_MISC is set (see commit link below):

#   define __WAIT_INT(status)   (*(const int *) &(status))

// ...

# define WEXITSTATUS(status)    __WEXITSTATUS (__WAIT_INT (status))

The actual implementation of the macro is inside __WEXITSTATUS, but the use of __WAIT_INT seems to be for the purpose of supporting the non-POSIX "union wait" variant of the wait interface. With this definition, a prvalue cannot be used with the macro, because it tries to take the address of status.

In 2016, with commit b49ab5f4503f36dcbf43f821f817da66b2931fe6 support for union wait - according to the NEWS entry deprecated in the early 1990s - has been removed and now the definition is simply

# define WEXITSTATUS(status)    __WEXITSTATUS (status)

Now it would work with a prvalue as well.

It seems that Ubuntu 16.04 still uses a glibc version from before that change, which isn't surprising since it was released at the time of the commit.

I don't know what POSIX has to say about whether or not it should be possible to use the macro with a int rvalue rather than the name of a variable.

That WEXITSTATUS can't always be used directly on a call to pclose seems to be known issue. Apparently the above-mentioned extension, which is now not present in glibc anymore, was (is?) also present in (some?) BSDs (and may originate from them?). See e.g. this question, in which the answer also expresses doubts about POSIX-compliance. However, OpenBSD, mentioned in the linked question, also removed union wait in 2014. According to the changelog it had been deprecated since 4.3BSD (released 1986).

CodePudding user response:

That looks like an oddball implementation of macro, causing problems with operator precedence. Usually it should be something like this:

#define     WEXITSTATUS(status)        (((status) & 0xff00) >> 8)

now if it is (and completely wrong as result)

#define     WEXITSTATUS(status)        status & 0xff00 >> 8

You wold get following order:

( std::cout << status ) & (0xff00 >> 8)

Though I can't imagine that such broken implementation could exist?

The processed code snippet shows that macro assumes status to be an expression returning at least a prvalue, something one can get address of and "magic" of casting it to const int.

#define     WEXITSTATUS(status)        ((((*(const int *) &(status))) & 0xff00) >> 8)

The error happens from address operator getting a wrong operand. Essentially this macro cannot work with a constant only with expression or variable, assuming that those are values returned from particular source described in documentation.

  • Related