Skip Menu |

This queue is for tickets about the Win32-API CPAN distribution.

Report information
The Basics
Id: 107663
Status: open
Priority: 0/
Queue: Win32-API

People
Owner: Nobody in particular
Requestors: amock [...] marvell.com
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in:
  • 0.82
  • 0.83_01
Fixed in: (no value)



Subject: Unpacking of byte array still buggy in 0.83_01
Hi, a few ago I stumbled over the error in Win32API::Struct 0.82 when unpacking a BYTE / UNSIGNED CHAR buffer. After some debugging I found that the buffers are being packed using 'a'.$repeat but got unpacked using 'Z'.$repeat. I'm using plain Strawberry Perl 32 and/or 64 bit on Windows 7 64 bit. "This is perl 5, version 22, subversion 0 (v5.22.0) built for MSWin32-x86-multi-thread-64int" I used Win32::API to access FTDI's FTCJTAG.DLL and imported the DLL functions using the corresponding .h file and Win32::API::more. Great so far! Really easy to import a DLL using the .h file contents. The buffers were declared : Win32::API::Struct->typedef ('WriteDataByteBuffer', qw ( BYTE data[64])); Win32::API::Struct->typedef ('ReadDataByteBuffer', qw ( BYTE data[64])); Win32::API::Struct->typedef ('ReadCmdSequenceDataByteBuffer', qw ( BYTE data[128])); Win32::API::Type->typedef('PWriteDataByteBuffer', 'WriteDataByteBuffer*'); Win32::API::Type->typedef('PReadDataByteBuffer', 'ReadDataByteBuffer*'); Win32::API::Type->typedef('PReadCmdSequenceDataByteBuffer', 'ReadCmdSequenceDataByteBuffer*'); The JTAG_Read function in FTCJTAG.DLL in my case/for my device returns 5 bytes. (4 bytes data DWORD and 1 byte JTAG status bits) unpack ('Z64', $buffer->data) stops unpacking at the first 0 found -> WRONG unpack ('a64', $buffer->data) unpacks all bytes even zeros and pads with 0. I fixed it just by changing Z to a. Then while finishing my tasks and documenting, I found the new version 0.83_01 that tries to fix something unpacking arrays. But unpack ('Z'... for any byte sized array is still wrong, and when fixed by a 'a' then the Win32::API::_TruncateToWideNull($$itemvalueref) later on kills the buffer's values. IMHO the Z is only correct if the buffer contains a Zero terminted string, if the buffer contains any binary data, 'a' is the only valid format specifier for the unpack, because 0s (zeros) are preserved. Padding a zero-terminated string with 0s does not harm, whereas cutting binary data at the first zero is harmful. I would suggest $type = $type_size == 1 ? 'Z'.$repeat #have pack truncate to NULL char :'a'.($repeat*$type_size); #manually truncate to wide NULL char later to be changed to $type = 'a'.($repeat*$type_size); Uuuh I can't find Win32::API::_TruncateToWideNull, but commenting out that line (with type='a'....) solves my problem. WideChars should at least be of original size 2... Open for comments, Axel
On Fri Oct 09 10:29:18 2015, amock@marvell.com wrote: Show quoted text
> Hi, > > a few ago I stumbled over the error in Win32API::Struct 0.82 when > unpacking a BYTE / UNSIGNED CHAR buffer. > After some debugging I found that the buffers are being packed using > 'a'.$repeat but got unpacked using 'Z'.$repeat. > > I'm using plain Strawberry Perl 32 and/or 64 bit on Windows 7 64 bit. > "This is perl 5, version 22, subversion 0 (v5.22.0) built for MSWin32- > x86-multi-thread-64int" > > I used Win32::API to access FTDI's FTCJTAG.DLL and imported the DLL > functions using the corresponding .h file and Win32::API::more. > Great so far! Really easy to import a DLL using the .h file contents. > > The buffers were declared : > Win32::API::Struct->typedef ('WriteDataByteBuffer', qw ( > BYTE data[64])); > Win32::API::Struct->typedef ('ReadDataByteBuffer', qw ( > BYTE data[64])); > Win32::API::Struct->typedef ('ReadCmdSequenceDataByteBuffer', qw ( > BYTE data[128])); > > Win32::API::Type->typedef('PWriteDataByteBuffer', > 'WriteDataByteBuffer*'); > Win32::API::Type->typedef('PReadDataByteBuffer', > 'ReadDataByteBuffer*'); > Win32::API::Type->typedef('PReadCmdSequenceDataByteBuffer', > 'ReadCmdSequenceDataByteBuffer*');
Do not use Win32::API::Struct like that. First Win32::API::Struct is very inefficient. Second you null term problem is because it was sent through Win32::API and you didn't pass a plain string buffer to be written to. Just pad out a regular scalar with as described in http://search.cpan.org/~bulkdd/Win32-API/API.pm#CALLING_AN_IMPORTED_FUNCTION $s = "\x00" x 64; Then declare the func to Win32::API as a char * or P (I prefer P personally), then pass $s to the $api->Call call. Also 64 or 128 bytes is not enough per documents of the C API so I dont think you read them correctly. ---------------------------------------------------------------------------------- FTC_STATUS JTAG_Read (FTC_HANDLE ftHandle, BOOL bInstructionTestData, DWORD dwNumBitsToRead, PReadDataByteBuffer pReadDataBuffer, LPDWORD lpdwNumBytesReturned, DWORD dwTapControllerState) This function reads data from an external device ie a device attached to a FT2232D dual device or FT2232H dual hi-speed device or FT4232H quad hi-speed device. A FT2232D dual device or FT2232H dual hi-speed device or FT4232H quad hi-speed device communicates with an external device by simulating the JTAG synchronous protocol. Parameters ftHandle Handle of a FT2232D dual device or FT2232H dual hi- speed device or FT4232H quad hi-speed device. bInstructionTestData Specifies the type of register, that data is to be read from on an external device. Instruction(TRUE) or test data(FALSE). dwNumBitsToRead Specifies the number of bits to be read from an external device. Valid range 2 to 524280. 524280 bits is equivalent to 64K bytes. pReadDataBuffer Pointer to buffer that returns the data read from an external device. Size of buffer should be set to 65535. ---------------------------------------------------------------------------------- Show quoted text
> The JTAG_Read function in FTCJTAG.DLL in my case/for my device returns > 5 bytes. (4 bytes data DWORD and 1 byte JTAG status bits) > > unpack ('Z64', $buffer->data) stops unpacking at the first 0 found -> > WRONG > > unpack ('a64', $buffer->data) unpacks all bytes even zeros and pads > with 0. > > I fixed it just by changing Z to a. > > Then while finishing my tasks and documenting, I found the new version > 0.83_01 that tries to fix something unpacking arrays. > But unpack ('Z'... for any byte sized array is still wrong, and when > fixed by a 'a' then the > Win32::API::_TruncateToWideNull($$itemvalueref) later on kills the > buffer's values. > > IMHO the Z is only correct if the buffer contains a Zero terminted > string, if the buffer contains any binary data, 'a' is the only valid > format specifier for the unpack, because 0s (zeros) are preserved. > Padding a zero-terminated string with 0s does not harm, whereas > cutting binary data at the first zero is harmful.
How would you extract whether a char array is null termed or not from this struct definition https://msdn.microsoft.com/en-us/library/windows/desktop/aa365740%28v=vs.85%29.aspx for example? C lang does not specify whether a char * is random binary or null terminated. There is no way to know this programmatically from any C prototype (COM does know the different between an array of chars and a string https://msdn.microsoft.com/en-us/library/cc237562.aspx but this module isn't called Win32::COM). Most char *s are printable bytes, not binary data (like a C struct) casted to a char * that is effectively a void *. There are back compat problems that an inline char array in a Win32::API::Struct was already null termed for years. Show quoted text
> I would suggest > $type = $type_size == 1 ? > 'Z'.$repeat #have pack truncate to NULL char > :'a'.($repeat*$type_size); #manually truncate to wide NULL char > later > > to be changed to > $type = 'a'.($repeat*$type_size);
This causes the treatment of char * (null term) and wchar_t *s (not null term) to be different which was one of the issues in https://rt.cpan.org/Ticket/Display.html?id=92971 which I fixed. Show quoted text
> Uuuh I can't find Win32::API::_TruncateToWideNull,
It is undocumented, that is why it has _, it is written in XS.
On Fri Oct 16 19:41:28 2015, BULKDD wrote: Show quoted text
> Do not use Win32::API::Struct like that. First Win32::API::Struct is > very inefficient. Second you**R** null term problem is because it was sent > through Win32::API***STRUCT*** and you didn't pass a plain string buffer to be > written to. Just pad out a regular scalar with as described in > http://search.cpan.org/~bulkdd/Win32- > API/API.pm#CALLING_AN_IMPORTED_FUNCTION
spelling correction