diff mbox series

[RFC,2/4] xen/arm64: bitops: justify uninitialized variable inside a macro

Message ID d06a312944bee7457fa2ac75e0cfef20f0ec430f.1689329728.git.nicola.vetrini@bugseng.com (mailing list archive)
State New, archived
Headers show
Series fix some issues related to MISRA C:2012 Rule 9.1 | expand

Commit Message

Nicola Vetrini July 14, 2023, 11:49 a.m. UTC
The macro 'testop' expands to a function that declares the local
variable 'oldbit', which is written before being set, but is such a
way that is not amenable to automatic checking.

Therefore, a deviation comment, is introduced to document this situation.

A similar reasoning applies to macro 'guest_testop'.

Signed-off-by: Nicola Vetrini <nicola.vetrini@bugseng.com>
---
 docs/misra/safe.json                     | 16 ++++++++++++++++
 xen/arch/arm/arm64/lib/bitops.c          |  3 +++
 xen/arch/arm/include/asm/guest_atomics.h |  3 +++
 3 files changed, 22 insertions(+)

Comments

Julien Grall July 14, 2023, 1:05 p.m. UTC | #1
Hi,

On 14/07/2023 12:49, Nicola Vetrini wrote:
> The macro 'testop' expands to a function that declares the local
> variable 'oldbit', which is written before being set, but is such a
> way that is not amenable to automatic checking.

The code is pretty straightforward. So I am not entirely sure why Eclair 
is not happy. Is it because the value is set by assembly code?

Cheers,
Luca Fancellu July 14, 2023, 2:20 p.m. UTC | #2
> On 14 Jul 2023, at 12:49, Nicola Vetrini <nicola.vetrini@bugseng.com> wrote:
> 
> The macro 'testop' expands to a function that declares the local
> variable 'oldbit', which is written before being set, but is such a
> way that is not amenable to automatic checking.
> 
> Therefore, a deviation comment, is introduced to document this situation.
> 
> A similar reasoning applies to macro 'guest_testop'.
> 
> Signed-off-by: Nicola Vetrini <nicola.vetrini@bugseng.com>
> ---
> docs/misra/safe.json                     | 16 ++++++++++++++++
> xen/arch/arm/arm64/lib/bitops.c          |  3 +++
> xen/arch/arm/include/asm/guest_atomics.h |  3 +++
> 3 files changed, 22 insertions(+)
> 
> diff --git a/docs/misra/safe.json b/docs/misra/safe.json
> index 244001f5be..4cf7cbf57b 100644
> --- a/docs/misra/safe.json
> +++ b/docs/misra/safe.json
> @@ -20,6 +20,22 @@
>         },
>         {
>             "id": "SAF-2-safe",
> +            "analyser": {
> +                "eclair": "MC3R1.R9.1"
> +            },
> +            "name": "Rule 9.1: initializer not needed",
> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
> +        },
> +        {
> +            "id": "SAF-3-safe",
> +            "analyser": {
> +                "eclair": "MC3R1.R9.1"
> +            },
> +            "name": "Rule 9.1: initializer not needed",
> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
> +        },

Since the rule and the justification are the same, you can declare only once and use the same tag on top of the offending lines, so /* SAF-2-safe MC3R1.R9.1 */,
also, I remember some maintainers not happy about the misra rule being put after the tag, now I don’t recall who

> +        {
> +            "id": "SAF-4-safe",
>             "analyser": {},
>             "name": "Sentinel",
>             "text": "Next ID to be used"
> diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
> index 20e3f3d6ce..e0728bb29d 100644
> --- a/xen/arch/arm/arm64/lib/bitops.c
> +++ b/xen/arch/arm/arm64/lib/bitops.c
> @@ -114,8 +114,11 @@ bitop(change_bit, eor)
> bitop(clear_bit, bic)
> bitop(set_bit, orr)
> 
> +/* SAF-2-safe MC3R1.R9.1 */
> testop(test_and_change_bit, eor)
> +/* SAF-2-safe MC3R1.R9.1 */
> testop(test_and_clear_bit, bic)
> +/* SAF-2-safe MC3R1.R9.1 */
> testop(test_and_set_bit, orr)
> 
> static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
> diff --git a/xen/arch/arm/include/asm/guest_atomics.h b/xen/arch/arm/include/asm/guest_atomics.h
> index a1745f8613..9d8f8ec3a3 100644
> --- a/xen/arch/arm/include/asm/guest_atomics.h
> +++ b/xen/arch/arm/include/asm/guest_atomics.h
> @@ -67,8 +67,11 @@ guest_bitop(change_bit)
> /* test_bit does not use load-store atomic operations */
> #define guest_test_bit(d, nr, p) ((void)(d), test_bit(nr, p))
> 
> +/* SAF-3-safe MC3R1.R9.1 */
> guest_testop(test_and_set_bit)
> +/* SAF-3-safe MC3R1.R9.1 */
> guest_testop(test_and_clear_bit)
> +/* SAF-3-safe MC3R1.R9.1 */
> guest_testop(test_and_change_bit)
> 
> #undef guest_testop
> -- 
> 2.34.1
> 
>
Luca Fancellu July 14, 2023, 2:32 p.m. UTC | #3
> On 14 Jul 2023, at 15:20, Luca Fancellu <Luca.Fancellu@arm.com> wrote:
> 
> 
> 
>> On 14 Jul 2023, at 12:49, Nicola Vetrini <nicola.vetrini@bugseng.com> wrote:
>> 
>> The macro 'testop' expands to a function that declares the local
>> variable 'oldbit', which is written before being set, but is such a
>> way that is not amenable to automatic checking.
>> 
>> Therefore, a deviation comment, is introduced to document this situation.
>> 
>> A similar reasoning applies to macro 'guest_testop'.
>> 
>> Signed-off-by: Nicola Vetrini <nicola.vetrini@bugseng.com>
>> ---
>> docs/misra/safe.json                     | 16 ++++++++++++++++
>> xen/arch/arm/arm64/lib/bitops.c          |  3 +++
>> xen/arch/arm/include/asm/guest_atomics.h |  3 +++
>> 3 files changed, 22 insertions(+)
>> 
>> diff --git a/docs/misra/safe.json b/docs/misra/safe.json
>> index 244001f5be..4cf7cbf57b 100644
>> --- a/docs/misra/safe.json
>> +++ b/docs/misra/safe.json
>> @@ -20,6 +20,22 @@
>>        },
>>        {
>>            "id": "SAF-2-safe",
>> +            "analyser": {
>> +                "eclair": "MC3R1.R9.1"
>> +            },
>> +            "name": "Rule 9.1: initializer not needed",
>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>> +        },
>> +        {
>> +            "id": "SAF-3-safe",
>> +            "analyser": {
>> +                "eclair": "MC3R1.R9.1"
>> +            },
>> +            "name": "Rule 9.1: initializer not needed",
>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>> +        },
> 
> Since the rule and the justification are the same, you can declare only once and use the same tag on top of the offending lines, so /* SAF-2-safe MC3R1.R9.1 */,
> also, I remember some maintainers not happy about the misra rule being put after the tag, now I don’t recall who

