Bugcheck 50 PAGE_FAULT_IN_NONPAGED_AREA

I am new to driver development and would appreciate
any assistance with this particular issue with a
driver running on Xp Embedded. The driver will have
the infamous Blue Screen around 10 percent of the time
on all machines that have the driver installed. This
ONLY happens on reboot or powerup. I have never had
this happen during normal operation. Using WinDbg
during this scenario I get a Bugcheck
PAGE_FAULT_IN_NON_PAGED_AREA (50). After this, I used
the !analyze -v command in WinDbg to get more details.
It appears that my driver is the cause as seen in the
analyze data.

*** Fatal System Error: 0x00000050
(0xE195E068,0x00000001,0xFC7D4BFF,0x00000001)

kd> !analyze -v

PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be
protected by try-except,
it must be protected by a Probe. Typically the
address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: e195e068, memory referenced.
Arg2: 00000001, value 0 = read operation, 1 = write
operation.
Arg3: fc7d4bff, If non-zero, the instruction address
which referenced the bad memory
address.
Arg4: 00000001, (reserved)

WRITE_ADDRESS: e195e068 Paged pool

FAULTING_IP:
sciecp!EcpGetHardwareInfo+10f
[c:\sciecp_latest\autocon.c @ 599]
fc7d4bff 66c704500000 mov word ptr
[eax+edx*2],0x0

MM_INTERNAL_CODE: 1

DEFAULT_BUCKET_ID: DRIVER_FAULT

BUGCHECK_STR: 0x50

LAST_CONTROL_TRANSFER: from fc7d44c2 to fc7d4bff

TRAP_FRAME: fc91376c – (.trap fffffffffc91376c)
ErrCode = 00000002
eax=e195df90 ebx=00000000 ecx=e195df90 edx=0000006c
esi=81dff6e8 edi=e195cb68
eip=fc7d4bff esp=fc9137e0 ebp=fc9137fc iopl=0
nv up ei pl zr na po nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000
efl=00010246
sciecp!EcpGetHardwareInfo+0x10f:
fc7d4bff 66c704500000 mov word ptr
[eax+edx*2],0x0
Resetting default scope

STACK_TEXT:
fc9137fc fc7d44c2 81dd2000 fc91380c e195c978
sciecp!EcpGetHardwareInfo+0x10f
[c:\sciecp_latest\autocon.c @ 599]
fc913820 80b3368a 81dff6e8 81dd2000 00000000
sciecp!DriverEntry+0x22 [c:\sciecp_latest\init.c @ 92]

FOLLOWUP_IP:
sciecp!EcpGetHardwareInfo+10f
[c:\sciecp_latest\autocon.c @ 599]
fc7d4bff 66c704500000 mov word ptr
[eax+edx*2],0x0

SYMBOL_STACK_INDEX: 0
FOLLOWUP_NAME: MachineOwner
SYMBOL_NAME: sciecp!EcpGetHardwareInfo+10f
MODULE_NAME: sciecp
IMAGE_NAME: sciecp.sys
DEBUG_FLR_IMAGE_TIMESTAMP: 46fc163f
STACK_COMMAND: .trap fffffffffc91376c ; kb
FAILURE_BUCKET_ID:
0x50_W_sciecp!EcpGetHardwareInfo+10f

BUCKET_ID: 0x50_W_sciecp!EcpGetHardwareInfo+10f

The failure seems to be in my driver sciecp.sys
autocon.c file where I allocate around 110 bytes of
PagedPool for holding the Registry key for use in
detecting hardware. Most of the time this works.
Here is a snippet of code.

// Make a copy of the Registry path name
// and be sure it has a terminator at the
// end…
//
TempString.Length = 0;
TempString.MaximumLength =
RegistryPath->Length +
sizeof( UNICODE_NULL );

if(( TempString.Buffer = ExAllocatePool( PagedPool,
TempString.MaximumLength )) == NULL ){
*ConfigList = NULL;
ExFreePool( ConfigArray );
return STATUS_INSUFFICIENT_RESOURCES;
}

RtlCopyUnicodeString( &TempString, RegistryPath );
TempString.Buffer[TempString.Length] =
UNICODE_NULL; // THIS IS WHERE WE GET THE BUGCHECK

