Displaying a UNICODE_STRING

Hi there.

I am fairly new to driver development and have been fighting with this problem for a few days now…Might be really obvious and probably is in my experience but I cannot get a complete UNICODE string to be displayed. Every time I try to output the data I only get the first character ?

I am retreiving a value from the registry and then checking to see what the value contains. The PKEY_VALUE_PARTIAL_INFORMATION structure that I am returning indicates that the data length is 10 but only 1 character of the unicode string is being displayed…

Code snippet…The function below will return the number of the port eg COM1 number returned is 1 and is used in a filter driver but I have now added the driver as a class driver and the port can now be an LPT port or a COM port and so I want to check the full string and if the first 3 chars are COM I know I have a COM port and similarly if they equal LPT I have an LPT port…as a result of this I can return the PortType to the calling function…so I know what I am dealing with…

static NTSTATUS GetPortNumber( PDEVICE_OBJECT pdo, PULONG PortNr, PULONG PortType )
{
NTSTATUS nts = STATUS_SUCCESS;
HANDLE hkey;
*PortNr = -1;

/*
* Open the device registry key for the PDO.
*/
nts = IoOpenDeviceRegistryKey( pdo,
PLUGPLAY_REGKEY_DEVICE,
STANDARD_RIGHTS_READ,
&hkey );

if( NT_SUCCESS( nts ) )
{
UNICODE_STRING us;
ULONG i, size;

/*
* Get size required to store the data.
*/
RtlInitUnicodeString( &us, L"PortName" );

nts = ZwQueryValueKey( hkey,
&us,
KeyValuePartialInformation,
&i,
0,
&size );

if( nts == STATUS_BUFFER_TOO_SMALL )
{
char *sTmp=NULL;

/*
* Allocate the buffer now.
*/
PKEY_VALUE_PARTIAL_INFORMATION pvp =
(PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag( PagedPool,
size,
TAG );

if( pvp )
{
/*
* Get the data.
*/
nts = ZwQueryValueKey( hkey,
&us,
KeyValuePartialInformation,
pvp,
size,
&size );

if( NT_SUCCESS( nts ) )
{
if( pvp->DataLength > 6 )
{
KdPrint((“In getPortNo, data length is %d\n”, pvp->DataLength));

******** THIS next call always displays the first char only of the UNICODE string. “L” or “C”.

KdPrint((“%s - PORT NAME is %wZ\n”, DRIVERNAME, pvp->Data ));
/*
* Extract the number element from the port name. “COMnnn”
*/
us.Length = us.MaximumLength = (USHORT)pvp->DataLength - 6;
us.Buffer = (PWSTR)(pvp->Data + 6);
RtlUnicodeStringToInteger( &us, 10, PortNr );

/*
* Temp debug code…??? trying to work out why UNICODE string not being displayed correcly.
*/
sTmp = (char*)ExAllocatePoolWithTag( PagedPool,
pvp->DataLength+1,
TAG );

strncpy(sTmp, (char*)&pvp->Data[0], pvp->DataLength);
KdPrint((“%s - PORT NAME is %c%c%c \n”, DRIVERNAME, sTmp[0],sTmp[1],sTmp[2] ));

if( strncmp( sTmp, “LPT”, 3 ) == 0 )
{
KdPrint((“Got an LPT port!!!\n”));
*PortType = LPT_PORT;
}
else
{
*PortType = COM_PORT;
KdPrint((“Got a COM port !!!\n”));
}

}/* if */

}/* if - NT_SUCCESS( nts ) */

/*
* Free any memory used.
*/
ExFreePool( pvp );

}/* if - pvp */

}/* if - nts == STATUS_BUFFER_TOO_SMALL */

/*
* Close the file handle.
*/
ZwClose( hkey );

}/* if - NT_SUCCESS( nts ) */

/*
* If we didn’t have success along the way…
*/
if( nts != STATUS_SUCCESS )
{
KdPrint( ( “%s - GetPortNumber(%u) 0x%X.\n”, DRIVERNAME, *PortNr, nts ) );
}

return nts;

}/* End of GetPortNumber */

Much apprectiate for any ideas why this is not displaying the string correctly…
and apologies if I have done something really stupid ! I just can’t see it …! Doh.

Regards

For debug prints you need %wZ for a UNICODE_STRING. The %Z is for counted
strings, and the “w” indicates wide (i.e. unicode).

–
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply

wrote in message news:xxxxx@ntdev…
> Hi there.
>
> I am fairly new to driver development and have been fighting with this
> problem for a few days now…Might be really obvious and probably is in my
> experience but I cannot get a complete UNICODE string to be displayed.
> Every time I try to output the data I only get the first character ?
>
> I am retreiving a value from the registry and then checking to see what
> the value contains. The PKEY_VALUE_PARTIAL_INFORMATION structure that I
> am returning indicates that the data length is 10 but only 1 character of
> the unicode string is being displayed…
>
> Code snippet…The function below will return the number of the port eg
> COM1 number returned is 1 and is used in a filter driver but I have now
> added the driver as a class driver and the port can now be an LPT port or
> a COM port and so I want to check the full string and if the first 3 chars
> are COM I know I have a COM port and similarly if they equal LPT I have an
> LPT port…as a result of this I can return the PortType to the calling
> function…so I know what I am dealing with…
>
> static NTSTATUS GetPortNumber( PDEVICE_OBJECT pdo, PULONG PortNr, PULONG
> PortType )
> {
> NTSTATUS nts = STATUS_SUCCESS;
> HANDLE hkey;
> PortNr = -1;
>
> /

> * Open the device registry key for the PDO.
> /
> nts = IoOpenDeviceRegistryKey( pdo,
> PLUGPLAY_REGKEY_DEVICE,
> STANDARD_RIGHTS_READ,
> &hkey );
>
> if( NT_SUCCESS( nts ) )
> {
> UNICODE_STRING us;
> ULONG i, size;
>
> /

> * Get size required to store the data.
> /
> RtlInitUnicodeString( &us, L"PortName" );
>
> nts = ZwQueryValueKey( hkey,
> &us,
> KeyValuePartialInformation,
> &i,
> 0,
> &size );
>
> if( nts == STATUS_BUFFER_TOO_SMALL )
> {
> char sTmp=NULL;
>
> /

> * Allocate the buffer now.
> /
> PKEY_VALUE_PARTIAL_INFORMATION pvp =
> (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(
> PagedPool,
> size,
> TAG );
>
> if( pvp )
> {
> /

> * Get the data.
> /
> nts = ZwQueryValueKey( hkey,
> &us,
> KeyValuePartialInformation,
> pvp,
> size,
> &size );
>
> if( NT_SUCCESS( nts ) )
> {
> if( pvp->DataLength > 6 )
> {
> KdPrint((“In getPortNo, data length is %d\n”, pvp->DataLength));
>
> ******** THIS next call always displays the first char only of the UNICODE
> string. “L” or “C”.
>
>
> KdPrint((“%s - PORT NAME is %wZ\n”, DRIVERNAME, pvp->Data ));
> /

> * Extract the number element from the port name.
> “COMnnn”
> /
> us.Length = us.MaximumLength = (USHORT)pvp->DataLength -
> 6;
> us.Buffer = (PWSTR)(pvp->Data + 6);
> RtlUnicodeStringToInteger( &us, 10, PortNr );
>
> /

> * Temp debug code…??? trying to work out why UNICODE
> string not being displayed correcly.
> /
> sTmp = (char
)ExAllocatePoolWithTag( PagedPool,
> pvp->DataLength+1,
> TAG );
>
> strncpy(sTmp, (char
)&pvp->Data[0], pvp->DataLength);
> KdPrint((“%s - PORT NAME is %c%c%c \n”, DRIVERNAME,
> sTmp[0],sTmp[1],sTmp[2] ));
>
> if( strncmp( sTmp, “LPT”, 3 ) == 0 )
> {
> KdPrint((“Got an LPT port!!!\n”));
> *PortType = LPT_PORT;
> }
> else
> {
> PortType = COM_PORT;
> KdPrint((“Got a COM port !!!\n”));
> }
>
> }/
if /
>
> }/
if - NT_SUCCESS( nts ) /
>
> /

> * Free any memory used.
> /
> ExFreePool( pvp );
>
> }/
if - pvp /
>
> }/
if - nts == STATUS_BUFFER_TOO_SMALL /
>
> /

> * Close the file handle.
> /
> ZwClose( hkey );
>
> }/
if - NT_SUCCESS( nts ) /
>
> /

> * If we didn’t have success along the way…
> */
> if( nts != STATUS_SUCCESS )
> {
> KdPrint( ( “%s - GetPortNumber(%u) 0x%X.\n”, DRIVERNAME, PortNr,
> nts ) );
> }
>
> return nts;
>
> }/
End of GetPortNumber */
>
>
>
> Much apprectiate for any ideas why this is not displaying the string
> correctly…
> and apologies if I have done something really stupid ! I just can’t see
> it …! Doh.
>
> Regards
>
>
>

Pass PUNICODE_STRING to KdPrint with the %wZ format spec.

–
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

wrote in message news:xxxxx@ntdev…
> Hi there.
>
> I am fairly new to driver development and have been fighting with this
problem for a few days now…Might be really obvious and probably is in my
experience but I cannot get a complete UNICODE string to be displayed. Every
time I try to output the data I only get the first character ?
>
> I am retreiving a value from the registry and then checking to see what the
value contains. The PKEY_VALUE_PARTIAL_INFORMATION structure that I am
returning indicates that the data length is 10 but only 1 character of the
unicode string is being displayed…
>
> Code snippet…The function below will return the number of the port eg COM1
number returned is 1 and is used in a filter driver but I have now added the
driver as a class driver and the port can now be an LPT port or a COM port and
so I want to check the full string and if the first 3 chars are COM I know I
have a COM port and similarly if they equal LPT I have an LPT port…as a
result of this I can return the PortType to the calling function…so I know
what I am dealing with…
>
> static NTSTATUS GetPortNumber( PDEVICE_OBJECT pdo, PULONG PortNr, PULONG
PortType )
> {
> NTSTATUS nts = STATUS_SUCCESS;
> HANDLE hkey;
> PortNr = -1;
>
> /

> * Open the device registry key for the PDO.
> /
> nts = IoOpenDeviceRegistryKey( pdo,
> PLUGPLAY_REGKEY_DEVICE,
> STANDARD_RIGHTS_READ,
> &hkey );
>
> if( NT_SUCCESS( nts ) )
> {
> UNICODE_STRING us;
> ULONG i, size;
>
> /

> * Get size required to store the data.
> /
> RtlInitUnicodeString( &us, L"PortName" );
>
> nts = ZwQueryValueKey( hkey,
> &us,
> KeyValuePartialInformation,
> &i,
> 0,
> &size );
>
> if( nts == STATUS_BUFFER_TOO_SMALL )
> {
> char sTmp=NULL;
>
> /

> * Allocate the buffer now.
> /
> PKEY_VALUE_PARTIAL_INFORMATION pvp =
> (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag( PagedPool,
> size,
> TAG );
>
> if( pvp )
> {
> /

> * Get the data.
> /
> nts = ZwQueryValueKey( hkey,
> &us,
> KeyValuePartialInformation,
> pvp,
> size,
> &size );
>
> if( NT_SUCCESS( nts ) )
> {
> if( pvp->DataLength > 6 )
> {
> KdPrint((“In getPortNo, data length is %d\n”, pvp->DataLength));
>
> ******** THIS next call always displays the first char only of the UNICODE
string. “L” or “C”.
>
>
> KdPrint((“%s - PORT NAME is %wZ\n”, DRIVERNAME, pvp->Data ));
> /

> * Extract the number element from the port name. “COMnnn”
> /
> us.Length = us.MaximumLength = (USHORT)pvp->DataLength - 6;
> us.Buffer = (PWSTR)(pvp->Data + 6);
> RtlUnicodeStringToInteger( &us, 10, PortNr );
>
> /

> * Temp debug code…??? trying to work out why UNICODE
string not being displayed correcly.
> /
> sTmp = (char
)ExAllocatePoolWithTag( PagedPool,
> pvp->DataLength+1,
> TAG );
>
> strncpy(sTmp, (char
)&pvp->Data[0], pvp->DataLength);
> KdPrint((“%s - PORT NAME is %c%c%c \n”, DRIVERNAME,
sTmp[0],sTmp[1],sTmp[2] ));
>
> if( strncmp( sTmp, “LPT”, 3 ) == 0 )
> {
> KdPrint((“Got an LPT port!!!\n”));
> *PortType = LPT_PORT;
> }
> else
> {
> PortType = COM_PORT;
> KdPrint((“Got a COM port !!!\n”));
> }
>
> }/
if /
>
> }/
if - NT_SUCCESS( nts ) /
>
> /

> * Free any memory used.
> /
> ExFreePool( pvp );
>
> }/
if - pvp /
>
> }/
if - nts == STATUS_BUFFER_TOO_SMALL /
>
> /

> * Close the file handle.
> /
> ZwClose( hkey );
>
> }/
if - NT_SUCCESS( nts ) /
>
> /

> * If we didn’t have success along the way…
> */
> if( nts != STATUS_SUCCESS )
> {
> KdPrint( ( “%s - GetPortNumber(%u) 0x%X.\n”, DRIVERNAME, PortNr,
nts ) );
> }
>
> return nts;
>
> }/
End of GetPortNumber */
>
>
>
> Much apprectiate for any ideas why this is not displaying the string
correctly…
> and apologies if I have done something really stupid ! I just can’t see it
…! Doh.
>
> Regards
>
>
>

FYI pvp->Data is not a UNICODE_STRING, it is an array of WCHAR.

Two ways to print this out.

  1. Have a proper UNICODE_STRING struct available and use:

unicodeString.Length = unicodeString.MaximumLength = pvp->DataLength.

KdPrint ((“PortName is: %wZ\n”, &unicodeString));

  1. Create a nul-terminated string of WCHARs

PWCHAR pWideString;

pWideString = ExAllocatePool (xxxx, pvp->DataLength + sizeof (WCHAR));
RtlZeroMemory (pWideString, pvp->DataLength + sizeof (WCHAR));
RtlCopyMemory (pWideString, pvp->Data, pvp->DataLength);

KdPrint ((“PortName is: %S\n”, pWideString));

Solution 2 would be frowned upon since it relies on the programmer to
create a large enough buffer to include the nul-terminator.

Mark,

At 15:04 18/03/2008, xxxxx@baesystems.com wrote:

Hi there.

I am fairly new to driver development and have been fighting with
this problem for a few days now…Might be really obvious and
probably is in my experience but I cannot get a complete UNICODE
string to be displayed. Every time I try to output the data I only
get the first character ?

I am retreiving a value from the registry and then checking to see
what the value contains. The PKEY_VALUE_PARTIAL_INFORMATION
structure that I am returning indicates that the data length is 10
but only 1 character of the unicode string is being displayed…

Code snippet…The function below will return the number of the
port eg COM1 number returned is 1 and is used in a filter driver but
I have now added the driver as a class driver and the port can now
be an LPT port or a COM port and so I want to check the full string
and if the first 3 chars are COM I know I have a COM port and
similarly if they equal LPT I have an LPT port…as a result of
this I can return the PortType to the calling function…so I know
what I am dealing with…

static NTSTATUS GetPortNumber( PDEVICE_OBJECT pdo, PULONG PortNr,
PULONG PortType )
{
NTSTATUS nts = STATUS_SUCCESS;
HANDLE hkey;
*PortNr = -1;

/*
* Open the device registry key for the PDO.
*/
nts = IoOpenDeviceRegistryKey( pdo,
PLUGPLAY_REGKEY_DEVICE,
STANDARD_RIGHTS_READ,
&hkey );

if( NT_SUCCESS( nts ) )
{
UNICODE_STRING us;
ULONG i, size;

/*
* Get size required to store the data.
*/
RtlInitUnicodeString( &us, L"PortName" );

nts = ZwQueryValueKey( hkey,
&us,
KeyValuePartialInformation,
&i,
0,
&size );

if( nts == STATUS_BUFFER_TOO_SMALL )
{
char *sTmp=NULL;

/*
* Allocate the buffer now.
*/
PKEY_VALUE_PARTIAL_INFORMATION pvp =
(PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(
PagedPool,
size,
TAG );

if( pvp )
{
/*
* Get the data.
*/
nts = ZwQueryValueKey( hkey,
&us,
KeyValuePartialInformation,
pvp,
size,
&size );

if( NT_SUCCESS( nts ) )
{
if( pvp->DataLength > 6 )
{
KdPrint((“In getPortNo, data length is %d\n”, pvp->DataLength));

******** THIS next call always displays the first char only of the
UNICODE string. “L” or “C”.

KdPrint((“%s - PORT NAME is %wZ\n”, DRIVERNAME, pvp->Data ));
/*
* Extract the number element from the port name. “COMnnn”
*/
us.Length = us.MaximumLength = (USHORT)pvp->DataLength - 6;
us.Buffer = (PWSTR)(pvp->Data + 6);
RtlUnicodeStringToInteger( &us, 10, PortNr );

/*
* Temp debug code…??? trying to work out why
UNICODE string not being displayed correcly.
*/
sTmp = (char*)ExAllocatePoolWithTag( PagedPool,
pvp->DataLength+1,
TAG );

strncpy(sTmp, (char*)&pvp->Data[0], pvp->DataLength);
KdPrint((“%s - PORT NAME is %c%c%c \n”,
DRIVERNAME, sTmp[0],sTmp[1],sTmp[2] ));

if( strncmp( sTmp, “LPT”, 3 ) == 0 )
{
KdPrint((“Got an LPT port!!!\n”));
*PortType = LPT_PORT;
}
else
{
*PortType = COM_PORT;
KdPrint((“Got a COM port !!!\n”));
}

}/* if */

}/* if - NT_SUCCESS( nts ) */

/*
* Free any memory used.
*/
ExFreePool( pvp );

}/* if - pvp */

}/* if - nts == STATUS_BUFFER_TOO_SMALL */

/*
* Close the file handle.
*/
ZwClose( hkey );

}/* if - NT_SUCCESS( nts ) */

/*
* If we didn’t have success along the way…
*/
if( nts != STATUS_SUCCESS )
{
KdPrint( ( “%s - GetPortNumber(%u) 0x%X.\n”, DRIVERNAME,
*PortNr, nts ) );
}

return nts;

}/* End of GetPortNumber */

Much apprectiate for any ideas why this is not displaying the string
correctly…
and apologies if I have done something really stupid ! I just can’t
see it …! Doh.

Regards


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Is this a UNICODE_STRING or just a REG_SZ? You’re kind of treating it
as both:

this:

KdPrint((“%s - PORT NAME is %wZ\n”, DRIVERNAME, pvp->Data ));

would be used for a UNICODE_STRING (%wZ).

but:

strncpy(sTmp, (char*)&pvp->Data[0], pvp->DataLength);

would indicate that is is a REG_SZ/PWSTR, except that you’re now mixing
ANSI/UNICODE.

You’ve kind of confused me, but I don’t think that what you’re reading
is a a ‘UNICODE_STRING,’ but rather a ‘UNICODE string.’ I think all you
need is something like KdPrint((“%S”, pvp->Data). Be aware, that
because of the UNICODE, you can only call this at IRQL=PASSIVE_LEVEL.

Good luck,

mm

xxxxx@baesystems.com wrote:

Hi there.

I am fairly new to driver development and have been fighting with this problem for a few days now…Might be really obvious and probably is in my experience but I cannot get

a complete UNICODE string to be displayed. Every time I try to output
the data I only get the first character ?

I am retreiving a value from the registry and then checking to see what the value contains. The PKEY_VALUE_PARTIAL_INFORMATION structure that I

am returning indicates that the data length is 10 but only 1 character
of the unicode string is being displayed…

Code snippet…The function below will return the number of the port eg COM1 number returned is 1 and is used in a filter driver but I have now added the driver as a class driver and the port can now be an LPT port or a COM port and so I want to check the full string and if the first 3 chars are COM I know I have a COM port and similarly if they equal LPT I have an LPT port…as a result of this I can return the PortType to the calling function…so I know what I am dealing with…

static NTSTATUS GetPortNumber( PDEVICE_OBJECT pdo, PULONG PortNr, PULONG PortType )
{
NTSTATUS nts = STATUS_SUCCESS;
HANDLE hkey;
*PortNr = -1;

/*
* Open the device registry key for the PDO.
*/
nts = IoOpenDeviceRegistryKey( pdo,
PLUGPLAY_REGKEY_DEVICE,
STANDARD_RIGHTS_READ,
&hkey );

if( NT_SUCCESS( nts ) )
{
UNICODE_STRING us;
ULONG i, size;

/*
* Get size required to store the data.
*/
RtlInitUnicodeString( &us, L"PortName" );

nts = ZwQueryValueKey( hkey,
&us,
KeyValuePartialInformation,
&i,
0,
&size );

if( nts == STATUS_BUFFER_TOO_SMALL )
{
char *sTmp=NULL;

/*
* Allocate the buffer now.
*/
PKEY_VALUE_PARTIAL_INFORMATION pvp =
(PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag( PagedPool,
size,
TAG );

if( pvp )
{
/*
* Get the data.
*/
nts = ZwQueryValueKey( hkey,
&us,
KeyValuePartialInformation,
pvp,
size,
&size );

if( NT_SUCCESS( nts ) )
{
if( pvp->DataLength > 6 )
{
KdPrint((“In getPortNo, data length is %d\n”, pvp->DataLength));

******** THIS next call always displays the first char only of the UNICODE string. “L” or “C”.

KdPrint((“%s - PORT NAME is %wZ\n”, DRIVERNAME, pvp->Data ));
/*
* Extract the number element from the port name. “COMnnn”
*/
us.Length = us.MaximumLength = (USHORT)pvp->DataLength - 6;
us.Buffer = (PWSTR)(pvp->Data + 6);
RtlUnicodeStringToInteger( &us, 10, PortNr );

/*
* Temp debug code…??? trying to work out why UNICODE string not being displayed correcly.
*/
sTmp = (char*)ExAllocatePoolWithTag( PagedPool,
pvp->DataLength+1,
TAG );

strncpy(sTmp, (char*)&pvp->Data[0], pvp->DataLength);
KdPrint((“%s - PORT NAME is %c%c%c \n”, DRIVERNAME, sTmp[0],sTmp[1],sTmp[2] ));

if( strncmp( sTmp, “LPT”, 3 ) == 0 )
{
KdPrint((“Got an LPT port!!!\n”));
*PortType = LPT_PORT;
}
else
{
*PortType = COM_PORT;
KdPrint((“Got a COM port !!!\n”));
}

}/* if */

}/* if - NT_SUCCESS( nts ) */

/*
* Free any memory used.
*/
ExFreePool( pvp );

}/* if - pvp */

}/* if - nts == STATUS_BUFFER_TOO_SMALL */

/*
* Close the file handle.
*/
ZwClose( hkey );

}/* if - NT_SUCCESS( nts ) */

/*
* If we didn’t have success along the way…
*/
if( nts != STATUS_SUCCESS )
{
KdPrint( ( “%s - GetPortNumber(%u) 0x%X.\n”, DRIVERNAME, *PortNr, nts ) );
}

return nts;

}/* End of GetPortNumber */

Much apprectiate for any ideas why this is not displaying the string correctly…
and apologies if I have done something really stupid ! I just can’t see it …! Doh.

Regards

Ooops - missed out the line:

unicodeString.Buffer = (PWCHAR) &pvp->Data[0];

For solution 1.

FYI pvp->Data is not a UNICODE_STRING, it is an array of WCHAR.

Two ways to print this out.

  1. Have a proper UNICODE_STRING struct available and use:

unicodeString.Length = unicodeString.MaximumLength = pvp->DataLength.

KdPrint ((“PortName is: %wZ\n”, &unicodeString));

  1. Create a nul-terminated string of WCHARs

PWCHAR pWideString;

pWideString = ExAllocatePool (xxxx, pvp->DataLength + sizeof (WCHAR));
RtlZeroMemory (pWideString, pvp->DataLength + sizeof (WCHAR));
RtlCopyMemory (pWideString, pvp->Data, pvp->DataLength);

KdPrint ((“PortName is: %S\n”, pWideString));

Solution 2 would be frowned upon since it relies on the programmer to
create a large enough buffer to include the nul-terminator.

Mark,

You had the same thought I did, Mark, but I thought that registry
strings were already null terminated (i. e. - REG_SZ)? If not, then
what I wrote will not work.

Thanks,

mm

Mark S. Edwards wrote:

FYI pvp->Data is not a UNICODE_STRING, it is an array of WCHAR.

Two ways to print this out.

  1. Have a proper UNICODE_STRING struct available and use:

unicodeString.Length = unicodeString.MaximumLength = pvp->DataLength.

KdPrint ((“PortName is: %wZ\n”, &unicodeString));

  1. Create a nul-terminated string of WCHARs

PWCHAR pWideString;

pWideString = ExAllocatePool (xxxx, pvp->DataLength + sizeof (WCHAR));
RtlZeroMemory (pWideString, pvp->DataLength + sizeof (WCHAR));
RtlCopyMemory (pWideString, pvp->Data, pvp->DataLength);

KdPrint ((“PortName is: %S\n”, pWideString));

Solution 2 would be frowned upon since it relies on the programmer to
create a large enough buffer to include the nul-terminator.

Mark,

At 15:04 18/03/2008, xxxxx@baesystems.com wrote:
> Hi there.
>
> I am fairly new to driver development and have been fighting with this
> problem for a few days now…Might be really obvious and probably is
> in my experience but I cannot get a complete UNICODE string to be
> displayed. Every time I try to output the data I only get the first
> character ?
>
> I am retreiving a value from the registry and then checking to see
> what the value contains. The PKEY_VALUE_PARTIAL_INFORMATION
> structure that I am returning indicates that the data length is 10 but
> only 1 character of the unicode string is being displayed…
>
> Code snippet…The function below will return the number of the port
> eg COM1 number returned is 1 and is used in a filter driver but I have
> now added the driver as a class driver and the port can now be an LPT
> port or a COM port and so I want to check the full string and if the
> first 3 chars are COM I know I have a COM port and similarly if they
> equal LPT I have an LPT port…as a result of this I can return the
> PortType to the calling function…so I know what I am dealing with…
>
> static NTSTATUS GetPortNumber( PDEVICE_OBJECT pdo, PULONG PortNr,
> PULONG PortType )
> {
> NTSTATUS nts = STATUS_SUCCESS;
> HANDLE hkey;
> *PortNr = -1;
>
> /*
> * Open the device registry key for the PDO.
> */
> nts = IoOpenDeviceRegistryKey( pdo,
> PLUGPLAY_REGKEY_DEVICE,
> STANDARD_RIGHTS_READ,
> &hkey );
>
> if( NT_SUCCESS( nts ) )
> {
> UNICODE_STRING us;
> ULONG i, size;
>
> /*
> * Get size required to store the data.
> */
> RtlInitUnicodeString( &us, L"PortName" );
>
> nts = ZwQueryValueKey( hkey,
> &us,
> KeyValuePartialInformation,
> &i,
> 0,
> &size );
>
> if( nts == STATUS_BUFFER_TOO_SMALL )
> {
> char *sTmp=NULL;
>
> /*
> * Allocate the buffer now.
> */
> PKEY_VALUE_PARTIAL_INFORMATION pvp =
> (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(
> PagedPool,
> size,
> TAG );
>
> if( pvp )
> {
> /*
> * Get the data.
> */
> nts = ZwQueryValueKey( hkey,
> &us,
> KeyValuePartialInformation,
> pvp,
> size,
> &size );
>
> if( NT_SUCCESS( nts ) )
> {
> if( pvp->DataLength > 6 )
> {
> KdPrint((“In getPortNo, data length is %d\n”, pvp->DataLength));
>
> ******** THIS next call always displays the first char only of the
> UNICODE string. “L” or “C”.
>
>
> KdPrint((“%s - PORT NAME is %wZ\n”, DRIVERNAME, pvp->Data ));
> /*
> * Extract the number element from the port name.
> “COMnnn”
> */
> us.Length = us.MaximumLength =
> (USHORT)pvp->DataLength - 6;
> us.Buffer = (PWSTR)(pvp->Data + 6);
> RtlUnicodeStringToInteger( &us, 10, PortNr );
>
> /*
> * Temp debug code…??? trying to work out why
> UNICODE string not being displayed correcly.
> */
> sTmp = (char*)ExAllocatePoolWithTag( PagedPool,
> pvp->DataLength+1,
> TAG );
>
> strncpy(sTmp, (char*)&pvp->Data[0], pvp->DataLength);
> KdPrint((“%s - PORT NAME is %c%c%c \n”, DRIVERNAME,
> sTmp[0],sTmp[1],sTmp[2] ));
>
> if( strncmp( sTmp, “LPT”, 3 ) == 0 )
> {
> KdPrint((“Got an LPT port!!!\n”));
> *PortType = LPT_PORT;
> }
> else
> {
> *PortType = COM_PORT;
> KdPrint((“Got a COM port !!!\n”));
> }
>
> }/* if */
>
> }/* if - NT_SUCCESS( nts ) */
>
> /*
> * Free any memory used.
> */
> ExFreePool( pvp );
>
> }/* if - pvp */
>
> }/* if - nts == STATUS_BUFFER_TOO_SMALL */
>
> /*
> * Close the file handle.
> */
> ZwClose( hkey );
>
> }/* if - NT_SUCCESS( nts ) */
>
> /*
> * If we didn’t have success along the way…
> */
> if( nts != STATUS_SUCCESS )
> {
> KdPrint( ( “%s - GetPortNumber(%u) 0x%X.\n”, DRIVERNAME,
> *PortNr, nts ) );
> }
>
> return nts;
>
> }/* End of GetPortNumber */
>
>
>
> Much apprectiate for any ideas why this is not displaying the string
> correctly…
> and apologies if I have done something really stupid ! I just can’t
> see it …! Doh.
>
> Regards
>
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer

At 15:32 18/03/2008, Martin O’Brien wrote:

You had the same thought I did, Mark, but I thought that registry
strings were already null terminated (i. e. - REG_SZ)? If not, then
what I wrote will not work.

Thanks,

mm

Couldn’t remember if they were terminated or not, experience says
that these days most strings returned in a counted buffer probably
are not null terminated, but there are some exceptions.

Easiest to play safe and always make sure there’s a terminator,
especially in these times when we’re all encouraged not to leave
ourselves open to buffer overflow attacks.

But then I’ve probably been just as guilty as anyone in using
(“%S\n”) when in quick debug mode :wink:

Mark.

REG_SZ and REG_EXPAND_SZ are not guaranteed to be null terminated in either user or kernel mode. REG_MULTI_SZ is not not guaranteed to be double null terminated either. The registry, just like the io manager, is “fast and dumb” (as peter so eloquently put it) and does not validate the buffer against the type when you set the value.

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Mark S. Edwards
Sent: Tuesday, March 18, 2008 8:44 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Displaying a UNICODE_STRING

At 15:32 18/03/2008, Martin O’Brien wrote:

You had the same thought I did, Mark, but I thought that registry
strings were already null terminated (i. e. - REG_SZ)? If not, then
what I wrote will not work.

Thanks,

mm

Couldn’t remember if they were terminated or not, experience says
that these days most strings returned in a counted buffer probably
are not null terminated, but there are some exceptions.

Easiest to play safe and always make sure there’s a terminator,
especially in these times when we’re all encouraged not to leave
ourselves open to buffer overflow attacks.

But then I’ve probably been just as guilty as anyone in using
(“%S\n”) when in quick debug mode :wink:

Mark.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Thanks, Doron. Someone need to fix the documentation (6001.18000 WDK):

“REG_SZ A null-terminated Unicode string”

mm

Doron Holan wrote:

REG_SZ and REG_EXPAND_SZ are not guaranteed to be null terminated in either user or kernel mode. REG_MULTI_SZ is not not guaranteed to be double null terminated either. The registry, just like the io manager, is “fast and dumb” (as peter so eloquently put it) and does not validate the buffer against the type when you set the value.

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Mark S. Edwards
Sent: Tuesday, March 18, 2008 8:44 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Displaying a UNICODE_STRING

At 15:32 18/03/2008, Martin O’Brien wrote:
> You had the same thought I did, Mark, but I thought that registry
> strings were already null terminated (i. e. - REG_SZ)? If not, then
> what I wrote will not work.
>
> Thanks,
>
>
> mm

Couldn’t remember if they were terminated or not, experience says
that these days most strings returned in a counted buffer probably
are not null terminated, but there are some exceptions.

Easiest to play safe and always make sure there’s a terminator,
especially in these times when we’re all encouraged not to leave
ourselves open to buffer overflow attacks.

But then I’ve probably been just as guilty as anyone in using
(“%S\n”) when in quick debug mode :wink:

Mark.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Martin O’Brien wrote:

Thanks, Doron. Someone need to fix the documentation (6001.18000 WDK):

“REG_SZ A null-terminated Unicode string”

Oh, they are SUPPOSED to contain null-terminated strings. However, the
registry data types are nothing but another piece of data associated
with the value. There is nothing that enforces the data types. You can
shove whatever random data you want in a REG_SZ, or a REG_MULTI_SZ, and
the registry will happily store it.

I think what Doron is saying is “caveat emptor”.

–
Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

My recollection is that the Win32 routines take a null terminated string and
store it, including the null. When you query the value in kernel mode, you
get back the null terminated string, including the null, with length of the
data also including the null.

In kernel mode (or with native user mode routines), I’m pretty sure it’s
possible to store a REG_SZ without the null, which is likely to screw up a
lot of applications. It will also screw up drivers that don’t do the right
thing.

However, depending on where you got the quote below, I might argue against
changing the doc. If it has to do with setting the value, then it is the
case that it SHOULD be null terminated.

  • Dan.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Martin O’Brien
Sent: Tuesday, March 18, 2008 4:20 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Displaying a UNICODE_STRING

Thanks, Doron. Someone need to fix the documentation (6001.18000 WDK):

“REG_SZ A null-terminated Unicode string”

mm

Doron Holan wrote:

REG_SZ and REG_EXPAND_SZ are not guaranteed to be null terminated in
either user or kernel mode. REG_MULTI_SZ is not not guaranteed to be double
null terminated either. The registry, just like the io manager, is “fast
and dumb” (as peter so eloquently put it) and does not validate the buffer
against the type when you set the value.

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Mark S.
Edwards
Sent: Tuesday, March 18, 2008 8:44 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Displaying a UNICODE_STRING

At 15:32 18/03/2008, Martin O’Brien wrote:
> You had the same thought I did, Mark, but I thought that registry
> strings were already null terminated (i. e. - REG_SZ)? If not, then
> what I wrote will not work.
>
> Thanks,
>
>
> mm

Couldn’t remember if they were terminated or not, experience says that
these days most strings returned in a counted buffer probably are not
null terminated, but there are some exceptions.

Easiest to play safe and always make sure there’s a terminator,
especially in these times when we’re all encouraged not to leave
ourselves open to buffer overflow attacks.

But then I’ve probably been just as guilty as anyone in using
(“%S\n”) when in quick debug mode :wink:

Mark.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

I am pretty sure the UM apis just thunk to the native w/out additional validation. IIRC, RegGetValue will validate the results for you. The docs already call out that the string data may not be null terminated, although it is a little buried, http://msdn2.microsoft.com/en-us/library/ms724884.aspx

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Dan Kyler
Sent: Tuesday, March 18, 2008 4:16 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] Displaying a UNICODE_STRING

My recollection is that the Win32 routines take a null terminated string and
store it, including the null. When you query the value in kernel mode, you
get back the null terminated string, including the null, with length of the
data also including the null.

In kernel mode (or with native user mode routines), I’m pretty sure it’s
possible to store a REG_SZ without the null, which is likely to screw up a
lot of applications. It will also screw up drivers that don’t do the right
thing.

However, depending on where you got the quote below, I might argue against
changing the doc. If it has to do with setting the value, then it is the
case that it SHOULD be null terminated.

  • Dan.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Martin O’Brien
Sent: Tuesday, March 18, 2008 4:20 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Displaying a UNICODE_STRING

Thanks, Doron. Someone need to fix the documentation (6001.18000 WDK):

“REG_SZ A null-terminated Unicode string”

mm

Doron Holan wrote:

REG_SZ and REG_EXPAND_SZ are not guaranteed to be null terminated in
either user or kernel mode. REG_MULTI_SZ is not not guaranteed to be double
null terminated either. The registry, just like the io manager, is “fast
and dumb” (as peter so eloquently put it) and does not validate the buffer
against the type when you set the value.

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Mark S.
Edwards
Sent: Tuesday, March 18, 2008 8:44 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Displaying a UNICODE_STRING

At 15:32 18/03/2008, Martin O’Brien wrote:
> You had the same thought I did, Mark, but I thought that registry
> strings were already null terminated (i. e. - REG_SZ)? If not, then
> what I wrote will not work.
>
> Thanks,
>
>
> mm

Couldn’t remember if they were terminated or not, experience says that
these days most strings returned in a counted buffer probably are not
null terminated, but there are some exceptions.

Easiest to play safe and always make sure there’s a terminator,
especially in these times when we’re all encouraged not to leave
ourselves open to buffer overflow attacks.

But then I’ve probably been just as guilty as anyone in using
(“%S\n”) when in quick debug mode :wink:

Mark.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Brings to mind the old Systems Internals RegHide (http://technet.microsoft.com/en-us/sysinternals/bb897446.aspx) and RegDelNull (http://technet.microsoft.com/en-us/sysinternals/bb897448.aspx) programs. These deal with keys (not values), but interesting nonetheless.

Too bad the source is now gone. :frowning:

-Stephen

I got it from here (WDK)

http://msdn2.microsoft.com/en-us/library/ms805862.aspx

and it doesn’t mention anything about values potentially not being NULL
terminated. Although I hear what Dan is saying - I’m not saying that he
would necessarily apply it to this particular link - personally, while
it isn’t an attractive option and would make the documentation a little
more complicated in a number of places, I would change it, at least in
the WDK, because it could cause pretty obvious problems, and it is what
it is. In particular, as Mark already mentioned, we live in world that
is presently convinced against all reason that buffer overflows and the
like are currently the biggest threat to man kind, and making this
change would at least prevent someone from claiming that his or her
“discovery” of this “undocumented behavior” was the result of the
extensive “security research” that they did before spending twenty
minutes to develop a “proof of concept of an exploit that could allow
remote execution of arbitrary code with privileges of the current user.”

mm

Doron Holan wrote:

I am pretty sure the UM apis just thunk to the native w/out additional validation. IIRC, RegGetValue will validate the results for you. The docs already call out that the string data may not be null terminated, although it is a little buried, http://msdn2.microsoft.com/en-us/library/ms724884.aspx

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Dan Kyler
Sent: Tuesday, March 18, 2008 4:16 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] Displaying a UNICODE_STRING

My recollection is that the Win32 routines take a null terminated string and
store it, including the null. When you query the value in kernel mode, you
get back the null terminated string, including the null, with length of the
data also including the null.

In kernel mode (or with native user mode routines), I’m pretty sure it’s
possible to store a REG_SZ without the null, which is likely to screw up a
lot of applications. It will also screw up drivers that don’t do the right
thing.

However, depending on where you got the quote below, I might argue against
changing the doc. If it has to do with setting the value, then it is the
case that it SHOULD be null terminated.

  • Dan.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Martin O’Brien
Sent: Tuesday, March 18, 2008 4:20 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Displaying a UNICODE_STRING

Thanks, Doron. Someone need to fix the documentation (6001.18000 WDK):

“REG_SZ A null-terminated Unicode string”

mm

Doron Holan wrote:
> REG_SZ and REG_EXPAND_SZ are not guaranteed to be null terminated in
either user or kernel mode. REG_MULTI_SZ is not not guaranteed to be double
null terminated either. The registry, just like the io manager, is “fast
and dumb” (as peter so eloquently put it) and does not validate the buffer
against the type when you set the value.
> d
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com] On Behalf Of Mark S.
> Edwards
> Sent: Tuesday, March 18, 2008 8:44 AM
> To: Windows System Software Devs Interest List
> Subject: Re:[ntdev] Displaying a UNICODE_STRING
>
> At 15:32 18/03/2008, Martin O’Brien wrote:
>> You had the same thought I did, Mark, but I thought that registry
>> strings were already null terminated (i. e. - REG_SZ)? If not, then
>> what I wrote will not work.
>>
>> Thanks,
>>
>>
>> mm
> Couldn’t remember if they were terminated or not, experience says that
> these days most strings returned in a counted buffer probably are not
> null terminated, but there are some exceptions.
>
> Easiest to play safe and always make sure there’s a terminator,
> especially in these times when we’re all encouraged not to leave
> ourselves open to buffer overflow attacks.
>
> But then I’ve probably been just as guilty as anyone in using
> (“%S\n”) when in quick debug mode :wink:
>
> Mark.
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Maybe Microsoft can take a leaf out of the food industry ?

Instead of “This product may contain nuts.”, the documentation can be
littered with warnings like “This value may contain nulls.”

:slight_smile: :slight_smile:

Mark

At 23:21 18/03/2008, Doron Holan wrote:

I am pretty sure the UM apis just thunk to the native w/out
additional validation. IIRC, RegGetValue will validate the results
for you. The docs already call out that the string data may not be
null terminated, although it is a little buried,
http://msdn2.microsoft.com/en-us/library/ms724884.aspx

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Dan Kyler
Sent: Tuesday, March 18, 2008 4:16 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] Displaying a UNICODE_STRING

My recollection is that the Win32 routines take a null terminated string and
store it, including the null. When you query the value in kernel mode, you
get back the null terminated string, including the null, with length of the
data also including the null.

In kernel mode (or with native user mode routines), I’m pretty sure it’s
possible to store a REG_SZ without the null, which is likely to screw up a
lot of applications. It will also screw up drivers that don’t do the right
thing.

However, depending on where you got the quote below, I might argue against
changing the doc. If it has to do with setting the value, then it is the
case that it SHOULD be null terminated.

  • Dan.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Martin O’Brien
Sent: Tuesday, March 18, 2008 4:20 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Displaying a UNICODE_STRING

Thanks, Doron. Someone need to fix the documentation (6001.18000 WDK):

“REG_SZ A null-terminated Unicode string”

mm

Doron Holan wrote:
> REG_SZ and REG_EXPAND_SZ are not guaranteed to be null terminated in
either user or kernel mode. REG_MULTI_SZ is not not guaranteed to be double
null terminated either. The registry, just like the io manager, is “fast
and dumb” (as peter so eloquently put it) and does not validate the buffer
against the type when you set the value.
>
> d
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com] On Behalf Of Mark S.
> Edwards
> Sent: Tuesday, March 18, 2008 8:44 AM
> To: Windows System Software Devs Interest List
> Subject: Re:[ntdev] Displaying a UNICODE_STRING
>
> At 15:32 18/03/2008, Martin O’Brien wrote:
>> You had the same thought I did, Mark, but I thought that registry
>> strings were already null terminated (i. e. - REG_SZ)? If not, then
>> what I wrote will not work.
>>
>> Thanks,
>>
>>
>> mm
>
> Couldn’t remember if they were terminated or not, experience says that
> these days most strings returned in a counted buffer probably are not
> null terminated, but there are some exceptions.
>
> Easiest to play safe and always make sure there’s a terminator,
> especially in these times when we’re all encouraged not to leave
> ourselves open to buffer overflow attacks.
>
> But then I’ve probably been just as guilty as anyone in using
> (“%S\n”) when in quick debug mode :wink:
>
> Mark.
>
>
> —
>