[PATCH] lib: sbi: Fix printf handling of long long
Jessica Clarke
jrtc27 at jrtc27.com
Wed Jul 27 07:53:37 PDT 2022
On 27 Jul 2022, at 15:48, Jessica Clarke <jrtc27 at jrtc27.com> wrote:
>
> On 27 Jul 2022, at 15:32, Andrew Jones <ajones at ventanamicro.com> wrote:
>>
>> On Wed, Jul 27, 2022 at 10:07:39PM +0800, dramforever wrote:
>>> Do not attempt to unnecessarily align va_list before reading long long
>>> arguments.
>>
>> Can you please elaborate on why it was presumed necessary once, but is now
>> deemed not necessary?
>
> Because of this nonsense that follows:
>
> if (sizeof(unsigned long long) ==
> sizeof(unsigned long)) {
> tmp = va_arg(args, unsigned long long);
> acnt += sizeof(unsigned long long);
> } else {
> ((unsigned long *)&tmp)[0] =
> va_arg(args, unsigned long);
> ((unsigned long *)&tmp)[1] =
> va_arg(args, unsigned long);
> acnt += 2*sizeof(unsigned long);
> }
>
> For RV64 the condition of the while is always false as variadic
> arguments are already padded to 8 bytes.
Uh I forgot to snip this sentence after my understanding evolved. This
is false and contradicted by what I say later.
> For RV32 the implementation of
> va_arg will dynamically align the pointer to 8 bytes at run time
> (mirroring what this loop does) so it would seem unnecessary, except
> for the nonsense that follows. Since unsigned long is only 32-bit, it
> ends up taking the else branch and reading two unsigned longs, which
> will *not* get the same dynamic alignment from the compiler. So long as
> that nonsense also exists the code is needed on RV32. Where this gets
> more problematic, though, is on RV64, since acnt does not stay in sync
> with how much args has been offset; all variadic arguments are padded
> to 8 bytes, but for (unsigned) int the printf implementation here only
> increments acnt by sizeof(int). Thus, on RV64, if you pass an odd
> number of ints and then a long long the implementation will erroneously
> skip an entry, which is presumably what resulted in this being found
> and the patch in question.
>
> This should all be changed to just reading an unsigned long long
> because that will do the right thing (if not that is a serious compiler
> bug), not try to buggily reimplement va_arg ABI lowering.
>
> Note this code has existed right from 9e8ff05cb61f ("Initial commit.”).
>
> Jess
>
>>> Signed-off-by: dramforever <dramforever at live.com>
>>> ---
>>> lib/sbi/sbi_console.c | 5 -----
>>> 1 file changed, 5 deletions(-)
>>>
>>> diff --git a/lib/sbi/sbi_console.c b/lib/sbi/sbi_console.c
>>> index 34c843d..7af50e5 100644
>>> --- a/lib/sbi/sbi_console.c
>>> +++ b/lib/sbi/sbi_console.c
>>> @@ -261,11 +261,6 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
>>> continue;
>>> }
>>> if (*format == 'l' && *(format + 1) == 'l') {
>>> - while (acnt &
>>> - (sizeof(unsigned long long) - 1)) {
>>> - va_arg(args, int);
>>> - acnt += sizeof(int);
>>> - }
>>
>> I think this should generate a "set but not used" warning with clang, as
>> this was the only place acnt was getting used. We can just remove all of
>> it.
>>
>> Thanks,
>> drew
>>
>>> if (sizeof(unsigned long long) ==
>>> sizeof(unsigned long)) {
>>> tmp = va_arg(args, unsigned long long);
>>> --
>>> 2.37.0
>>>
>>>
>>> --
>>> opensbi mailing list
>>> opensbi at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/opensbi
>>
>> --
>> opensbi mailing list
>> opensbi at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/opensbi
>
More information about the opensbi
mailing list