Forum > Windows

The declaration of WriteFile, ReadFile win32 api may be incorrect.

<< < (3/7) > >>

marunguy:
Windows.ReadFile sample source

Windows 10 64bit, Lazarus 2.2.2 64bit, FPC 3.2.2

I'm a lazarus beginner and there may be mistakes in my sample code.

It is not possible to write a Windows.ReadFile sample source that reproduce the crash situation.
It seems to have been moved to the side by the size of the pointer.
However, garbage values are read into the buffer when Windows.ReadFile is called.

* test.txt contents

--- 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";}};} ---01234567890123456789012345678901
* win64 build mode output - Windows.ReadFile

--- 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";}};} ---read_num=32buffer=38 39 30 31 32 33 34 35
* win32 build mode output - Windows.ReadFile

--- 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";}};} ---read_num=32buffer=34 35 36 37 38 39 30 31
* win32/win64 build mode output - MyReadFile

--- 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";}};} ---read_num=32buffer=30 31 32 33 34 35 36 37
* sample code

--- 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";}};} ---unit unitmain; {$mode ObjFPC}{$H+} interface uses    Classes, SysUtils, Windows; function MyReadFile(hFile: THandle; Buffer: Pointer; const nNumberOfBytesToRead: DWORD; lpNumberOfBytesRead: PDWORD; lpOverlapped: POverlapped): BOOL; stdcall; external 'kernel32' name 'ReadFile'; procedure test_readfile(); implementation procedure test_readfile();var    file_hdl: HANDLE = 0;    buffer: array[0..31] of Byte;    ptr: pointer;    read_num: DWORD = 0;begin    file_hdl := Windows.CreateFileW(PWideChar(UnicodeString('test.txt')), GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);    if file_hdl = INVALID_HANDLE_VALUE then    begin        WriteLn(Format('failed to CreateFileW, LE=%d', [GetLastError()]));        exit;    end;     try        ptr := @buffer[0];        if not Windows.ReadFile(file_hdl, ptr, 32, read_num, nil) then        //if not MyReadFile(file_hdl, ptr, 32, @read_num, nil) then        begin            WriteLn(Format('failed to ReadFile, LE=%d', [GetLastError()]));            exit;        end;         WriteLn(Format('read_num=%d', [read_num]));        WriteLn(Format('buffer=%x %x %x %x %x %x %x %x',            [buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]]));    finally        Windows.CloseHandle(file_hdl);    end; end; initialization test_readfile(); end. 

marunguy:

--- Quote from: tetrastes on May 19, 2022, 02:08:53 pm ---
--- Quote from: marunguy on May 19, 2022, 10:25:54 am ---
--- 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";}};} ---Windows.WriteFile(my_hdl, buf, buf_len, written_bytes, nil)Windows.ReadFile(my_hdl, buf, buf_len, read_bytes, nil);
Invalid Buffer value is passed in win64 build mode.
The access viloation exception occurs in win32 build mode when ReadFile is called.

--- End quote ---

You didn't write what were your parameters, and how you passed them exactly.
This is how it is done e.g. in synaser.pas:

--- 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";}};} ---varFHandle: THandle;Buffer: pointer;Length: longint;Result: longint;Overlapped: TOverlapped; ... WriteFile(FHandle, Buffer^, Length, DWord(Result), @Overlapped);ReadFile(FHandle, Buffer^, Length, Dword(Result), @Overlapped);
and it works for more than twenty years without any problem.

--- End quote ---

buf type is pointer in my code;

--- 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";}};} ---buf: pointer;
When modify my code(buf  -> buf^), Windows.WriteFile, ReadFile works correctly.

--- 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";}};} ---Windows.WriteFile(my_hdl, buf^, buf_len, written_bytes, nil)Windows.ReadFile(my_hdl, buf^, buf_len, read_bytes, nil);
But I don't understand the difference between 'buf' and 'buf^'.

440bx:
the problem is in this line of code:
--- 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";}};} ---if not Windows.WriteFile(file_hdl, buffer, Length(buffer), written, nil) then
what that line of code does is pass @buffer to Windows.WriteFile because the parameter is untyped.  That's what causes the address to be passed instead of the value.

if you change that line of code to read:
--- 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";}};} ---if not Windows.WriteFile(file_hdl, buffer^, Length(buffer), written, nil) then(note that buffer is dereferenced, i.e, buffer^, that should work.

The reason it works with "MyWriteFile" is because your definition is _correct_, i.e, the parameter "buffer" is of type pointer (as it should be) instead of untyped.  That causes the value of buffer (which is a pointer) to be passed to MyWriteFile instead of a pointer to the buffer pointer which is what's passed with Windows.WriteFile.



ETA:


--- Quote from: marunguy on May 20, 2022, 10:10:32 am ---But I don't understand the difference between 'buf' and 'buf^'.

--- End quote ---
in the call to Windows.WriteFile, buf^ dereferences buf but since the parameter is untyped what ends up being passed is buf, i.e, @buf^ = buf, which is what should have been passed without all these binary contortions.

In the call to MyWriteFile you can simply pass buf because buf is already a pointer to the buffer and, since your definition is correct (buf is a pointer, not an untyped var), it works. 

In the call to Windows.WriteFile, because the definition automatically takes the address of the variable you are passing, you need to dereference the variable you're passing so that when the address is taken, you end up with the value of the variable, in this case, buf.

marcov:
Note that WriteFileEX does have an overload.

440bx:

--- Quote from: marcov on May 20, 2022, 10:28:29 am ---Note that WriteFileEX does have an overload.

--- End quote ---
WriteFileEx is defined correctly, that is, the buffer  parameter is of type pointer as it should be.  That's one more reason there should be an overload for WriteFile with "Buffer : pointer" because those two functions are supposed to differ _only_ in the fact that WriteFileEx takes an additional parameter but, all the other parameters they have in common should be identical and, currently, they aren't.

OTH, I understand why the FPC definition is the way it is, WriteFile is incorrectly defined in Delphi's Windows.pas (it's an untyped var just as it is in FPC) and, that "deficiency" was replicated in FPC but, definitions like that make porting C code to Pascal quite a headache when they are used (the code is a perfect translation but, it doesn't work in Pascal because the definition is "creative".)

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version