Sorry, I see there was in a patch before a SAF-1-safe with the same justification, so I suggest you use SAF-3-safe as tag and drop the new justifications introduced here

> 
>> +        {
>> +            "id": "SAF-4-safe",
>>            "analyser": {},
>>            "name": "Sentinel",
>>            "text": "Next ID to be used"
>> diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
>> index 20e3f3d6ce..e0728bb29d 100644
>> --- a/xen/arch/arm/arm64/lib/bitops.c
>> +++ b/xen/arch/arm/arm64/lib/bitops.c
>> @@ -114,8 +114,11 @@ bitop(change_bit, eor)
>> bitop(clear_bit, bic)
>> bitop(set_bit, orr)
>> 
>> +/* SAF-2-safe MC3R1.R9.1 */
>> testop(test_and_change_bit, eor)
>> +/* SAF-2-safe MC3R1.R9.1 */
>> testop(test_and_clear_bit, bic)
>> +/* SAF-2-safe MC3R1.R9.1 */
>> testop(test_and_set_bit, orr)
>> 
>> static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
>> diff --git a/xen/arch/arm/include/asm/guest_atomics.h b/xen/arch/arm/include/asm/guest_atomics.h
>> index a1745f8613..9d8f8ec3a3 100644
>> --- a/xen/arch/arm/include/asm/guest_atomics.h
>> +++ b/xen/arch/arm/include/asm/guest_atomics.h
>> @@ -67,8 +67,11 @@ guest_bitop(change_bit)
>> /* test_bit does not use load-store atomic operations */
>> #define guest_test_bit(d, nr, p) ((void)(d), test_bit(nr, p))
>> 
>> +/* SAF-3-safe MC3R1.R9.1 */
>> guest_testop(test_and_set_bit)
>> +/* SAF-3-safe MC3R1.R9.1 */
>> guest_testop(test_and_clear_bit)
>> +/* SAF-3-safe MC3R1.R9.1 */
>> guest_testop(test_and_change_bit)
>> 
>> #undef guest_testop
>> -- 
>> 2.34.1
>> 
>> 
>
Luca Fancellu July 14, 2023, 2:36 p.m. UTC | #4
>>>           "id": "SAF-2-safe",
>>> +            "analyser": {
>>> +                "eclair": "MC3R1.R9.1"
>>> +            },
>>> +            "name": "Rule 9.1: initializer not needed",
>>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>>> +        },
>>> +        {
>>> +            "id": "SAF-3-safe",
>>> +            "analyser": {
>>> +                "eclair": "MC3R1.R9.1"
>>> +            },
>>> +            "name": "Rule 9.1: initializer not needed",
>>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>>> +        },
>> 
>> Since the rule and the justification are the same, you can declare only once and use the same tag on top of the offending lines, so /* SAF-2-safe MC3R1.R9.1 */,
>> also, I remember some maintainers not happy about the misra rule being put after the tag, now I don’t recall who
> 
> Sorry, I see there was in a patch before a SAF-1-safe with the same justification, so I suggest you use SAF-3-safe as tag and drop the new justifications introduced here