The Bugcheck is generated when adding the UNICODE_NULL
chars a the end of the Registry key string. Next I
ran the !pool command from WinDbg with these results
displayed.

kd> !pool e195e068
Pool page e195e068 region is Paged pool
e195e000 is not a valid small pool allocation,
checking large pool…
e195e000 is freed (or corrupt) pool
Bad allocation size @e195e000, too large

Then I ran !poolval with these results.

kd> !poolval e195e000
Pool page e195e000 region is Paged pool
Validating Pool headers for pool page: e195e000
Pool page [e195e000] is __inVALID.
Analyzing linked list…
Scanning for single bit errors…
None found

I have seen that this function in my handed down
driver code ExAllocatePool() seems to pass every time
even though I read that it is an obsolete function.
If the memory is freed, how did it pass the
ExAllocatePool() check before writing the UNICODE_NULL
chars to the Registry String? Or could this be a byte
alignment / page boundary issue? Any ideas? Thanks in
advance.

Robert


Need a vacation? Get great deals
to amazing places on Yahoo! Travel.
http://travel.yahoo.com/

You pointed out the problem yourself. The pointer arithmentic is wrong.
TempString.Length is in bytes and Buffer is a pointer to double bytes so
"TempString.Buffer[TempString.Length] " is pointing twice as far as you
intended. Cast it to a single byte pointer to solve the problem. For
instance:

char *p=TempString.Buffer+TempString.Length;
*(PWSTR)p=UNICODE_NULL;

/Daniel

“Robert Moss” wrote in message news:xxxxx@ntdev…
> //
> TempString.Length = 0;
> TempString.MaximumLength =
> RegistryPath->Length +
> sizeof( UNICODE_NULL );
>
> if(( TempString.Buffer = ExAllocatePool( PagedPool,
> TempString.MaximumLength )) == NULL ){
> *ConfigList = NULL;
> ExFreePool( ConfigArray );
> return STATUS_INSUFFICIENT_RESOURCES;
> }
>
> RtlCopyUnicodeString( &TempString, RegistryPath );
> TempString.Buffer[TempString.Length] =
> UNICODE_NULL; // THIS IS WHERE WE GET THE BUGCHECK
>
> The Bugcheck is generated when adding the UNICODE_NULL
> chars a the end of the Registry key string. Next I
> ran the !pool command from WinDbg with these results
> displayed.

You are indexing TempString.Length, but Length is in BYTES and not WCHARs AFAIK.
Try TempString.Length / sizeof(WCHAR)

Robert Moss wrote:

I am new to driver development and would appreciate
any assistance with this particular issue with a
driver running on Xp Embedded. The driver will have
the infamous Blue Screen around 10 percent of the time
on all machines that have the driver installed. This
ONLY happens on reboot or powerup. I have never had
this happen during normal operation. Using WinDbg
during this scenario I get a Bugcheck
PAGE_FAULT_IN_NON_PAGED_AREA (50). After this, I used
the !analyze -v command in WinDbg to get more details.
It appears that my driver is the cause as seen in the
analyze data.

*** Fatal System Error: 0x00000050
(0xE195E068,0x00000001,0xFC7D4BFF,0x00000001)

kd> !analyze -v

PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be
protected by try-except,
it must be protected by a Probe. Typically the
address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: e195e068, memory referenced.
Arg2: 00000001, value 0 = read operation, 1 = write
operation.
Arg3: fc7d4bff, If non-zero, the instruction address
which referenced the bad memory
address.
Arg4: 00000001, (reserved)

WRITE_ADDRESS: e195e068 Paged pool

FAULTING_IP:
sciecp!EcpGetHardwareInfo+10f
[c:\sciecp_latest\autocon.c @ 599]
fc7d4bff 66c704500000 mov word ptr
[eax+edx*2],0x0

MM_INTERNAL_CODE: 1

DEFAULT_BUCKET_ID: DRIVER_FAULT

BUGCHECK_STR: 0x50

LAST_CONTROL_TRANSFER: from fc7d44c2 to fc7d4bff

