diff mbox series

[XEN,10/11] xen/sched: add ASSERT_UNREACHABLE() to address MISRA C:2012 Rule 2.1

Message ID 3f1385f2ddb151a53ca092ea1caeac5d12fd80f5.1690985045.git.nicola.vetrini@bugseng.com (mailing list archive)
State New, archived
Headers show
Series xen: address MISRA C:2012 Rule 2.1 | expand

Commit Message

Nicola Vetrini Aug. 2, 2023, 2:38 p.m. UTC
The break statement after the return statement is definitely unreachable.
As such, an call to the ASSERT_UNREACHABLE() macro is added to signal
the intentionality of such construct.

Signed-off-by: Nicola Vetrini <nicola.vetrini@bugseng.com>
---
The break in the clause is mandated by Required Rule 16.3, which is
not yet an accepted rule for Xen, but may be in the future.
---
 xen/common/sched/core.c | 1 +
 1 file changed, 1 insertion(+)

Comments

Jan Beulich Aug. 3, 2023, 9:17 a.m. UTC | #1
On 02.08.2023 16:38, Nicola Vetrini wrote:
> --- a/xen/common/sched/core.c
> +++ b/xen/common/sched/core.c
> @@ -2233,6 +2233,7 @@ static bool sched_tasklet_check_cpu(unsigned int cpu)
>          /* fallthrough */
>      case TASKLET_enqueued|TASKLET_scheduled:
>          return true;
> +        ASSERT_UNREACHABLE();
>          break;

What use is "break" after "return"? IOW rather than adding code here,
imo a line wants removing.

Jan
Nicola Vetrini Aug. 7, 2023, 8:13 a.m. UTC | #2
On 03/08/2023 11:17, Jan Beulich wrote:
> On 02.08.2023 16:38, Nicola Vetrini wrote:
>> --- a/xen/common/sched/core.c
>> +++ b/xen/common/sched/core.c
>> @@ -2233,6 +2233,7 @@ static bool sched_tasklet_check_cpu(unsigned int 
>> cpu)
>>          /* fallthrough */
>>      case TASKLET_enqueued|TASKLET_scheduled:
>>          return true;
>> +        ASSERT_UNREACHABLE();
>>          break;
> 
> What use is "break" after "return"? IOW rather than adding code here,
> imo a line wants removing.
> 
> Jan

The "return false" after the switch would still be unreachable. The 
reasoning behind preserving the break
is mainly MISRA Rule 16.3: "An unconditional break statement shall 
terminate every switch-clause", which has
not yet been considered for adoption, but might be in future 
discussions, leading to putting back the break here.
Jan Beulich Aug. 7, 2023, 8:50 a.m. UTC | #3
On 07.08.2023 10:13, Nicola Vetrini wrote:
> On 03/08/2023 11:17, Jan Beulich wrote:
>> On 02.08.2023 16:38, Nicola Vetrini wrote:
>>> --- a/xen/common/sched/core.c
>>> +++ b/xen/common/sched/core.c
>>> @@ -2233,6 +2233,7 @@ static bool sched_tasklet_check_cpu(unsigned int 
>>> cpu)
>>>          /* fallthrough */
>>>      case TASKLET_enqueued|TASKLET_scheduled:
>>>          return true;
>>> +        ASSERT_UNREACHABLE();
>>>          break;
>>
>> What use is "break" after "return"? IOW rather than adding code here,
>> imo a line wants removing.
> 
> The "return false" after the switch would still be unreachable. The 
> reasoning behind preserving the break
> is mainly MISRA Rule 16.3: "An unconditional break statement shall 
> terminate every switch-clause", which has
> not yet been considered for adoption, but might be in future 
> discussions, leading to putting back the break here.

Well, adding such bogus "break"s is going to face my opposition, and
it is in direct conflict with the "no unreachable code" rule here.

Jan
Julien Grall Aug. 8, 2023, 3:25 p.m. UTC | #4
Hi,