I meant “use SAF-1-safe”, sorry, I should do less multitasking
Nicola Vetrini July 14, 2023, 2:49 p.m. UTC | #5
On 14/07/23 16:32, Luca Fancellu wrote:
> 
> 
>> On 14 Jul 2023, at 15:20, Luca Fancellu <Luca.Fancellu@arm.com> wrote:
>>
>>
>>
>>> On 14 Jul 2023, at 12:49, Nicola Vetrini <nicola.vetrini@bugseng.com> wrote:
>>>
>>> The macro 'testop' expands to a function that declares the local
>>> variable 'oldbit', which is written before being set, but is such a
>>> way that is not amenable to automatic checking.
>>>
>>> Therefore, a deviation comment, is introduced to document this situation.
>>>
>>> A similar reasoning applies to macro 'guest_testop'.
>>>
>>> Signed-off-by: Nicola Vetrini <nicola.vetrini@bugseng.com>
>>> ---
>>> docs/misra/safe.json                     | 16 ++++++++++++++++
>>> xen/arch/arm/arm64/lib/bitops.c          |  3 +++
>>> xen/arch/arm/include/asm/guest_atomics.h |  3 +++
>>> 3 files changed, 22 insertions(+)
>>>
>>> diff --git a/docs/misra/safe.json b/docs/misra/safe.json
>>> index 244001f5be..4cf7cbf57b 100644
>>> --- a/docs/misra/safe.json
>>> +++ b/docs/misra/safe.json
>>> @@ -20,6 +20,22 @@
>>>         },
>>>         {
>>>             "id": "SAF-2-safe",
>>> +            "analyser": {
>>> +                "eclair": "MC3R1.R9.1"
>>> +            },
>>> +            "name": "Rule 9.1: initializer not needed",
>>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>>> +        },
>>> +        {
>>> +            "id": "SAF-3-safe",
>>> +            "analyser": {
>>> +                "eclair": "MC3R1.R9.1"
>>> +            },
>>> +            "name": "Rule 9.1: initializer not needed",
>>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>>> +        },
>>
>> Since the rule and the justification are the same, you can declare only once and use the same tag on top of the offending lines, so /* SAF-2-safe MC3R1.R9.1 */,
>> also, I remember some maintainers not happy about the misra rule being put after the tag, now I don’t recall who
> 
> Sorry, I see there was in a patch before a SAF-1-safe with the same justification, so I suggest you use SAF-3-safe as tag and drop the new justifications introduced here

I was a bit uncertain in choosing whether to use different IDs for 
bitops.c and guest_atomics.h, as they are very similar. Maybe a 
catch-all justification is too broad, but I have no strong opinion here.

As for the rule identifier after the tag, that's not a big problem (I 
added it mostly to emphasize why the deviation is there at a glance).

