Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2008-06

Assignment to bitpacked record member that crosses byte boundary does not always work correctly (i386).

3 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Unknown author

Hi,

I was interested to see if bit packing works when a record member spans byte boundaries, and in general it appears to work. However on my i386 system I discovered a bug that the following illustrates.

//---------------------------------------------
//Tested on Intel Core 2 Duo running Windows XP Pro SP2.
// Compiler version 2.2.0 [2007/09/09] and 2.3.1  [2008/02/03]
uses SysUtils, Crt;
type
    bit = 0..1;
    t7bit = 0..$3F;
    // A record to test behaviour over byte boundaries.
    BitStruct = bitpacked record
        bit0    : bit;
        bit8_1  : byte;   // Assigning $FF to this member causes
problems...
        bit15_9 : t7bit;
    end;
    // Map the record to a word for convenience - but overlaying
    // a word using absolute instead of a variant record produces
    // the same result.
    MappedStruct = record
        case boolean of
            false : (AsWord : word);
            true  : (AsBits : BitStruct);
    end;
var
    BitTest : MappedStruct;
begin
    clrscr;
    // Load a bitpacked value via the members, that should map to $01FF
in AsWord member.
    BitTest.AsBits.bit0 := 1;
    BitTest.AsBits.bit8_1 := $FF;
    BitTest.AsBits.bit15_9 := $00;
    // Display the mapped word value.

Writeln(' Expected word value : $01FF, Got : $',
IntToHex(BitTest.AsWord,4),

           ' (I get $0129 V2.2.0, $0129 V2.3.1)');
    // Display a member value

Writeln(' Expected bit8_1 value : $FF, Got : $',
IntToHex(BitTest.AsBits.bit8_1,2),

           '  (I get $94 V2.2.0, $94 V2.3.1)');
    WriteLn;
    WriteLn(' Repeat same test, but now in ''with'' statement ...');
    Writeln;
    with BitTest, AsBits do begin
        //  Same bitpacked value.
        bit0 := 1;
        bit8_1 := $FF;
        bit15_9 := $00;
        // Display the word value.

Writeln(' Expected word value : $01FF, Got :
$',IntToHex(BitTest.AsWord, 4),

                ' (I get $0001 V2.2.0, $01F9 V2.3.1)');
                // Display a member value

Writeln(' Expected bit8_1 value : $FF, Got : $',
IntToHex(BitTest.AsBits.bit8_1, 2),

           '  (I get $00 V2.2.0, $FC V2.3.1)');
    end;
    BitTest.AsWord := $01FF;
    WriteLn;
    WriteLn(' Assign $01FF to ''AsWord'' member and check ''AsBit''
members (works on my system)');
    WriteLn;
    WriteLn('   Expected bit15..9 value : $00, Got :
$',IntToHex(BitTest.AsBits.bit15_9, 2));
    Writeln('   Expected bit8_1 value : $FF, Got : $',
IntToHex(BitTest.AsBits.bit8_1 ,2));
    Writeln('   Expected bit0 value : $01, Got : $',
IntToHex(BitTest.AsBits.bit0, 2));
    repeat until KeyPressed;
end.
//---------------------------------------------

The limited amount of testing done indicates that the record member bit8_1 only causes a problem with a value of $FF, but the interesting thing is that the result varies depending on program structure and compiler version: Different results are seen whith the same code in a procedure, in a 'with' statement, or if there is code in front of it etc. The result is NOT always incorrect.

Note that using a variant record to show the value is only a convenience here and the error can be seen without a variant record by examining the record directly in a watch window, or by overlaying the record using the absolute keyword.

I have attached slightly more comprehensive tests.

Best Regards,

Russell Davies

*******************************************************************************************************

Disclaimer:
Denel (Pty) Ltd t/a Denel Aviation (Denel Aviation) Registration number: 1992/001337/07 This message and any attachments are confidential and intended solely for the addressee. If you have received this message in error, please notify Denel Aviation immediately, telephone number +27 11 927 1111 and by Reply email to sender. Any unauthorised use, alteration or dissemination of the contents of this email is strictly prohibited. In no event will Denel Aviation or the sender be liable in any manner whatsoever to any person for any loss or any direct, indirect, special or consequential damages arising from use of this email or any linked website, including, without limitation, from any lost profits, business interruption, loss of programmes or other data that may be stored on any information handling system or otherwise from any assurance that this email is virus free even if Denel Aviation is expressly advised of the possibility of such damages.

*******************************************************************************************************

Reply by email

Jonas Maebe
to Unknown author

On 17 Jun 2008, at 10:56, <

Show quoted text 8 lines
wrote: The limited amount of testing done indicates that the record member bit8_1 only causes a problem with a value of $FF, but the interesting thing is that the result varies depending on program structure and compiler version: Different results are seen whith the same code in a procedure, in a 'with' statement, or if there is code in front of it etc. The result is NOT always incorrect.

The problem can occur both when assigning 0 and when assigning field_type(-1). I'll look into fixing it tomorrow.

Jonas

Reply by email

Jonas Maebe
to Jonas Maebe
Jonas Maebe wrote 12 lines
On 17 Jun 2008, at 10:56, < > wrote: > The limited amount of testing done indicates that the record member > bit8_1 only causes a problem with a value of $FF, but the interesting > thing is that the result varies depending on program structure and > compiler version: Different results are seen whith the same code in a > procedure, in a 'with' statement, or if there is code in front of it > etc. The result is NOT always incorrect. The problem can occur both when assigning 0 and when assigning field_type(-1). I'll look into fixing it tomorrow.

Fixed. Note that
a) your test programs were specific to little endian systems (bitpacked records have a different layout on big endian systems) b) the internal layout of bitpacked records is not guaranteed to remain the same over different versions (although there are no particular intentions to change it either)
c) the second test program only defines 15 bits of the packed records, so in the tests when checking for expected results you have to mask out the left over bit (since it can contain garbage) d) there was one error in the second test: if bit9_15 is set to one and the rest to 0, the value of AsWord should be $0200 rather than $0100.

Thanks for the good test programs!

Jonas

Reply by email