On 02/08/2023 15:38, Nicola Vetrini wrote:
> The break statement after the return statement is definitely unreachable.
> As such, an call to the ASSERT_UNREACHABLE() macro is added to signal
> the intentionality of such construct.

How about using unreachable() rather than ASSERT_UNREACHABLE()? The main 
difference is the later will hint the compiler that the code cannot be 
reached and will not crash Xen in debug build (this could be changed).

> 
> Signed-off-by: Nicola Vetrini <nicola.vetrini@bugseng.com>
> ---
> The break in the clause is mandated by Required Rule 16.3, which is
> not yet an accepted rule for Xen, but may be in the future.
> ---
>   xen/common/sched/core.c | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c
> index 022f548652..fcee902b4e 100644
> --- a/xen/common/sched/core.c
> +++ b/xen/common/sched/core.c
> @@ -2233,6 +2233,7 @@ static bool sched_tasklet_check_cpu(unsigned int cpu)
>           /* fallthrough */
>       case TASKLET_enqueued|TASKLET_scheduled:
>           return true;
> +        ASSERT_UNREACHABLE();
>           break;
>       case TASKLET_scheduled:
>           clear_bit(_TASKLET_scheduled, tasklet_work);

Cheers,
Jan Beulich Aug. 8, 2023, 3:36 p.m. UTC | #5
On 08.08.2023 17:25, Julien Grall wrote:
> On 02/08/2023 15:38, Nicola Vetrini wrote:
>> The break statement after the return statement is definitely unreachable.
>> As such, an call to the ASSERT_UNREACHABLE() macro is added to signal
>> the intentionality of such construct.
> 
> How about using unreachable() rather than ASSERT_UNREACHABLE()? The main 
> difference is the later will hint the compiler that the code cannot be 
> reached and will not crash Xen in debug build (this could be changed).

Isn't using unreachable() in place of ASSERT_UNREACHABLE() unsafe (not
here but in general)? It'll tell the compiler that (in the extreme case)
it can omit the function epilogue, including the return instruction. In
the resulting build, if the code turns out to be reachable, execution
would fall through into whatever follows.

In the case here ...

>> --- a/xen/common/sched/core.c
>> +++ b/xen/common/sched/core.c
>> @@ -2233,6 +2233,7 @@ static bool sched_tasklet_check_cpu(unsigned int cpu)
>>           /* fallthrough */
>>       case TASKLET_enqueued|TASKLET_scheduled:
>>           return true;
>> +        ASSERT_UNREACHABLE();
>>           break;
>>       case TASKLET_scheduled:
>>           clear_bit(_TASKLET_scheduled, tasklet_work);

... "return" alone already tells the compiler that "break" is
unreachable. You don't need unreachable() for that. As said before,
"break" like this simply want purging (and Misra is wrong to demand
"break" everywhere - it should instead demand no [unannotated]
fall-through, which can also be achieved by return, continue, and
goto).

Jan
Julien Grall Aug. 8, 2023, 3:44 p.m. UTC | #6
Hi,

On 08/08/2023 16:36, Jan Beulich wrote:
> On 08.08.2023 17:25, Julien Grall wrote:
>> On 02/08/2023 15:38, Nicola Vetrini wrote:
>>> The break statement after the return statement is definitely unreachable.
>>> As such, an call to the ASSERT_UNREACHABLE() macro is added to signal
>>> the intentionality of such construct.
>>
>> How about using unreachable() rather than ASSERT_UNREACHABLE()? The main
>> difference is the later will hint the compiler that the code cannot be
>> reached and will not crash Xen in debug build (this could be changed).
> 
> Isn't using unreachable() in place of ASSERT_UNREACHABLE() unsafe (not
> here but in general)?

Yes it is.

  It'll tell the compiler that (in the extreme case)
> it can omit the function epilogue, including the return instruction. In
> the resulting build, if the code turns out to be reachable, execution
> would fall through into whatever follows.