> 
>>
>>> +        {
>>> +            "id": "SAF-4-safe",
>>>             "analyser": {},
>>>             "name": "Sentinel",
>>>             "text": "Next ID to be used"
>>> diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
>>> index 20e3f3d6ce..e0728bb29d 100644
>>> --- a/xen/arch/arm/arm64/lib/bitops.c
>>> +++ b/xen/arch/arm/arm64/lib/bitops.c
>>> @@ -114,8 +114,11 @@ bitop(change_bit, eor)
>>> bitop(clear_bit, bic)
>>> bitop(set_bit, orr)
>>>
>>> +/* SAF-2-safe MC3R1.R9.1 */
>>> testop(test_and_change_bit, eor)
>>> +/* SAF-2-safe MC3R1.R9.1 */
>>> testop(test_and_clear_bit, bic)
>>> +/* SAF-2-safe MC3R1.R9.1 */
>>> testop(test_and_set_bit, orr)
>>>
>>> static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
>>> diff --git a/xen/arch/arm/include/asm/guest_atomics.h b/xen/arch/arm/include/asm/guest_atomics.h
>>> index a1745f8613..9d8f8ec3a3 100644
>>> --- a/xen/arch/arm/include/asm/guest_atomics.h
>>> +++ b/xen/arch/arm/include/asm/guest_atomics.h
>>> @@ -67,8 +67,11 @@ guest_bitop(change_bit)
>>> /* test_bit does not use load-store atomic operations */
>>> #define guest_test_bit(d, nr, p) ((void)(d), test_bit(nr, p))
>>>
>>> +/* SAF-3-safe MC3R1.R9.1 */
>>> guest_testop(test_and_set_bit)
>>> +/* SAF-3-safe MC3R1.R9.1 */
>>> guest_testop(test_and_clear_bit)
>>> +/* SAF-3-safe MC3R1.R9.1 */
>>> guest_testop(test_and_change_bit)
>>>
>>> #undef guest_testop
>>> -- 
>>> 2.34.1
>>>
>>>
>>
>
Luca Fancellu July 16, 2023, 9:20 a.m. UTC | #6
> On 14 Jul 2023, at 14:05, Julien Grall <julien@xen.org> wrote:
> 
> Hi,
> 
> On 14/07/2023 12:49, Nicola Vetrini wrote:
>> The macro 'testop' expands to a function that declares the local
>> variable 'oldbit', which is written before being set, but is such a
>> way that is not amenable to automatic checking.
> 
> The code is pretty straightforward. So I am not entirely sure why Eclair is not happy. Is it because the value is set by assembly code?

Hi Julien,

Yes I agree that it’s strange, do you think that that if at line 97 we initialize oldbit to zero, it would solve the issue?
@Nicola

Cheers,
Luca

> 
> Cheers,
> 
> -- 
> Julien Grall
>
Julien Grall July 16, 2023, 4:50 p.m. UTC | #7
Hi,

On 16/07/2023 10:20, Luca Fancellu wrote:
>> On 14 Jul 2023, at 14:05, Julien Grall <julien@xen.org> wrote:
>>
>> Hi,
>>
>> On 14/07/2023 12:49, Nicola Vetrini wrote:
>>> The macro 'testop' expands to a function that declares the local
>>> variable 'oldbit', which is written before being set, but is such a
>>> way that is not amenable to automatic checking.
>>
>> The code is pretty straightforward. So I am not entirely sure why Eclair is not happy. Is it because the value is set by assembly code?
> 
> Hi Julien,
> 
> Yes I agree that it’s strange, do you think that that if at line 97 we initialize oldbit to zero, it would solve the issue?

At the moment, I am not entirely happy to zero oldbit because we have 
other places in Xen where we need assembly instructions to read a value 
(e.g. READ_SYSREG()).

So I would first like to understand why Eclair can't cope with it.

Cheers,
Nicola Vetrini July 17, 2023, 12:16 p.m. UTC | #8
On 16/07/23 18:50, Julien Grall wrote:
> Hi,
> 
> On 16/07/2023 10:20, Luca Fancellu wrote:
>>> On 14 Jul 2023, at 14:05, Julien Grall <julien@xen.org> wrote:
>>>
>>> Hi,
>>>
>>> On 14/07/2023 12:49, Nicola Vetrini wrote:
>>>> The macro 'testop' expands to a function that declares the local
>>>> variable 'oldbit', which is written before being set, but is such a
>>>> way that is not amenable to automatic checking.
>>>
>>> The code is pretty straightforward. So I am not entirely sure why 
>>> Eclair is not happy. Is it because the value is set by assembly code?

Exactly. The reason why I didn't just state that oldbit is always 
written or never read before being written in that function is that I 
was unsure about the meaning of the assembly.

>>
>> Hi Julien,
>>
>> Yes I agree that it’s strange, do you think that that if at line 97 we 
>> initialize oldbit to zero, it would solve the issue?
> 
> At the moment, I am not entirely happy to zero oldbit because we have 
> other places in Xen where we need assembly instructions to read a value 
> (e.g. READ_SYSREG()).
> 
> So I would first like to understand why Eclair can't cope with it.
> 
> Cheers,
>
Julien Grall July 17, 2023, 1:45 p.m. UTC | #9
Hi,

On 17/07/2023 13:16, Nicola Vetrini wrote:
> 
> 
> On 16/07/23 18:50, Julien Grall wrote:
>> Hi,
>>
>> On 16/07/2023 10:20, Luca Fancellu wrote:
>>>> On 14 Jul 2023, at 14:05, Julien Grall <julien@xen.org> wrote:
>>>>
>>>> Hi,
>>>>
>>>> On 14/07/2023 12:49, Nicola Vetrini wrote:
>>>>> The macro 'testop' expands to a function that declares the local
>>>>> variable 'oldbit', which is written before being set, but is such a
>>>>> way that is not amenable to automatic checking.
>>>>
>>>> The code is pretty straightforward. So I am not entirely sure why 
>>>> Eclair is not happy. Is it because the value is set by assembly code?
> 
> Exactly.

I am a bit puzzled. There are other values read from assembly (e.g. 
READ_SYSREG(), read_atomic()) within Xen. This is including 'res' in the 
same function. So can you elaborate, why 'oldbit' is a problem but not 
the others?

Cheers,
Jan Beulich July 17, 2023, 1:59 p.m. UTC | #10
On 14.07.2023 16:20, Luca Fancellu wrote:
> 
> 
>> On 14 Jul 2023, at 12:49, Nicola Vetrini <nicola.vetrini@bugseng.com> wrote:
>>
>> The macro 'testop' expands to a function that declares the local
>> variable 'oldbit', which is written before being set, but is such a
>> way that is not amenable to automatic checking.
>>
>> Therefore, a deviation comment, is introduced to document this situation.
>>
>> A similar reasoning applies to macro 'guest_testop'.
>>
>> Signed-off-by: Nicola Vetrini <nicola.vetrini@bugseng.com>
>> ---
>> docs/misra/safe.json                     | 16 ++++++++++++++++
>> xen/arch/arm/arm64/lib/bitops.c          |  3 +++
>> xen/arch/arm/include/asm/guest_atomics.h |  3 +++
>> 3 files changed, 22 insertions(+)
>>
>> diff --git a/docs/misra/safe.json b/docs/misra/safe.json
>> index 244001f5be..4cf7cbf57b 100644
>> --- a/docs/misra/safe.json
>> +++ b/docs/misra/safe.json
>> @@ -20,6 +20,22 @@
>>         },
>>         {
>>             "id": "SAF-2-safe",
>> +            "analyser": {
>> +                "eclair": "MC3R1.R9.1"
>> +            },
>> +            "name": "Rule 9.1: initializer not needed",
>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>> +        },
>> +        {
>> +            "id": "SAF-3-safe",
>> +            "analyser": {
>> +                "eclair": "MC3R1.R9.1"
>> +            },
>> +            "name": "Rule 9.1: initializer not needed",
>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>> +        },
> 
> Since the rule and the justification are the same, you can declare only once and use the same tag on top of the offending lines, so /* SAF-2-safe MC3R1.R9.1 */,

+1

I'm puzzled by the wording vs comment placement though: The comments
are inserted ahead of the macro invocations, so there are no "following
local variables". Plus does this imply the comment would suppress the
checking on _all_ of them, rather than just the one that was confirmed
to be safe? What if another new one was added, that actually introduces
a problem?

> also, I remember some maintainers not happy about the misra rule being put after the tag, now I don’t recall who

Me, at least. The annotations should be tool-agnostic imo, or else the
more tools we use, the longer these comments might get.

Jan
Jan Beulich July 17, 2023, 2:06 p.m. UTC | #11
On 17.07.2023 14:16, Nicola Vetrini wrote:
> On 16/07/23 18:50, Julien Grall wrote:
>> On 16/07/2023 10:20, Luca Fancellu wrote:
>>>> On 14 Jul 2023, at 14:05, Julien Grall <julien@xen.org> wrote:
>>>> On 14/07/2023 12:49, Nicola Vetrini wrote:
>>>>> The macro 'testop' expands to a function that declares the local
>>>>> variable 'oldbit', which is written before being set, but is such a
>>>>> way that is not amenable to automatic checking.
>>>>
>>>> The code is pretty straightforward. So I am not entirely sure why 
>>>> Eclair is not happy. Is it because the value is set by assembly code?
> 
> Exactly. The reason why I didn't just state that oldbit is always 
> written or never read before being written in that function is that I 
> was unsure about the meaning of the assembly.

