Does `user/sh.c` violate the strict aliasing rules?
yuxqiu opened this issue · comments
The C standard Section 6.5 defines the strict aliasing rule as follows.
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the effective type of the object,
- a type that is the signed or unsigned type corresponding to the effective type of the object,
- a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
- an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
- a character type.
In user/sh.c
, all pointers to different types of commands are converted to struct cmd*
:
Lines 196 to 221 in f5b93ef
The returned pointer is then used to access the type
field:
Lines 71 to 130 in f5b93ef
At this point, it seems to me that this access (cmd->type
) violates the strict aliasing rules, since struct cmd*
and struct execcmd*
(for example) cannot be aliased:
struct cmd
is not compatible withstruct execcmd
.- Same as above.
struct cmd
is not a signed/unsigned type.- Same as above.
struct execcmd
does not contain any members whose types are compatible withstruct cmd
.struct cmd
is not a character type.
IMHO, the correct thing to do is to replace int type;
with struct cmd type;
. By doing so, we can then alias struct cmd*
and struct execcmd*
. CPython does the same (PEP 3123).
- In addition, this gives us more reassurance about pointer conversions (from
struct execcmd*
tostruct cmd*
). According to C standard 6.7.2.1, "A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning."
(Although this project is written in ANSI C, the C version is not specified as a compiler flag. Therefore, I assume it should follow the C17 standard as the version of gcc installed on my machine is 12.2.0, which uses -std=gnu17
.)