Right, but the problem is somewhat similar with adding 
ASSERT_UNREACHABLE() without proper error path because there is no 
guarantee the rest of the code will be correct in the unlikely case it 
is reachable.

> 
> In the case here ...
> 
>>> --- a/xen/common/sched/core.c
>>> +++ b/xen/common/sched/core.c
>>> @@ -2233,6 +2233,7 @@ static bool sched_tasklet_check_cpu(unsigned int cpu)
>>>            /* fallthrough */
>>>        case TASKLET_enqueued|TASKLET_scheduled:
>>>            return true;
>>> +        ASSERT_UNREACHABLE();
>>>            break;
>>>        case TASKLET_scheduled:
>>>            clear_bit(_TASKLET_scheduled, tasklet_work);
> 
> ... "return" alone already tells the compiler that "break" is
> unreachable. You don't need unreachable() for that. As said before,
> "break" like this simply want purging (and Misra is wrong to demand
> "break" everywhere - it should instead demand no [unannotated]
> fall-through, which can also be achieved by return, continue, and
> goto).

My suggestion was in the context of this series where we add 
ASSERT_UNREACHABLE() before break. From my understanding, we don't have 
a lot of leeway here because, from what Nicola wrote, rule 16.3 is 
mandatory.

So I think using unreachable is better if we every decide to use break 
after return.

Cheers,
Nicola Vetrini Aug. 8, 2023, 3:53 p.m. UTC | #7
>> 
>> ... "return" alone already tells the compiler that "break" is
>> unreachable. You don't need unreachable() for that. As said before,
>> "break" like this simply want purging (and Misra is wrong to demand
>> "break" everywhere - it should instead demand no [unannotated]
>> fall-through, which can also be achieved by return, continue, and
>> goto).
> 
> My suggestion was in the context of this series where we add
> ASSERT_UNREACHABLE() before break. From my understanding, we don't
> have a lot of leeway here because, from what Nicola wrote, rule 16.3
> is mandatory.
> 
> So I think using unreachable is better if we every decide to use break
> after return.
> 
> Cheers,

16.3 is not Mandatory, just Required. I was just reluctant to knowingly 
add one more violation
while fixing another before submitting the patch. If indeed 16.3 won't 
likely be adopted by Xen,
then that break should indeed go away.

However, the main thing that's holding me back from doing a slimmed-down 
v2 here is that
evidently there's no consensus even on the ASSERT_UNREACHABLE() patches.
Julien Grall Aug. 8, 2023, 3:57 p.m. UTC | #8
On 08/08/2023 16:53, Nicola Vetrini wrote:
> 
>>>
>>> ... "return" alone already tells the compiler that "break" is
>>> unreachable. You don't need unreachable() for that. As said before,
>>> "break" like this simply want purging (and Misra is wrong to demand
>>> "break" everywhere - it should instead demand no [unannotated]
>>> fall-through, which can also be achieved by return, continue, and
>>> goto).
>>
>> My suggestion was in the context of this series where we add
>> ASSERT_UNREACHABLE() before break. From my understanding, we don't
>> have a lot of leeway here because, from what Nicola wrote, rule 16.3
>> is mandatory.
>>
>> So I think using unreachable is better if we every decide to use break
>> after return.
>>
>> Cheers,
> 
> 16.3 is not Mandatory, just Required.

Ah I misread what you wrote. In that case...

> I was just reluctant to knowingly 
> add one more violation
> while fixing another before submitting the patch. If indeed 16.3 won't 
> likely be adopted by Xen,
> then that break should indeed go away.
> 
> However, the main thing that's holding me back from doing a slimmed-down 
> v2 here is that
> evidently there's no consensus even on the ASSERT_UNREACHABLE() patches.

... I agree with the following statement from Jan:

"it should instead demand no [unannotated] fall-through, which can also 
be achieved by return, continue, and goto"