So I'm pretty sure the tool wouldn't take apart the string literal passed
first to the asm(). Instead I expect it goes from the operands specified,
which for oldbit is "=&r". There's nothing conditional here, so if the
tool didn't trust that outputs are written, it would need to flag such an
issue on about any asm() having outputs.

I hope the issue isn't that the tool doesn't properly deal with the
do/while.

In any event: I may misremember earlier discussions, but isn't this a
pretty obvious false positive? In which case didn't we mean to flag
those as such (because really an improved checking tool could avoid them)?

Jan
Nicola Vetrini July 17, 2023, 2:17 p.m. UTC | #12
On 17/07/23 16:06, Jan Beulich wrote:
> On 17.07.2023 14:16, Nicola Vetrini wrote:
>> On 16/07/23 18:50, Julien Grall wrote:
>>> On 16/07/2023 10:20, Luca Fancellu wrote:
>>>>> On 14 Jul 2023, at 14:05, Julien Grall <julien@xen.org> wrote:
>>>>> On 14/07/2023 12:49, Nicola Vetrini wrote:
>>>>>> The macro 'testop' expands to a function that declares the local
>>>>>> variable 'oldbit', which is written before being set, but is such a
>>>>>> way that is not amenable to automatic checking.
>>>>>
>>>>> The code is pretty straightforward. So I am not entirely sure why
>>>>> Eclair is not happy. Is it because the value is set by assembly code?
>>
>> Exactly. The reason why I didn't just state that oldbit is always
>> written or never read before being written in that function is that I
>> was unsure about the meaning of the assembly.
> 
> So I'm pretty sure the tool wouldn't take apart the string literal passed
> first to the asm(). Instead I expect it goes from the operands specified,
> which for oldbit is "=&r". There's nothing conditional here, so if the
> tool didn't trust that outputs are written, it would need to flag such an
> issue on about any asm() having outputs.
> 
> I hope the issue isn't that the tool doesn't properly deal with the
> do/while.
> 
> In any event: I may misremember earlier discussions, but isn't this a
> pretty obvious false positive? In which case didn't we mean to flag
> those as such (because really an improved checking tool could avoid them)?
> 
> Jan
> 

Actually, given that the function indeed always writes oldbit in the asm 
instruction, I can state that this post-condition holds for the function.
Nicola Vetrini July 17, 2023, 3:28 p.m. UTC | #13
On 17/07/23 15:59, Jan Beulich wrote:
> On 14.07.2023 16:20, Luca Fancellu wrote:
>>
>>
>>> On 14 Jul 2023, at 12:49, Nicola Vetrini <nicola.vetrini@bugseng.com> wrote:
>>>
>>> The macro 'testop' expands to a function that declares the local
>>> variable 'oldbit', which is written before being set, but is such a
>>> way that is not amenable to automatic checking.
>>>
>>> Therefore, a deviation comment, is introduced to document this situation.
>>>
>>> A similar reasoning applies to macro 'guest_testop'.
>>>
>>> Signed-off-by: Nicola Vetrini <nicola.vetrini@bugseng.com>
>>> ---
>>> docs/misra/safe.json                     | 16 ++++++++++++++++
>>> xen/arch/arm/arm64/lib/bitops.c          |  3 +++
>>> xen/arch/arm/include/asm/guest_atomics.h |  3 +++
>>> 3 files changed, 22 insertions(+)
>>>
>>> diff --git a/docs/misra/safe.json b/docs/misra/safe.json
>>> index 244001f5be..4cf7cbf57b 100644
>>> --- a/docs/misra/safe.json
>>> +++ b/docs/misra/safe.json
>>> @@ -20,6 +20,22 @@
>>>          },
>>>          {
>>>              "id": "SAF-2-safe",
>>> +            "analyser": {
>>> +                "eclair": "MC3R1.R9.1"
>>> +            },
>>> +            "name": "Rule 9.1: initializer not needed",
>>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>>> +        },
>>> +        {
>>> +            "id": "SAF-3-safe",
>>> +            "analyser": {
>>> +                "eclair": "MC3R1.R9.1"
>>> +            },
>>> +            "name": "Rule 9.1: initializer not needed",
>>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>>> +        },
>>
>> Since the rule and the justification are the same, you can declare only once and use the same tag on top of the offending lines, so /* SAF-2-safe MC3R1.R9.1 */,
> 
> +1
> 
> I'm puzzled by the wording vs comment placement though: The comments
> are inserted ahead of the macro invocations, so there are no "following
> local variables". Plus does this imply the comment would suppress the
> checking on _all_ of them, rather than just the one that was confirmed
> to be safe? What if another new one was added, that actually introduces
> a problem?
> 
>> also, I remember some maintainers not happy about the misra rule being put after the tag, now I don’t recall who
> 
> Me, at least. The annotations should be tool-agnostic imo, or else the
> more tools we use, the longer these comments might get.
> 
> Jan

No problem for both: Given the earlier remarks by Julien on patch 1/4, I 
think we can devise something along the lines of

/* SAF-x-safe MISRA:C 2012 Rule 9.1 <Justification> */
int var;

and then write a generic justification in docs/misra/safe.json, while
<Justification> contains a specific one (e.g., this loop does so and so 
to ensure that no access to unset variables happens). Thus any 
modification to that variable would give who submits the patch and the 
reviewer a chance to spot any inconsistency when the code is modified.

