[PATCH] hw/timer: fix int underflow

Dmitry Frolov posted 1 patch 1 year, 3 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20241106104041.624806-2-frolov@swemel.ru
Maintainers: Peter Maydell <peter.maydell@linaro.org>
hw/timer/imx_gpt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
[PATCH] hw/timer: fix int underflow
Posted by Dmitry Frolov 1 year, 3 months ago
Both timeout and return value of imx_gpt_update_count() are unsigned.
Thus "limit" can not be negative, but obviously it was implied.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Signed-off-by: Dmitry Frolov <frolov@swemel.ru>
---
 hw/timer/imx_gpt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index 23b3d79bdb..06e4837fed 100644
--- a/hw/timer/imx_gpt.c
+++ b/hw/timer/imx_gpt.c
@@ -238,7 +238,7 @@ static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event)
     }
 
     /* the new range to count down from */
-    limit = timeout - imx_gpt_update_count(s);
+    limit = (long long)timeout - imx_gpt_update_count(s);
 
     if (limit < 0) {
         /*
-- 
2.43.0
Re: [PATCH] hw/timer: fix int underflow
Posted by Peter Maydell 1 year, 2 months ago
On Wed, 6 Nov 2024 at 10:41, Dmitry Frolov <frolov@swemel.ru> wrote:
>
> Both timeout and return value of imx_gpt_update_count() are unsigned.
> Thus "limit" can not be negative, but obviously it was implied.

For changes to device models, you need to look at the
data sheet for the device to determine the correct
behaviour so you can confirm that the change you're
making is right. This commit message doesn't include
any of that reasoning, which means reviewers have to
do it all for themselves.

> Found by Linux Verification Center (linuxtesting.org) with SVACE.
>
> Signed-off-by: Dmitry Frolov <frolov@swemel.ru>
> ---
>  hw/timer/imx_gpt.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
> index 23b3d79bdb..06e4837fed 100644
> --- a/hw/timer/imx_gpt.c
> +++ b/hw/timer/imx_gpt.c
> @@ -238,7 +238,7 @@ static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event)
>      }
>
>      /* the new range to count down from */
> -    limit = timeout - imx_gpt_update_count(s);
> +    limit = (long long)timeout - imx_gpt_update_count(s);

We really shouldn't be using "long long" here in the
first place. If we need a 64-bit signed integer to
give correct behaviour then that's int64_t. Almost
all the handful of uses of 'long long' in hw/ are
doing it just as a lazy way to avoid PRIx64 in a
printf format string.

The GPT has a 32-bit up-counter. If timeout is, for
instance, 0x9000_0000 and the current count is
0x2000_0000 then we want the new "limit" value to
be 0x7000_0000 because we still have 0x7000_0000
cycles to go til we hit the next point where we want
to generate a compare event. So I think we do indeed
want to cast to a 64-bit signed value here.

(More broadly I think the problem with this device is
that it's trying to use ptimer (which is a down-counter)
to model an up-counter. This doesn't work very well,
and it's better to not do that. Arguably we should have
some nicer abstractions over raw qtimers for the
up-counter case and/or get ptimer to handle that
too, but that's a lot of work...)

thanks
-- PMM
Re: [PATCH] hw/timer: fix int underflow
Posted by Дмитрий Фролов 1 year ago
Hello, Peter.
I beg a pardon, but I guess, we have a misunderstanding here.

The problem is that comparison "if (limit < 0)" will never
be true. Thus, "true" branch is unreachable. According to
the comment below, it was assumed that "limit" may be
negative, and this means, that "QEMU is running too slow...".

"limit" is declared as "long long" and it is initialized
with diff of two unsigned values:
"timeout - imx_gpt_update_count(s)".
Unsigned subtraction will never give a signed result!
if timeout > imx_gpt_update_count(s), the result will be > 0.
if timeout < imx_gpt_update_count(s), the result will also
be > 0 (underflow). Then, actually, this (positive) result
will be implicitly casted to "long long" and assigned to
"limit". This makes no sense!

So, to my opinion, explicit cast to "long long" is necessary
here to get the expected behavior.

With best regards,
Dmitry.
Re: [PATCH] hw/timer: fix int underflow
Posted by Peter Maydell 1 year ago
On Tue, 14 Jan 2025 at 06:41, Дмитрий Фролов <frolov@swemel.ru> wrote:
>
> Hello, Peter.
> I beg a pardon, but I guess, we have a misunderstanding here.
>
> The problem is that comparison "if (limit < 0)" will never
> be true. Thus, "true" branch is unreachable. According to
> the comment below, it was assumed that "limit" may be
> negative, and this means, that "QEMU is running too slow...".
>
> "limit" is declared as "long long" and it is initialized
> with diff of two unsigned values:
> "timeout - imx_gpt_update_count(s)".
> Unsigned subtraction will never give a signed result!
> if timeout > imx_gpt_update_count(s), the result will be > 0.
> if timeout < imx_gpt_update_count(s), the result will also
> be > 0 (underflow). Then, actually, this (positive) result
> will be implicitly casted to "long long" and assigned to
> "limit". This makes no sense!
>
> So, to my opinion, explicit cast to "long long" is necessary
> here to get the expected behavior.

I wasn't saying the existing code was necessarily correct,
or that your proposed change was necessarily wrong.
I was saying your patch didn't come with any analysis of
what the actual hardware behaviour is, which is
how you would determine whether the fix you propose
is the correct one, or if it should be some other
change instead. (Some of my response was trying to
provide some of that analysis.)

thanks
-- PMM
Re: [PATCH] hw/timer: fix int underflow
Posted by Paolo Bonzini 1 year ago
On 1/14/25 11:14, Peter Maydell wrote:
>> So, to my opinion, explicit cast to "long long" is necessary
>> here to get the expected behavior.
> 
> I wasn't saying the existing code was necessarily correct,
> or that your proposed change was necessarily wrong.
> I was saying your patch didn't come with any analysis of
> what the actual hardware behaviour is, which is
> how you would determine whether the fix you propose
> is the correct one, or if it should be some other
> change instead. (Some of my response was trying to
> provide some of that analysis.)
I would say that the patch is more or less obvious in the sense that the 
intent of the code is to model a counter (which counts up by 1 and 
cannot miss a step) with a timer within a process that could be 
preempted.  You probably will not find an answer in the datasheet, other 
than by analyzing the signal diagrams, because this scenario simply 
cannot exist with a hardware counter.

However, the patch has another problem, which is that it can cause a 
stack overflow at imx_gpt_compute_next_timeout(s, event).

Paolo
Re: [PATCH] hw/timer: fix int underflow
Posted by Peter Maydell 1 year ago
On Tue, 14 Jan 2025 at 10:40, Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> On 1/14/25 11:14, Peter Maydell wrote:
> >> So, to my opinion, explicit cast to "long long" is necessary
> >> here to get the expected behavior.
> >
> > I wasn't saying the existing code was necessarily correct,
> > or that your proposed change was necessarily wrong.
> > I was saying your patch didn't come with any analysis of
> > what the actual hardware behaviour is, which is
> > how you would determine whether the fix you propose
> > is the correct one, or if it should be some other
> > change instead. (Some of my response was trying to
> > provide some of that analysis.)
> I would say that the patch is more or less obvious in the sense that the
> intent of the code is to model a counter (which counts up by 1 and
> cannot miss a step) with a timer within a process that could be
> preempted.  You probably will not find an answer in the datasheet, other
> than by analyzing the signal diagrams, because this scenario simply
> cannot exist with a hardware counter.

Well, for a start, you want to look at the datasheet
to check that this really is modelling a counter and
how wide the counter is (32 bits in this case).

thanks
-- PMM
Re: [PATCH] hw/timer: fix int underflow
Posted by Philippe Mathieu-Daudé 1 year, 2 months ago
Hi Dmitry,

On 6/11/24 11:40, Dmitry Frolov wrote:
> Both timeout and return value of imx_gpt_update_count() are unsigned.
> Thus "limit" can not be negative, but obviously it was implied.
> 
> Found by Linux Verification Center (linuxtesting.org) with SVACE.
> 
> Signed-off-by: Dmitry Frolov <frolov@swemel.ru>
> ---
>   hw/timer/imx_gpt.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
> index 23b3d79bdb..06e4837fed 100644
> --- a/hw/timer/imx_gpt.c
> +++ b/hw/timer/imx_gpt.c
> @@ -238,7 +238,7 @@ static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event)
>       }
>   
>       /* the new range to count down from */
> -    limit = timeout - imx_gpt_update_count(s);
> +    limit = (long long)timeout - imx_gpt_update_count(s);