Cheers,
Stefano Stabellini Aug. 8, 2023, 9:14 p.m. UTC | #9
On Tue, 8 Aug 2023, Julien Grall wrote:
> On 08/08/2023 16:53, Nicola Vetrini wrote:
> > > > ... "return" alone already tells the compiler that "break" is
> > > > unreachable. You don't need unreachable() for that. As said before,
> > > > "break" like this simply want purging (and Misra is wrong to demand
> > > > "break" everywhere - it should instead demand no [unannotated]
> > > > fall-through, which can also be achieved by return, continue, and
> > > > goto).
> > > 
> > > My suggestion was in the context of this series where we add
> > > ASSERT_UNREACHABLE() before break. From my understanding, we don't
> > > have a lot of leeway here because, from what Nicola wrote, rule 16.3
> > > is mandatory.
> > > 
> > > So I think using unreachable is better if we every decide to use break
> > > after return.
> > > 
> > > Cheers,
> > 
> > 16.3 is not Mandatory, just Required.
> 
> Ah I misread what you wrote. In that case...
> 
> > I was just reluctant to knowingly add one more violation
> > while fixing another before submitting the patch. If indeed 16.3 won't
> > likely be adopted by Xen,
> > then that break should indeed go away.
> > 
> > However, the main thing that's holding me back from doing a slimmed-down v2
> > here is that
> > evidently there's no consensus even on the ASSERT_UNREACHABLE() patches.
> 
> ... I agree with the following statement from Jan:
> 
> "it should instead demand no [unannotated] fall-through, which can also be
> achieved by return, continue, and goto"

I also think it is a better idea to have no unannotated fall-through in
switch statements (unless we have a "case" with nothing underneath, so
two cases next to each other). In other words the following are all OK
in my view:

  case A:
    do();
    break;
  case B:
    do();
    return true;
  case Ca:
  case Cb:
    goto fail;
  case D:
    i++;
    continue;
  case E:
    do();
    /* fall-through */
  case F:
    do();
    break;

While the following is not OK:

  case A:
    do();
  case B:
    do();

This should be what we already do in Xen, although it is not documented
properly. Jan, Julien do you agree?

If so, could Eclair be configured to check for this pattern (or
similar)?

We must have one of the following:
- break, continue, return, goto
- /* fall-through */
- empty case body (case Ca/Cb)
Jan Beulich Aug. 9, 2023, 6:01 a.m. UTC | #10
On 08.08.2023 23:14, Stefano Stabellini wrote:
> On Tue, 8 Aug 2023, Julien Grall wrote:
>> On 08/08/2023 16:53, Nicola Vetrini wrote:
>>>>> ... "return" alone already tells the compiler that "break" is
>>>>> unreachable. You don't need unreachable() for that. As said before,
>>>>> "break" like this simply want purging (and Misra is wrong to demand
>>>>> "break" everywhere - it should instead demand no [unannotated]
>>>>> fall-through, which can also be achieved by return, continue, and
>>>>> goto).
>>>>
>>>> My suggestion was in the context of this series where we add
>>>> ASSERT_UNREACHABLE() before break. From my understanding, we don't
>>>> have a lot of leeway here because, from what Nicola wrote, rule 16.3
>>>> is mandatory.
>>>>
>>>> So I think using unreachable is better if we every decide to use break
>>>> after return.
>>>>
>>>> Cheers,
>>>
>>> 16.3 is not Mandatory, just Required.
>>
>> Ah I misread what you wrote. In that case...
>>
>>> I was just reluctant to knowingly add one more violation
>>> while fixing another before submitting the patch. If indeed 16.3 won't
>>> likely be adopted by Xen,
>>> then that break should indeed go away.
>>>
>>> However, the main thing that's holding me back from doing a slimmed-down v2
>>> here is that
>>> evidently there's no consensus even on the ASSERT_UNREACHABLE() patches.
>>
>> ... I agree with the following statement from Jan:
>>
>> "it should instead demand no [unannotated] fall-through, which can also be
>> achieved by return, continue, and goto"
> 
> I also think it is a better idea to have no unannotated fall-through in
> switch statements (unless we have a "case" with nothing underneath, so
> two cases next to each other). In other words the following are all OK
> in my view:
> 
>   case A:
>     do();
>     break;
>   case B:
>     do();
>     return true;
>   case Ca:
>   case Cb:
>     goto fail;
>   case D:
>     i++;
>     continue;
>   case E:
>     do();
>     /* fall-through */
>   case F:
>     do();
>     break;
> 
> While the following is not OK:
> 
>   case A:
>     do();
>   case B:
>     do();
> 
> This should be what we already do in Xen, although it is not documented
> properly. Jan, Julien do you agree?