However, given my other response to this same patch, this does not apply 
here specifically.
Jan Beulich July 17, 2023, 3:46 p.m. UTC | #14
On 17.07.2023 17:28, Nicola Vetrini wrote:
> 
> 
> On 17/07/23 15:59, Jan Beulich wrote:
>> On 14.07.2023 16:20, Luca Fancellu wrote:
>>>
>>>
>>>> On 14 Jul 2023, at 12:49, Nicola Vetrini <nicola.vetrini@bugseng.com> wrote:
>>>>
>>>> The macro 'testop' expands to a function that declares the local
>>>> variable 'oldbit', which is written before being set, but is such a
>>>> way that is not amenable to automatic checking.
>>>>
>>>> Therefore, a deviation comment, is introduced to document this situation.
>>>>
>>>> A similar reasoning applies to macro 'guest_testop'.
>>>>
>>>> Signed-off-by: Nicola Vetrini <nicola.vetrini@bugseng.com>
>>>> ---
>>>> docs/misra/safe.json                     | 16 ++++++++++++++++
>>>> xen/arch/arm/arm64/lib/bitops.c          |  3 +++
>>>> xen/arch/arm/include/asm/guest_atomics.h |  3 +++
>>>> 3 files changed, 22 insertions(+)
>>>>
>>>> diff --git a/docs/misra/safe.json b/docs/misra/safe.json
>>>> index 244001f5be..4cf7cbf57b 100644
>>>> --- a/docs/misra/safe.json
>>>> +++ b/docs/misra/safe.json
>>>> @@ -20,6 +20,22 @@
>>>>          },
>>>>          {
>>>>              "id": "SAF-2-safe",
>>>> +            "analyser": {
>>>> +                "eclair": "MC3R1.R9.1"
>>>> +            },
>>>> +            "name": "Rule 9.1: initializer not needed",
>>>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>>>> +        },
>>>> +        {
>>>> +            "id": "SAF-3-safe",
>>>> +            "analyser": {
>>>> +                "eclair": "MC3R1.R9.1"
>>>> +            },
>>>> +            "name": "Rule 9.1: initializer not needed",
>>>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>>>> +        },
>>>
>>> Since the rule and the justification are the same, you can declare only once and use the same tag on top of the offending lines, so /* SAF-2-safe MC3R1.R9.1 */,
>>
>> +1
>>
>> I'm puzzled by the wording vs comment placement though: The comments
>> are inserted ahead of the macro invocations, so there are no "following
>> local variables". Plus does this imply the comment would suppress the
>> checking on _all_ of them, rather than just the one that was confirmed
>> to be safe? What if another new one was added, that actually introduces
>> a problem?
>>
>>> also, I remember some maintainers not happy about the misra rule being put after the tag, now I don’t recall who
>>
>> Me, at least. The annotations should be tool-agnostic imo, or else the
>> more tools we use, the longer these comments might get.
> 
> No problem for both: Given the earlier remarks by Julien on patch 1/4, I 
> think we can devise something along the lines of
> 
> /* SAF-x-safe MISRA:C 2012 Rule 9.1 <Justification> */
> int var;
> 
> and then write a generic justification in docs/misra/safe.json, while
> <Justification> contains a specific one (e.g., this loop does so and so 
> to ensure that no access to unset variables happens).

But that still mentions the rule. What if a new MISRA:C 2025 appears,
with different rule numbers? I don't mind the comment mentioning, in
a sufficiently terse way, what problem is circumvented. But I don't
think tools or specifications should be referenced here. That's the
purpose of the referenced "database" entry.

Jan
Julien Grall July 17, 2023, 8:40 p.m. UTC | #15
Hi,

On 14/07/2023 12:49, Nicola Vetrini wrote:
> The macro 'testop' expands to a function that declares the local
> variable 'oldbit', which is written before being set, but is such a
> way that is not amenable to automatic checking.
> 
> Therefore, a deviation comment, is introduced to document this situation.
> 
> A similar reasoning applies to macro 'guest_testop'.

Would you be able to check if the code below (only compile tested so 
far) would silence Eclair?

diff --git a/xen/arch/arm/arm64/lib/bitops.c 
b/xen/arch/arm/arm64/lib/bitops.c
index 20e3f3d6ceaf..f7a10b790f2a 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -64,13 +64,15 @@ bool name##_timeout(int nr, volatile void *p, 
unsigned int max_try)         \
  }

  #define testop(name, instr) 
      \
-static always_inline bool int_##name(int nr, volatile void *p, int 
*oldbit, \
-                                     bool timeout, unsigned int 
max_try)    \
+static always_inline int int_##name(int nr, volatile void *p, 
     \
+                                    bool allow_timeout, bool *timeout, 
     \
+                                    unsigned int max_try) 
     \
  { 
      \
      volatile uint32_t *ptr = (uint32_t *)p + BITOP_WORD((unsigned 
int)nr);  \
      unsigned int bit = (unsigned int)nr % BITOP_BITS_PER_WORD; 
      \
      const uint32_t mask = BITOP_MASK(bit); 
      \
      unsigned long res, tmp; 
      \
+    int oldbit; 
     \
 
      \
      do 
      \
      { 
      \
@@ -79,27 +81,30 @@ static always_inline bool int_##name(int nr, 
volatile void *p, int *oldbit, \
          "   lsr     %w1, %w3, %w5 // Save old value of bit\n" 
      \
          "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n" 
      \
          "   stlxr   %w0, %w3, %2\n" 
      \
-        : "=&r" (res), "=&r" (*oldbit), "+Q" (*ptr), "=&r" (tmp) 
     \
+        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp) 
     \
          : "r" (mask), "r" (bit) 
      \
          : "memory"); 
      \
 
      \
          if ( !res ) 
      \
              break; 
      \