TRAP_FRAME: fc91376c – (.trap fffffffffc91376c)
ErrCode = 00000002
eax=e195df90 ebx=00000000 ecx=e195df90 edx=0000006c
esi=81dff6e8 edi=e195cb68
eip=fc7d4bff esp=fc9137e0 ebp=fc9137fc iopl=0
nv up ei pl zr na po nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000
efl=00010246
sciecp!EcpGetHardwareInfo+0x10f:
fc7d4bff 66c704500000 mov word ptr
[eax+edx*2],0x0
Resetting default scope

STACK_TEXT:
fc9137fc fc7d44c2 81dd2000 fc91380c e195c978
sciecp!EcpGetHardwareInfo+0x10f
[c:\sciecp_latest\autocon.c @ 599]
fc913820 80b3368a 81dff6e8 81dd2000 00000000
sciecp!DriverEntry+0x22 [c:\sciecp_latest\init.c @ 92]

FOLLOWUP_IP:
sciecp!EcpGetHardwareInfo+10f
[c:\sciecp_latest\autocon.c @ 599]
fc7d4bff 66c704500000 mov word ptr
[eax+edx*2],0x0

SYMBOL_STACK_INDEX: 0
FOLLOWUP_NAME: MachineOwner
SYMBOL_NAME: sciecp!EcpGetHardwareInfo+10f
MODULE_NAME: sciecp
IMAGE_NAME: sciecp.sys
DEBUG_FLR_IMAGE_TIMESTAMP: 46fc163f
STACK_COMMAND: .trap fffffffffc91376c ; kb
FAILURE_BUCKET_ID:
0x50_W_sciecp!EcpGetHardwareInfo+10f

BUCKET_ID: 0x50_W_sciecp!EcpGetHardwareInfo+10f

The failure seems to be in my driver sciecp.sys
autocon.c file where I allocate around 110 bytes of
PagedPool for holding the Registry key for use in
detecting hardware. Most of the time this works.
Here is a snippet of code.

// Make a copy of the Registry path name
// and be sure it has a terminator at the
// end…
//
TempString.Length = 0;
TempString.MaximumLength =
RegistryPath->Length +
sizeof( UNICODE_NULL );

if(( TempString.Buffer = ExAllocatePool( PagedPool,
TempString.MaximumLength )) == NULL ){
*ConfigList = NULL;
ExFreePool( ConfigArray );
return STATUS_INSUFFICIENT_RESOURCES;
}

RtlCopyUnicodeString( &TempString, RegistryPath );
TempString.Buffer[TempString.Length] =
UNICODE_NULL; // THIS IS WHERE WE GET THE BUGCHECK

The Bugcheck is generated when adding the UNICODE_NULL
chars a the end of the Registry key string. Next I
ran the !pool command from WinDbg with these results
displayed.

kd> !pool e195e068
Pool page e195e068 region is Paged pool
e195e000 is not a valid small pool allocation,
checking large pool…
e195e000 is freed (or corrupt) pool
Bad allocation size @e195e000, too large

Then I ran !poolval with these results.

kd> !poolval e195e000
Pool page e195e000 region is Paged pool
Validating Pool headers for pool page: e195e000
Pool page [e195e000] is __inVALID.
Analyzing linked list…
Scanning for single bit errors…
None found

I have seen that this function in my handed down
driver code ExAllocatePool() seems to pass every time
even though I read that it is an obsolete function.
If the memory is freed, how did it pass the
ExAllocatePool() check before writing the UNICODE_NULL
chars to the Registry String? Or could this be a byte
alignment / page boundary issue? Any ideas? Thanks in
advance.

Robert


Need a vacation? Get great deals
to amazing places on Yahoo! Travel.
http://travel.yahoo.com/


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


Sandor LUKACS
Analyst Programmer, R&D
BitDefender

E-mail: xxxxx@bitdefender.com
Phone : +40 264 443 008

www.bitdefender.com

I would agree with the other response. Dividing by sizeof(WCHAR) to move from number of bytes to number of characters is much more understandable then 2 casts to from char* and then back to WCHAR*

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Daniel Terhell
Sent: Tuesday, October 02, 2007 7:05 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Bugcheck 50 PAGE_FAULT_IN_NONPAGED_AREA

You pointed out the problem yourself. The pointer arithmentic is wrong.
TempString.Length is in bytes and Buffer is a pointer to double bytes so
"TempString.Buffer[TempString.Length] " is pointing twice as far as you
intended. Cast it to a single byte pointer to solve the problem. For
instance:

char *p=TempString.Buffer+TempString.Length;
*(PWSTR)p=UNICODE_NULL;

/Daniel

“Robert Moss” wrote in message news:xxxxx@ntdev…
> //
> TempString.Length = 0;
> TempString.MaximumLength =
> RegistryPath->Length +
> sizeof( UNICODE_NULL );
>
> if(( TempString.Buffer = ExAllocatePool( PagedPool,
> TempString.MaximumLength )) == NULL ){
> *ConfigList = NULL;
> ExFreePool( ConfigArray );
> return STATUS_INSUFFICIENT_RESOURCES;
> }
>
> RtlCopyUnicodeString( &TempString, RegistryPath );
> TempString.Buffer[TempString.Length] =
> UNICODE_NULL; // THIS IS WHERE WE GET THE BUGCHECK
>
> The Bugcheck is generated when adding the UNICODE_NULL
> chars a the end of the Registry key string. Next I
> ran the !pool command from WinDbg with these results
> displayed.


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 for showing your preference but I never use the / operator on integer
types and I do pointer arithmetic on one-byte pointer types only. The extra
variable used was put on display for extra clarity, the cast (which are
handled by the compiler) can be rewritten into one line.

/Daniel

“Doron Holan” wrote in message
news:xxxxx@ntdev…
I would agree with the other response. Dividing by sizeof(WCHAR) to move
from number of bytes to number of characters is much more understandable
then 2 casts to from char* and then back to WCHAR*

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Daniel Terhell
Sent: Tuesday, October 02, 2007 7:05 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Bugcheck 50 PAGE_FAULT_IN_NONPAGED_AREA

You pointed out the problem yourself. The pointer arithmentic is wrong.
TempString.Length is in bytes and Buffer is a pointer to double bytes so
"TempString.Buffer[TempString.Length] " is pointing twice as far as you
intended. Cast it to a single byte pointer to solve the problem. For
instance:

char p=TempString.Buffer+TempString.Length;
(PWSTR)p=UNICODE_NULL;

/Daniel

“Robert Moss” wrote in message news:xxxxx@ntdev…
> //
> TempString.Length = 0;
> TempString.MaximumLength =
> RegistryPath->Length +
> sizeof( UNICODE_NULL );
>
> if(( TempString.Buffer = ExAllocatePool( PagedPool,
> TempString.MaximumLength )) == NULL ){
> *ConfigList = NULL;
> ExFreePool( ConfigArray );
> return STATUS_INSUFFICIENT_RESOURCES;
> }
>
> RtlCopyUnicodeString( &TempString, RegistryPath );
> TempString.Buffer[TempString.Length] =
> UNICODE_NULL; // THIS IS WHERE WE GET THE BUGCHECK
>
> The Bugcheck is generated when adding the UNICODE_NULL
> chars a the end of the Registry key string. Next I
> ran the !pool command from WinDbg with these results
> displayed.


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

Daniel Terhell wrote:

You pointed out the problem yourself. The pointer arithmentic is
wrong. TempString.Length is in bytes and Buffer is a pointer to double
bytes so "TempString.Buffer[TempString.Length] " is pointing twice as
far as you intended. Cast it to a single byte pointer to solve the
problem. For instance:

char *p=TempString.Buffer+TempString.Length;
*(PWSTR)p=UNICODE_NULL;

Unfortunately, this suffers from exactly the same problem as the
original. In fact, according to the C standard, the expression
“TempString.Buffer[TempString.Length]” is exactly the same as
“*(TempString.Buffer+TempString.Length)”. (To demonstrate this, you can
rewrite the expression as “TempString.Length[TempString.Buffer]”, and it
will still work just fine. Write 4[“abcdefg”] some time to amuse your
friends.)

This would work, since the cast will come first:
*(PWSTR)((char*)TempString.Buffer + TempString.Length) = UNICODE_NULL;

However, as Doron said, I don’t think that’s anywhere near as clear as:
TempString.Buffer[TempString.Length/sizeof(WCHAR)] = UNICODE_NULL;