Yes.

> If so, could Eclair be configured to check for this pattern (or
> similar)?
> 
> We must have one of the following:
> - break, continue, return, goto
> - /* fall-through */

- fallthrough;

(the pseudo keyword that we have; see compiler.h for actually having the
documentation you're looking for, albeit missing "continue", and of
course not really expected to live [just] there)

Jan

> - empty case body (case Ca/Cb)
Julien Grall Aug. 11, 2023, 6:41 p.m. UTC | #11
Hi Stefano,

On 08/08/2023 22:14, Stefano Stabellini wrote:
> On Tue, 8 Aug 2023, Julien Grall wrote:
>> On 08/08/2023 16:53, Nicola Vetrini wrote:
>>>>> ... "return" alone already tells the compiler that "break" is
>>>>> unreachable. You don't need unreachable() for that. As said before,
>>>>> "break" like this simply want purging (and Misra is wrong to demand
>>>>> "break" everywhere - it should instead demand no [unannotated]
>>>>> fall-through, which can also be achieved by return, continue, and
>>>>> goto).
>>>>
>>>> My suggestion was in the context of this series where we add
>>>> ASSERT_UNREACHABLE() before break. From my understanding, we don't
>>>> have a lot of leeway here because, from what Nicola wrote, rule 16.3
>>>> is mandatory.
>>>>
>>>> So I think using unreachable is better if we every decide to use break
>>>> after return.
>>>>
>>>> Cheers,
>>>
>>> 16.3 is not Mandatory, just Required.
>>
>> Ah I misread what you wrote. In that case...
>>
>>> I was just reluctant to knowingly add one more violation
>>> while fixing another before submitting the patch. If indeed 16.3 won't
>>> likely be adopted by Xen,
>>> then that break should indeed go away.
>>>
>>> However, the main thing that's holding me back from doing a slimmed-down v2
>>> here is that
>>> evidently there's no consensus even on the ASSERT_UNREACHABLE() patches.
>>
>> ... I agree with the following statement from Jan:
>>
>> "it should instead demand no [unannotated] fall-through, which can also be
>> achieved by return, continue, and goto"
> 
> I also think it is a better idea to have no unannotated fall-through in
> switch statements (unless we have a "case" with nothing underneath, so
> two cases next to each other). In other words the following are all OK
> in my view:
> 
>    case A:
>      do();
>      break;
>    case B:
>      do();
>      return true;
>    case Ca:
>    case Cb:
>      goto fail;
>    case D:
>      i++;
>      continue;
>    case E:
>      do();
>      /* fall-through */
>    case F:
>      do();
>      break;
> 
> While the following is not OK:
> 
>    case A:
>      do();
>    case B:
>      do();
> 
> This should be what we already do in Xen, although it is not documented
> properly. Jan, Julien do you agree?

I agree.

Cheers,
diff mbox series

Patch

diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c
index 022f548652..fcee902b4e 100644
--- a/xen/common/sched/core.c
+++ b/xen/common/sched/core.c
@@ -2233,6 +2233,7 @@  static bool sched_tasklet_check_cpu(unsigned int cpu)
         /* fallthrough */
     case TASKLET_enqueued|TASKLET_scheduled:
         return true;
+        ASSERT_UNREACHABLE();
         break;
     case TASKLET_scheduled:
         clear_bit(_TASKLET_scheduled, tasklet_work);