You posted similar automatic change in at least 3 different
code areas. Each time different maintainers made similar
comments. At this point you should be able to auto-review
this patch and respin a proper follow up IMHO. Reviewers and
maintainers time is scarce.

Regards,

Phil.
Re: [PATCH] hw/timer: fix int underflow
Posted by Дмитрий Фролов 1 year, 2 months ago
Hi, Phil.

On 26.11.2024 11:39, Philippe Mathieu-Daudé wrote:
> Hi Dmitry,
>
> On 6/11/24 11:40, Dmitry Frolov wrote:
>> Both timeout and return value of imx_gpt_update_count() are unsigned.
>> Thus "limit" can not be negative, but obviously it was implied.
>>
>> Found by Linux Verification Center (linuxtesting.org) with SVACE.
>>
>> Signed-off-by: Dmitry Frolov <frolov@swemel.ru>
>> ---
>>   hw/timer/imx_gpt.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
>> index 23b3d79bdb..06e4837fed 100644
>> --- a/hw/timer/imx_gpt.c
>> +++ b/hw/timer/imx_gpt.c
>> @@ -238,7 +238,7 @@ static void 
>> imx_gpt_compute_next_timeout(IMXGPTState *s, bool event)
>>       }
>>         /* the new range to count down from */
>> -    limit = timeout - imx_gpt_update_count(s);
>> +    limit = (long long)timeout - imx_gpt_update_count(s);
>
> You posted similar automatic change in at least 3 different
> code areas.
The patches, I've sent, are not "automatic".
The problems were found by static analyzer in different code
areas, maintained by different people. These problems were
reviewed and fixed by me manually.
> Each time different maintainers made similar
> comments. At this point you should be able to auto-review
> this patch and respin a proper follow up IMHO. Reviewers and
> maintainers time is scarce.
Sorry, if do something wrong.
What is the proper workflow in this case from your point of view?

> Regards,
>
> Phil.

Regards,
Dmitry.
>

Re: [PATCH] hw/timer: fix int underflow
Posted by Дмитрий Фролов 1 year, 2 months ago
ping