It seems utterly silly to avoid integer division on philosophical
grounds. This is division by a constant; further, because it has to
multiply it by the same constant to do the indexing, the compiled code
will have neither the division or the multiplication.


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

And since the constant is 2, the compiler will usually use a shift instead of a divide to compute Length/sizeof(WCHAR), avoiding the divide entirely.

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Tuesday, October 02, 2007 11:11 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Bugcheck 50 PAGE_FAULT_IN_NONPAGED_AREA

Daniel Terhell wrote:

You pointed out the problem yourself. The pointer arithmentic is
wrong. TempString.Length is in bytes and Buffer is a pointer to double
bytes so "TempString.Buffer[TempString.Length] " is pointing twice as
far as you intended. Cast it to a single byte pointer to solve the
problem. For instance:

char *p=TempString.Buffer+TempString.Length;
*(PWSTR)p=UNICODE_NULL;

Unfortunately, this suffers from exactly the same problem as the
original. In fact, according to the C standard, the expression
“TempString.Buffer[TempString.Length]” is exactly the same as
“*(TempString.Buffer+TempString.Length)”. (To demonstrate this, you can
rewrite the expression as “TempString.Length[TempString.Buffer]”, and it
will still work just fine. Write 4[“abcdefg”] some time to amuse your
friends.)

This would work, since the cast will come first:
*(PWSTR)((char*)TempString.Buffer + TempString.Length) = UNICODE_NULL;

However, as Doron said, I don’t think that’s anywhere near as clear as:
TempString.Buffer[TempString.Length/sizeof(WCHAR)] = UNICODE_NULL;

It seems utterly silly to avoid integer division on philosophical
grounds. This is division by a constant; further, because it has to
multiply it by the same constant to do the indexing, the compiled code
will have neither the division or the multiplication.


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


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

Actually, I use the same approach a Daniel. Not because I have a problem
with divides, but because the pattern he offerred is general and will work
for any type of pointer with a byte offset. While the other is fine,
having a standard pattern for handling ptr + byte offset I my opinion makes
code more consistant and easier to spot problems.


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

“Doron Holan” wrote in message
news:xxxxx@ntdev…
And since the constant is 2, the compiler will usually use a shift instead
of a divide to compute Length/sizeof(WCHAR), avoiding the divide entirely.

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Tuesday, October 02, 2007 11:11 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Bugcheck 50 PAGE_FAULT_IN_NONPAGED_AREA

Daniel Terhell wrote:
> You pointed out the problem yourself. The pointer arithmentic is
> wrong. TempString.Length is in bytes and Buffer is a pointer to double
> bytes so “TempString.Buffer[TempString.Length] " is pointing twice as
> far as you intended. Cast it to a single byte pointer to solve the
> problem. For instance:
>
> char *p=TempString.Buffer+TempString.Length;
> (PWSTR)p=UNICODE_NULL;

Unfortunately, this suffers from exactly the same problem as the
original. In fact, according to the C standard, the expression
“TempString.Buffer[TempString.Length]” is exactly the same as
"
(TempString.Buffer+TempString.Length)”. (To demonstrate this, you can
rewrite the expression as “TempString.Length[TempString.Buffer]”, and it
will still work just fine. Write 4[“abcdefg”] some time to amuse your
friends.)

This would work, since the cast will come first:
(PWSTR)((char)TempString.Buffer + TempString.Length) = UNICODE_NULL;

However, as Doron said, I don’t think that’s anywhere near as clear as:
TempString.Buffer[TempString.Length/sizeof(WCHAR)] = UNICODE_NULL;

It seems utterly silly to avoid integer division on philosophical
grounds. This is division by a constant; further, because it has to
multiply it by the same constant to do the indexing, the compiled code
will have neither the division or the multiplication.


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


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

“Tim Roberts” wrote in message news:xxxxx@ntdev…

> It seems utterly silly to avoid integer division on philosophical
> grounds. This is division by a constant; further, because it has to
> multiply it by the same constant to do the indexing, the compiled code
> will have neither the division or the multiplication.
>

Thanks but this is not philosophical but practical. It is not compatible
with other languages. I do a lot of user mode development in other languages
which do not allow this syntax. For instance in Pascal you cannot do integer
divisions with the / operator. I am trying to keep one uniform syntax even
across different languages which makes switching easy for the brain.

