> [T]he change is entirely correct since the 'else' clause currently seems
> to take the increment into account:
>         if (s->len <= 2)
>             s->buf[s->len - 1] = data;
>         tmp105_write(s);
>
> Shouldn't the '- 1'  in the middle line be removed?

Several clarifications follow.

The bug seems to occur because the else clause does not correctly
account for the increment (i.e. !s->len ++). If this increment
operation in the conditional statement should remain there, the
assignment "s->buf[s->len - 1] = data" would appear to have to be
changed to "s->buf[s->len - 2] = data". However, this offset
adjustment would only shadow the root cause of the bug.

To further clarify this bug, I have also created a standalone unit test:

   
https://github.com/ahorn/benchmarks/blob/master/qemu-hw/tmp105/tmp105-test.c#L130

This test case would fail in the unmodified tmp105.c hardware model.
That is, you can produce the runtime assertion failure by reverting
the fix I have implemented in tmp105_tx() in the file

  https://github.com/ahorn/benchmarks/blob/master/qemu-hw/tmp105/tmp105.c#L140

There is also one correction about the bug description itself (see below).

 >> 8) Start transfer with I2C_START_RECV
>> 9) Receive high-order byte of temperature
>>    ...
>> Thus, when we read the higher-order byte in step (9), it is zero!

This description should read instead:

  [as before] ...

  8) Start transfer with I2C_START_RECV
  9) Receive high-order byte of temperature
10) Receive low-order byte of temperature

Thus, when we read the low-order byte in step (10), it is zero.

The rest of the argument remains the same.

I hope this correction and the unit test help in clarifying the source
of the error. I would greatly appreciate your thoughts on this.

With best regards,
Alex

On 6 December 2012 21:21, Blue Swirl <blauwir...@gmail.com> wrote:
> On Wed, Dec 5, 2012 at 7:48 PM, Alex Horn <alex.h...@cs.ox.ac.uk> wrote:
>> The private buffer length field must only be incremented after the I2C
>> frame has been transmitted.
>>
>> To expose this bug, assume the temperature in the TMP105 hardware model
>> is +0.125 C (e.g. snow slush). Note that eleven bit precision is required
>> to read this value; otherwise the reading is equal to zero centigrade (ice).
>>
>> Continue by considering the following I2C protocol steps:
>>
>> 1) Start transfer with I2C_START_SEND
>> 2) Send byte 0x01 (i.e. configuration register)
>> 3) Send byte 0x40 (i.e. eleven bit precision)
>> 4) End transfer with I2C_FINISH
>>
>> 5) Start transfer with I2C_START_SEND
>> 6) Send byte 0x00 (i.e. temperature register)
>> 7) End transfer I2C_FINISH
>>
>> 8) Start transfer with I2C_START_RECV
>> 9) Receive high-order byte of temperature
>>    ...
>>
>> In step (1), the function tmp105_tx() is called. By the conditional
>> check !s->len and the side effect with ++, s->len is equal to 1 when
>> step (2) begins. Thus, 0x40 is written to s->buf[1] in step (3).
>> By definition of tmp105_write(), s->config is set to zero in step (3).
>> Thus, when we read the higher-order byte in step (9), it is zero!
>>
>> In other words, the TMP105 hardware model allows us to measure 0 C (ice)
>> even with eleven bit precision when, in fact, it should be 0.125 C (slush)!
>>
>> Signed-off-by: Alex Horn <alex.h...@cs.ox.ac.uk>
>> ---
>>  hw/tmp105.c |    3 ++-
>>  1 files changed, 2 insertions(+), 1 deletions(-)
>>
>> diff --git a/hw/tmp105.c b/hw/tmp105.c
>> index 8e8dbd9..5f41a3f 100644
>> --- a/hw/tmp105.c
>> +++ b/hw/tmp105.c
>> @@ -152,7 +152,7 @@ static int tmp105_tx(I2CSlave *i2c, uint8_t data)
>>  {
>>      TMP105State *s = (TMP105State *) i2c;
>>
>> -    if (!s->len ++)
>> +    if (s->len == 0)
>
> Please fix coding style (add braces) while touching this line.
>
> QEMU code is not yet consistent with our CODING_STYLE, but changes
> should make progress towards that.
>
>>          s->pointer = data;
>>      else {
>>          if (s->len <= 2)
>> @@ -160,6 +160,7 @@ static int tmp105_tx(I2CSlave *i2c, uint8_t data)
>>          tmp105_write(s);
>>      }
>>
>> +    s->len ++;
>
> Please remove the space between s->len and ++. However, I don't think
> the change is entirely correct since the 'else' clause currently seems
> to take the increment into account:
>         if (s->len <= 2)
>             s->buf[s->len - 1] = data;
>         tmp105_write(s);
>
> Shouldn't the '- 1'  in the middle line be removed?
>
>>      return 0;
>>  }
>>
>> --
>> 1.7.6.5
>>
>>

Reply via email to