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*:
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 execcmd does not contain any members whose types are compatible with struct 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* to struct 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.)
The C standard Section 6.5 defines the strict aliasing rule as follows.
In
user/sh.c
, all pointers to different types of commands are converted tostruct cmd*
:https://github.com/mit-pdos/xv6-riscv/blob/f5b93ef12f7159f74f80f94729ee4faabe42c360/user/sh.c#L196-L221
The returned pointer is then used to access the
type
field:https://github.com/mit-pdos/xv6-riscv/blob/f5b93ef12f7159f74f80f94729ee4faabe42c360/user/sh.c#L71-L130
At this point, it seems to me that this access (
cmd->type
) violates the strict aliasing rules, sincestruct cmd*
andstruct execcmd*
(for example) cannot be aliased:struct cmd
is not compatible withstruct execcmd
.struct cmd
is not a signed/unsigned type.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;
withstruct cmd type;
. By doing so, we can then aliasstruct cmd*
andstruct execcmd*
. CPython does the same (PEP 3123).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
.)