I even would like to take this further and say I am against using the index
operator () because when I learnt C, Kernighan & Ritchie originally taught
to avoid it and use pointers instead. Although processor optimization
guides are nowadays recommending the use of the index operators, their
reasoning behind it is only based on how most compilers these days work.

/Daniel

Daniel Terhell wrote:

Thanks but this is not philosophical but practical. It is not
compatible with other languages. I do a lot of user mode development
in other languages which do not allow this syntax. For instance in
Pascal you cannot do integer divisions with the / operator. I am
trying to keep one uniform syntax even across different languages
which makes switching easy for the brain.

Please tell me that you do not do something like this:
#define Begin {
#define End }
#define And &&
#define Or ||

Although, along those lines, you could certainly do
#define div /
and then use the “div” operator in both C and Pascal.

The goal of language-independent source code is just not a reasonable
one, even if you limit yourself to C and Pascal. The pointer syntax is
different. The comparison operators are different. The type names are
different. Even the basic assignment operator is different. Eschewing
the integer division operator for such an unachievable goal is simply
not a productive path.

I even would like to take this further and say I am against using the
index operator () because when I learnt C, Kernighan & Ritchie
originally taught to avoid it and use pointers instead.

Utter nonsense. If you can quote an actual reference for that, I will
eat this message. By DEFINITION, the index operator and the addition
operator with pointers are synonymous. The compiler is REQUIRED to
generate identical code for them, and always has. This goes back to the
origins of the language.

Although processor optimization guides are nowadays recommending the
use of the index operators, their reasoning behind it is only based on
how most compilers these days work.

That is absolutely and utterly false.


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

Does one use ‘*’ to dereference pointers in Pacal?

> Please tell me that you do not do something like this:

. . .
#define And &&
#define Or ||
Here’s the contents of \Include\crt\iso646.h:

/* iso646.h standard header /
#ifndef _ISO646
#define _ISO646
#define and &&
#define and_eq &=
#define bitand &
#define bitor |
#define compl ~
#define not !
#define not_eq !=
#define or ||
#define or_eq |=
#define xor ^
#define xor_eq ^=
#endif /
_ISO646 /
/

* Copyright (c) 1994 by P.J. Plauger. ALL RIGHTS RESERVED.
* Consult your license regarding permissions and restrictions.
*/

Sorry, Tim. He should not define “or” for a diffreent reason: it’s already done for him:-)

-------------- Original message --------------
From: Tim Roberts

> Daniel Terhell wrote:
> >
> > Thanks but this is not philosophical but practical. It is not
> > compatible with other languages. I do a lot of user mode development
> > in other languages which do not allow this syntax. For instance in
> > Pascal you cannot do integer divisions with the / operator. I am
> > trying to keep one uniform syntax even across different languages
> > which makes switching easy for the brain.
>
> Please tell me that you do not do something like this:
> #define Begin {
> #define End }
> #define And &&
> #define Or ||
>
> Although, along those lines, you could certainly do
> #define div /
> and then use the “div” operator in both C and Pascal.
>
> The goal of language-independent source code is just not a reasonable
> one, even if you limit yourself to C and Pascal. The pointer syntax is
> different. The comparison operators are different. The type names are
> different. Even the basic assignment operator is different. Eschewing
> the integer division operator for such an unachievable goal is simply
> not a productive path.
>
>
> > I even would like to take this further and say I am against using the
> > index operator () because when I learnt C, Kernighan & Ritchie
> > originally taught to avoid it and use pointers instead.
>
> Utter nonsense. If you can quote an actual reference for that, I will
> eat this message. By DEFINITION, the index operator and the addition
> operator with pointers are synonymous. The compiler is REQUIRED to
> generate identical code for them, and always has. This goes back to the
> origins of the language.
>
>
> > Although processor optimization guides are nowadays recommending the
> > use of the index operators, their reasoning behind it is only based on
> > how most compilers these days work.
>
> That is absolutely and utterly false.
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.
>
>
> —
> 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, I am not buying into your macros because they will only add to
confusion. About the rest of the argument, much has been said about pointers
vs arrays. Here is an excerpt from the AMD processor optimization guide:

“Optimization: Use array notation instead of pointer notation when working
with arrays. Application: This optimization applies to:. 32-bit software.
64-bit software. Rationale: C allows the use of either the array operator
() or pointers to access the elements of an array. However, the use of
pointers in C makes work difficult for optimizers in C compilers. Without
detailed and aggressive pointer analysis, the compiler has to assume that
writes through a pointer canwrite to any location in memory, including
storage allocated to other variables. (For example, *p and
*q can refer to the same memory location, while x[0] and x[2] cannot.) Using
pointers causes aliasing, where the same block of memory is accessible in
more than one way. Using array notation makes the task of the optimizer
easier by reducing possible aliasing.”

In the eightees more or less the same rhetoric was used to reccomend the
opposite, that pointers would be faster because they could be easily loaded
in a count register and incremented with a loop instruction whereas the
array would need support for slow random access. If I dive in the basement I
can find you a lot of C lectures which strongly advice against using arrays
and use pointers for the sake of speed. It may be that the original reason
was that older processors before the 8086 such as the Z80 did not have index
registers which would allow easy indexing. Using index operators was really
being sneered upon those times.

/Daniel

“Tim Roberts” wrote in message news:xxxxx@ntdev…
> Daniel Terhell wrote:
>>
>> Thanks but this is not philosophical but practical. It is not
>> compatible with other languages. I do a lot of user mode development
>> in other languages which do not allow this syntax. For instance in
>> Pascal you cannot do integer divisions with the / operator. I am
>> trying to keep one uniform syntax even across different languages
>> which makes switching easy for the brain.
>
> Please tell me that you do not do something like this:
> #define Begin {
> #define End }
> #define And &&
> #define Or ||
>
> Although, along those lines, you could certainly do
> #define div /
> and then use the “div” operator in both C and Pascal.
>
> The goal of language-independent source code is just not a reasonable
> one, even if you limit yourself to C and Pascal. The pointer syntax is
> different. The comparison operators are different. The type names are
> different. Even the basic assignment operator is different. Eschewing
> the integer division operator for such an unachievable goal is simply
> not a productive path.
>
>
>> I even would like to take this further and say I am against using the
>> index operator () because when I learnt C, Kernighan & Ritchie
>> originally taught to avoid it and use pointers instead.
>
> Utter nonsense. If you can quote an actual reference for that, I will
> eat this message. By DEFINITION, the index operator and the addition
> operator with pointers are synonymous. The compiler is REQUIRED to
> generate identical code for them, and always has. This goes back to the
> origins of the language.
>
>
>> Although processor optimization guides are nowadays recommending the
>> use of the index operators, their reasoning behind it is only based on
>> how most compilers these days work.
>
> That is absolutely and utterly false.
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.
>
>

Daniel Terhell wrote:

In the eightees more or less the same rhetoric was used to reccomend
the opposite, that pointers would be faster because they could be
easily loaded in a count register and incremented with a loop
instruction whereas the array would need support for slow random
access. If I dive in the basement I can find you a lot of C lectures
which strongly advice against using arrays and use pointers for the
sake of speed. It may be that the original reason was that older
processors before the 8086 such as the Z80 did not have index
registers which would allow easy indexing. Using index operators was
really being sneered upon those times.

OK, but you are saying something here beyond what I’ve been saying.
You’re saying that using a pointer to run through a chunk of memory can
be faster than referencing individual array elements using array
notation. For example, to clear an array of integers, this:

int intArray[22];
int * pIntArray = intArray;
for( int* pi = intArray, i = 0; i < arraySize; i++ )
*pi++ = 0;

is probably faster than:

for( int i = 0; i < arraySize; i++ )
intArray[i] = 0;

I have no problem with that, depending on the architecture.

However, you were eschewing ANY use of the operator. When you need
to fetch item 6 of that array, these two statements are defined by the
language to be exactly identical:
return intArray[6];
return *(pintArray+6);


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

AMD is right. It has to do with the fact that pointers can be aliased, while
arrays cannot. A smart optimizer can go through an array loop and replace it
with highly optimized machine code, while the same loop with a pointer may
leave doubts about aliasing which can prevent the optimizer from doing a
better job.