-    } while ( !timeout || ((--max_try) > 0) ); 
     \
+    } while ( !allow_timeout || ((--max_try) > 0) ); 
     \
 
      \
      dmb(ish); 
      \
 
      \
-    *oldbit &= 1; 
     \
+    ASSERT(!allow_timeout || timeout); 
     \
+    if ( timeout ) 
     \
+        *timeout = !res; 
     \
+    else if ( !res ) 
     \
+        ASSERT_UNREACHABLE(); 
     \
 
      \
-    return !res; 
     \
+    return (oldbit & 1); 
     \
  } 
      \
 
      \
  int name(int nr, volatile void *p) 
      \
  { 
      \
      int oldbit; 
      \
 
      \
-    if ( !int_##name(nr, p, &oldbit, false, 0) ) 
     \
-        ASSERT_UNREACHABLE(); 
     \
+    oldbit = int_##name(nr, p, false, NULL, 0); 
     \
 
      \

Cheers,
Julien Grall July 17, 2023, 8:45 p.m. UTC | #16
On 17/07/2023 21:40, Julien Grall wrote:
> On 14/07/2023 12:49, Nicola Vetrini wrote:
>> The macro 'testop' expands to a function that declares the local
>> variable 'oldbit', which is written before being set, but is such a
>> way that is not amenable to automatic checking.
>>
>> Therefore, a deviation comment, is introduced to document this situation.
>>
>> A similar reasoning applies to macro 'guest_testop'.
> 
> Would you be able to check if the code below (only compile tested so 
> far) would silence Eclair?

Hmmm.. I think my e-mail client mangled the diff. Here an unmangled 
version if needed:

http://paste.debian.net/1286154/

Cheers,
Nicola Vetrini July 18, 2023, 1:48 p.m. UTC | #17
On 17/07/23 17:46, Jan Beulich wrote:
> On 17.07.2023 17:28, Nicola Vetrini wrote:
>>
>>
>> On 17/07/23 15:59, Jan Beulich wrote:
>>> On 14.07.2023 16:20, Luca Fancellu wrote:
>>>>
>>>>
>>>>> On 14 Jul 2023, at 12:49, Nicola Vetrini <nicola.vetrini@bugseng.com> wrote:
>>>>>
>>>>> The macro 'testop' expands to a function that declares the local
>>>>> variable 'oldbit', which is written before being set, but is such a
>>>>> way that is not amenable to automatic checking.
>>>>>
>>>>> Therefore, a deviation comment, is introduced to document this situation.
>>>>>
>>>>> A similar reasoning applies to macro 'guest_testop'.
>>>>>
>>>>> Signed-off-by: Nicola Vetrini <nicola.vetrini@bugseng.com>
>>>>> ---
>>>>> docs/misra/safe.json                     | 16 ++++++++++++++++
>>>>> xen/arch/arm/arm64/lib/bitops.c          |  3 +++
>>>>> xen/arch/arm/include/asm/guest_atomics.h |  3 +++
>>>>> 3 files changed, 22 insertions(+)
>>>>>
>>>>> diff --git a/docs/misra/safe.json b/docs/misra/safe.json
>>>>> index 244001f5be..4cf7cbf57b 100644
>>>>> --- a/docs/misra/safe.json
>>>>> +++ b/docs/misra/safe.json
>>>>> @@ -20,6 +20,22 @@
>>>>>           },
>>>>>           {
>>>>>               "id": "SAF-2-safe",
>>>>> +            "analyser": {
>>>>> +                "eclair": "MC3R1.R9.1"
>>>>> +            },
>>>>> +            "name": "Rule 9.1: initializer not needed",
>>>>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>>>>> +        },
>>>>> +        {
>>>>> +            "id": "SAF-3-safe",
>>>>> +            "analyser": {
>>>>> +                "eclair": "MC3R1.R9.1"
>>>>> +            },
>>>>> +            "name": "Rule 9.1: initializer not needed",
>>>>> +            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
>>>>> +        },
>>>>
>>>> Since the rule and the justification are the same, you can declare only once and use the same tag on top of the offending lines, so /* SAF-2-safe MC3R1.R9.1 */,
>>>
>>> +1
>>>
>>> I'm puzzled by the wording vs comment placement though: The comments
>>> are inserted ahead of the macro invocations, so there are no "following
>>> local variables". Plus does this imply the comment would suppress the
>>> checking on _all_ of them, rather than just the one that was confirmed
>>> to be safe? What if another new one was added, that actually introduces
>>> a problem?
>>>
>>>> also, I remember some maintainers not happy about the misra rule being put after the tag, now I don’t recall who
>>>
>>> Me, at least. The annotations should be tool-agnostic imo, or else the
>>> more tools we use, the longer these comments might get.
>>
>> No problem for both: Given the earlier remarks by Julien on patch 1/4, I
>> think we can devise something along the lines of
>>
>> /* SAF-x-safe MISRA:C 2012 Rule 9.1 <Justification> */
>> int var;
>>
>> and then write a generic justification in docs/misra/safe.json, while
>> <Justification> contains a specific one (e.g., this loop does so and so
>> to ensure that no access to unset variables happens).
> 
> But that still mentions the rule. What if a new MISRA:C 2025 appears,
> with different rule numbers? I don't mind the comment mentioning, in
> a sufficiently terse way, what problem is circumvented. But I don't
> think tools or specifications should be referenced here. That's the
> purpose of the referenced "database" entry.
> 
> Jan

Ok
Nicola Vetrini July 19, 2023, 8:54 a.m. UTC | #18
On 17/07/23 22:45, Julien Grall wrote:
> 
> 
> On 17/07/2023 21:40, Julien Grall wrote:
>> On 14/07/2023 12:49, Nicola Vetrini wrote:
>>> The macro 'testop' expands to a function that declares the local
>>> variable 'oldbit', which is written before being set, but is such a
>>> way that is not amenable to automatic checking.
>>>
>>> Therefore, a deviation comment, is introduced to document this 
>>> situation.
>>>
>>> A similar reasoning applies to macro 'guest_testop'.
>>
>> Would you be able to check if the code below (only compile tested so 
>> far) would silence Eclair?
> 
> Hmmm.. I think my e-mail client mangled the diff. Here an unmangled 
> version if needed:
> 
> http://paste.debian.net/1286154/
> 
> Cheers,
> 

I have a question: wouldn't this patch also imply an update of 
xen/arch/arm/include/asm/guest_atomics.h ?

This in particular is the bit of code that needs to be reworked to use 
the newer *_timeout definition.


bool succeed;

succeed = name##_timeout(nr, p, &oldbit, 

                          this_cpu(guest_safe_atomic_max));

