Forum > FPC development
Likely incorrect code generation in FPC v3.0.4
440bx:
Hello,
the following simple procedure puts a hex dump of a memory block into a listbox:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure UpdateListbox(ListBoxHex : HWND; BaseAddress : pointer; BlockSize : DWORD); { displays a memory block in hex }const SPACE = $20; { ASCII space character } HEX_DUMP_WIDTH = 16; { number of hex values per line } HexDigits : packed array[0..$F] of char = '0123456789ABCDEF'; var { variables related to the formatting of hex strings to be displayed } Buf : packed array[0..127] of char; { one output line } HexPtr : ^char; { pointer to hex area of line buffer } CharPtr : ^char; { pointer to character area of line buffer } p : PBYTE; { used to walk the memory block } I : DWORD; b : byte; begin { reset the contents of the hex view listbox. Minimize the flicker by } { turning listbox redrawing off while we change its settings. } SendMessage(ListBoxHex, WM_SETREDRAW, ord(FALSE), 0); { redraw off } I := 0; while I < BlockSize do begin FillMemory(@Buf, sizeof(Buf), SPACE); { space out the buffer } { place the offset at the beginning of the line } StrFmt(Buf, ' %p : ', [pointer(pchar(BaseAddress) + I)]); { calculate the pointer value to the start of the hex area in buf } HexPtr := pointer(pchar(@Buf) + lstrlen(Buf)); { calculate the pointer value to the start of the character area } CharPtr := pointer(pchar(HexPtr) + (HEX_DUMP_WIDTH * 3) + 1); repeat pchar(p) := pchar(BaseAddress) + I; { current byte pointer } HexPtr^ := HexDigits[p^ shr 4]; { first nibble } inc(HexPtr); { following lines to demonstrate the problem by comparison } if I = BlockSize - 1 then DebugBreak; b := p^; b := b and $F; HexPtr^ := HexDigits[b]; { problematic statement - occasionally causes an access violation on the last byte of the memory block } HexPtr^ := HexDigits[p^ and $F]; { second nibble } inc(HexPtr); { increment HexPtr again to leave a space between bytes } inc(HexPtr); { if the byte is a printable character then just place it in the char } { area of the buffer, otherwise put a dot instead } if p^ in [32..126] then CharPtr^ := char(p^) { the byte is printable } else CharPtr^ := '.'; { not printable, put a dot } inc(CharPtr); { put an extra space between the first and second half of the hex area } if I mod HEX_DUMP_WIDTH = (HEX_DUMP_WIDTH div 2) - 1 then Inc(HexPtr); inc(I); until (I >= BlockSize) or ((I mod HEX_DUMP_WIDTH) = 0); CharPtr^ := #0; { null terminate the buffer } SendMessage(ListBoxHex, LB_ADDSTRING, 0, ptruint(@Buf)); { add to listbox } end; SendMessage(ListBoxHex, WM_SETREDRAW, ord(TRUE), 0); { redraw on }end; Occasionally, it produces an access violation when accessing the last byte in the block. Inspecting the generated code shows it is as follows:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---32bit generated code (GDB assembler window) MapViewOfFile.lpr:124 b := p^;004019F7 8b8568ffffff mov -0x98(%ebp),%eax // note the BYTE access in the following statement (as it should be) 004019FD 8a00 mov (%eax),%al 004019FF 888560ffffff mov %al,-0xa0(%ebp)MapViewOfFile.lpr:125 b := b and $F;00401A05 668b8560ffffff mov -0xa0(%ebp),%ax00401A0C 66250f00 and $0xf,%ax00401A10 888560ffffff mov %al,-0xa0(%ebp)MapViewOfFile.lpr:126 HexPtr^ := HexDigits[b];00401A16 8b9570ffffff mov -0x90(%ebp),%edx00401A1C 0fb68560ffffff movzbl -0xa0(%ebp),%eax00401A23 8a80c0704200 mov 0x4270c0(%eax),%al00401A29 8802 mov %al,(%edx)MapViewOfFile.lpr:128 HexPtr^ := HexDigits[p^ and $F]; { second nibble }00401A2B 8b8568ffffff mov -0x98(%ebp),%eax // note the WORD access in the following statement (which is incorrect.) 00401A31 668b00 mov (%eax),%ax 00401A34 83e00f and $0xf,%eax00401A37 8b9570ffffff mov -0x90(%ebp),%edx00401A3D 8a80c0704200 mov 0x4270c0(%eax),%al00401A43 8802 mov %al,(%edx) Note that at address 00401A31 the instruction mov (%eax),%ax attempts to retrieve a _word_ instead of a byte, which is what causes a violation when that last byte is also the last accessible byte in the memory block.
Note that when the "operation" is done a step at a time (the first part of the code snippet), the instruction at 004019FD mov (%eax),%al accesses only a byte (as it should.)
The problem is also present in 64bit as the following shows:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---64bit generated code (visual studio debugger) if I = BlockSize - 1 then DebugBreak;0000000100001A86 8B 45 E8 mov eax,dword ptr [BLOCKSIZE] 0000000100001A89 48 8D 50 FF lea rdx,[rax-1] 0000000100001A8D 8B 85 48 FF FF FF mov eax,dword ptr [I] 0000000100001A93 48 39 C2 cmp rdx,rax 0000000100001A96 75 05 jne UPDATELISTBOX+13Dh (0100001A9Dh) 0000000100001A98 E8 63 FA FF FF call public_all+500h (0100001500h) b := p^;0000000100001A9D 48 8B 85 50 FF FF FF mov rax,qword ptr [P] // following statement accesses a byte, which is correct 0000000100001AA4 8A 00 mov al,byte ptr [rax] 0000000100001AA6 88 85 40 FF FF FF mov byte ptr [B],al b := b and $F;0000000100001AAC 80 A5 40 FF FF FF 0F and byte ptr [B],0Fh HexPtr^ := HexDigits[b];0000000100001AB3 48 8B 8D 60 FF FF FF mov rcx,qword ptr [HEXPTR] 0000000100001ABA 0F B6 85 40 FF FF FF movzx eax,byte ptr [B] 0000000100001AC1 48 8D 15 58 A6 02 00 lea rdx,[main+29C50h (010002C120h)] 0000000100001AC8 8A 04 02 mov al,byte ptr [rdx+rax] 0000000100001ACB 88 01 mov byte ptr [rcx],al HexPtr^ := HexDigits[p^ and $F]; { second nibble }0000000100001ACD 48 8B 85 50 FF FF FF mov rax,qword ptr [P] // the following statement accesses a word which is _incorrect_ 0000000100001AD4 66 8B 00 mov ax,word ptr [rax] 0000000100001AD7 66 25 0F 00 and ax,0Fh 0000000100001ADB 0F B7 C0 movzx eax,ax 0000000100001ADE 48 8B 8D 60 FF FF FF mov rcx,qword ptr [HEXPTR] 0000000100001AE5 48 8D 15 34 A6 02 00 lea rdx,[main+29C50h (010002C120h)] 0000000100001AEC 8A 04 02 mov al,byte ptr [rdx+rax] 0000000100001AEF 88 01 mov byte ptr [rcx],al the step-at-a-time instruction
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---0000000100001AA4 8A 00 mov al,byte ptr [rax] is correct whereas the one generated for the array indexing expression is not
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---0000000100001AD4 66 8B 00 mov ax,word ptr [rax]
Note: I have not tested this using any of the trunk versions of FPC. Maybe this bug has been corrected (which would be great) but, just in case it has gone unnoticed, I thought it was worth mentioning.
marcov:
Please try to transform it into a full program (doesn't need to be runnable, just compiling, e.g. a console program calling the function), and then post it to the bugtracker together with params.
One of the devs will then try it on trunk.
440bx:
--- Quote from: marcov on March 04, 2019, 11:02:36 pm ---Please try to transform it into a full program (doesn't need to be runnable, just compiling, e.g. a console program calling the function), and then post it to the bugtracker together with params.
One of the devs will then try it on trunk.
--- End quote ---
I understand the reason for your request but, the real problem is that even with a complete program the problem isn't easy to reproduce because it only happens when the last byte of the memory block happens to also be the last accessible byte in the block.
As I was typing the above, what came to mind is to allocate a 1 page block in the middle of reserved pages. That would ensure that the last byte is also the last accessible byte. I'll post a test program soon (I have something else to take care of right now).
All that said, the expression
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---HexPtr^ := HexDigits[p^ and $F];should NOT generate a word access, if the generated code accesses a word then, it is wrong. p is a pbyte, p^ cannot access a word.
marcov:
--- Quote from: 440bx on March 04, 2019, 11:13:41 pm ---I understand the reason for your request but, the real problem is that even with a complete program the problem isn't easy to reproduce because it only happens when the last byte of the memory block happens to also be the last accessible byte in the block.
--- End quote ---
As said it doesn't have to run or reproduce the crash. Just the 16-bits mov must be visible where it shouldn't in the asm output.
440bx:
--- Quote from: marcov on March 04, 2019, 11:26:01 pm ---As said it doesn't have to run or reproduce the crash. Just the 16-bits mov must be visible where it shouldn't in the asm output.
--- End quote ---
The attached program reliably reproduces the crash and the assembly code clearly shows that a word, instead of a byte, is being accessed.
ETA
reported on Mantis, ticket 0035187
Navigation
[0] Message Index
[#] Next page