I’m going to bet that a good compiler would go through both of your examples
and do the same level of optimization, but the only reason why the pointer
example still generates good code is that your int* pi is local to the loop.
Still, some analysis may be needed to make sure that your program doesn’t
play games with the pointer inside the loop body.

As far as the semantics being equal, it doesn’t follow that they must
generate the same code. Here, again, intArray[6] may be resolved to a
constant and the intArray+6*sizeof(blah) will be performed by the optimizer
at compile time, while *(pIntArray+6) will resolve to a pointer based
access. So, “return intArray[6]” may generate

mov eax,intArray+6*sizeof(blah)

where, again, the operand is computed at compile time, while "return
*(intArray+6) will generate something like

mov eax, [baseRegister + 6 * sizeof(blah)]

In this case the difference isn’t large, but in more complex cases you may
hobble the optimizer. Note also that the “base” register must be loaded, and
also saved and restored, leading to more complex code.

Alberto.

----- Original Message -----
From: “Tim Roberts”
To: “Windows System Software Devs Interest List”
Sent: Tuesday, October 02, 2007 5:53 PM
Subject: Re: [ntdev] Bugcheck 50 PAGE_FAULT_IN_NONPAGED_AREA

> Daniel Terhell wrote:
>>
>> In the eightees more or less the same rhetoric was used to reccomend
>> the opposite, that pointers would be faster because they could be
>> easily loaded in a count register and incremented with a loop
>> instruction whereas the array would need support for slow random
>> access. If I dive in the basement I can find you a lot of C lectures
>> which strongly advice against using arrays and use pointers for the
>> sake of speed. It may be that the original reason was that older
>> processors before the 8086 such as the Z80 did not have index
>> registers which would allow easy indexing. Using index operators was
>> really being sneered upon those times.
>
> OK, but you are saying something here beyond what I’ve been saying.
> You’re saying that using a pointer to run through a chunk of memory can
> be faster than referencing individual array elements using array
> notation. For example, to clear an array of integers, this:
>
> int intArray[22];
> int * pIntArray = intArray;
> for( int* pi = intArray, i = 0; i < arraySize; i++ )
> *pi++ = 0;
>
> is probably faster than:
>
> for( int i = 0; i < arraySize; i++ )
> intArray[i] = 0;
>
> I have no problem with that, depending on the architecture.
>
> However, you were eschewing ANY use of the operator. When you need
> to fetch item 6 of that array, these two statements are defined by the
> language to be exactly identical:
> return intArray[6];
> return *(pintArray+6);
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.
>
>
> —
> 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 for the assistance. Both methods seem to work
fine in testing.

Robert

— Daniel Terhell wrote:

> You pointed out the problem yourself. The pointer
> arithmentic is wrong.
> TempString.Length is in bytes and Buffer is a
> pointer to double bytes so
> "TempString.Buffer[TempString.Length] " is pointing
> twice as far as you
> intended. Cast it to a single byte pointer to solve
> the problem. For
> instance:
>
> char *p=TempString.Buffer+TempString.Length;
> *(PWSTR)p=UNICODE_NULL;
>
>
> /Daniel
>
>
> “Robert Moss” wrote in
> message news:xxxxx@ntdev…
> > //
> > TempString.Length = 0;
> > TempString.MaximumLength =
> > RegistryPath->Length +
> > sizeof( UNICODE_NULL );
> >
> > if(( TempString.Buffer = ExAllocatePool(
> PagedPool,
> > TempString.MaximumLength )) == NULL ){
> > *ConfigList = NULL;
> > ExFreePool( ConfigArray );
> > return STATUS_INSUFFICIENT_RESOURCES;
> > }
> >
> > RtlCopyUnicodeString( &TempString, RegistryPath );
> > TempString.Buffer[TempString.Length] =
> > UNICODE_NULL; // THIS IS WHERE WE GET THE
> BUGCHECK
> >
> > The Bugcheck is generated when adding the
> UNICODE_NULL
> > chars a the end of the Registry key string. Next
> I
> > ran the !pool command from WinDbg with these
> results
> > displayed.
>
>
> —
> 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
>

____________________________________________________________________________________
Moody friends. Drama queens. Your life? Nope! - their life, your story. Play Sims Stories at Yahoo! Games.
http://sims.yahoo.com/