if ( succeed )
         return oldbit;

Probably something similar to


int succeed;

succeed = name##_timeout(nr, p, false, NULL, [...]);
if ( succeed != 0 )
   return succeed;

I'm not really sure whether the third param should be true or false, but 
I assumed false because it's similar to the use in bitops.c
Julien Grall July 19, 2023, 9:50 a.m. UTC | #19
Hi,

On 19/07/2023 09:54, Nicola Vetrini wrote:
> 
> 
> On 17/07/23 22:45, Julien Grall wrote:
>>
>>
>> On 17/07/2023 21:40, Julien Grall wrote:
>>> On 14/07/2023 12:49, Nicola Vetrini wrote:
>>>> The macro 'testop' expands to a function that declares the local
>>>> variable 'oldbit', which is written before being set, but is such a
>>>> way that is not amenable to automatic checking.
>>>>
>>>> Therefore, a deviation comment, is introduced to document this 
>>>> situation.
>>>>
>>>> A similar reasoning applies to macro 'guest_testop'.
>>>
>>> Would you be able to check if the code below (only compile tested so 
>>> far) would silence Eclair?
>>
>> Hmmm.. I think my e-mail client mangled the diff. Here an unmangled 
>> version if needed:
>>
>> http://paste.debian.net/1286154/
>>
>> Cheers,
>>
> 
> I have a question: wouldn't this patch also imply an update of 
> xen/arch/arm/include/asm/guest_atomics.h ?
> 
> This in particular is the bit of code that needs to be reworked to use 
> the newer *_timeout definition.

My patch is not changing the exported *_timeout. It is only changing the 
definition of int_##name which is not exported.

But I have realized that one chunk were missing. Here the new version:

https://paste.debian.net/1286311/

Cheers,
diff mbox series

Patch

diff --git a/docs/misra/safe.json b/docs/misra/safe.json
index 244001f5be..4cf7cbf57b 100644
--- a/docs/misra/safe.json
+++ b/docs/misra/safe.json
@@ -20,6 +20,22 @@ 
         },
         {
             "id": "SAF-2-safe",
+            "analyser": {
+                "eclair": "MC3R1.R9.1"
+            },
+            "name": "Rule 9.1: initializer not needed",
+            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
+        },
+        {
+            "id": "SAF-3-safe",
+            "analyser": {
+                "eclair": "MC3R1.R9.1"
+            },
+            "name": "Rule 9.1: initializer not needed",
+            "text": "The following local variables are possibly subject to being read before being written, but code inspection ensured that the control flow in the construct where they appear ensures that no such event may happen."
+        },
+        {
+            "id": "SAF-4-safe",
             "analyser": {},
             "name": "Sentinel",
             "text": "Next ID to be used"
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
index 20e3f3d6ce..e0728bb29d 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -114,8 +114,11 @@  bitop(change_bit, eor)
 bitop(clear_bit, bic)
 bitop(set_bit, orr)
 
+/* SAF-2-safe MC3R1.R9.1 */
 testop(test_and_change_bit, eor)
+/* SAF-2-safe MC3R1.R9.1 */
 testop(test_and_clear_bit, bic)
+/* SAF-2-safe MC3R1.R9.1 */
 testop(test_and_set_bit, orr)
 
 static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
diff --git a/xen/arch/arm/include/asm/guest_atomics.h b/xen/arch/arm/include/asm/guest_atomics.h
index a1745f8613..9d8f8ec3a3 100644
--- a/xen/arch/arm/include/asm/guest_atomics.h
+++ b/xen/arch/arm/include/asm/guest_atomics.h
@@ -67,8 +67,11 @@  guest_bitop(change_bit)
 /* test_bit does not use load-store atomic operations */
 #define guest_test_bit(d, nr, p) ((void)(d), test_bit(nr, p))
 
+/* SAF-3-safe MC3R1.R9.1 */
 guest_testop(test_and_set_bit)
+/* SAF-3-safe MC3R1.R9.1 */
 guest_testop(test_and_clear_bit)
+/* SAF-3-safe MC3R1.R9.1 */
 guest_testop(test_and_change_bit)
 
 #undef guest_testop