predefined macros (__FILE__ ) in a KMDF driver

Hello

are we allowed to use FILE ANSI macro in a KMDF driver ? I am using DDK 8.1; the code compiles fine and the compiler expands it into string literal but I am worried of the actual location of the string in memory. Does the compiler automatically place the strings in NON PAGED or PAGED memory? I am worried about getting a PAGE FAULT when running at dispatch or above while accessing the string. is there a way I could verify that with windbg hooked up ?

Thank you.

You can use it

On Saturday, September 19, 2015, wrote:

> Hello
>
> are we allowed to use FILE ANSI macro in a KMDF driver ? I am using
> DDK 8.1; the code compiles fine and the compiler expands it into string
> literal but I am worried of the actual location of the string in memory.
> Does the compiler automatically place the strings in NON PAGED or PAGED
> memory? I am worried about getting a PAGE FAULT when running at dispatch or
> above while accessing the string. is there a way I could verify that with
> windbg hooked up ?
>
> Thank you.
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> 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 almost just accepted Martin’s answer, but since I had VS open in front of me and a do nothing KMDF driver project I was just looking at assembler in a few days ago… (the answer way down this message, but basically “it depends”)

I inserted this line in a paged function (i.e. #pragma alloc_text (PAGE, DevDriverCreateDevice):

DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, “test%s\n”, FILE);

And then looked at the generated assembler for that constant by setting the compiler output listing option:

; COMDAT ??_C@xxxxx@test?$CFs?6?$xxxxx@NNGAKEGL@
PAGE$s SEGMENT
??_C@xxxxx@test?$CFs?6?$xxxxx@NNGAKEGL@ DB ‘test%s’, 0aH, 00H ; ?? ::NNGAKEGL::string' PAGE$s ENDS ; COMDAT ??_C@xxxxx@Device?4c?$xxxxx@NNGAKEGL@ PAGE$s SEGMENT ??_C@xxxxx@Device?4c?$xxxxx@NNGAKEGL@ DB 'Device.c', 00H ; ?? ::NNGAKEGL::string’
PAGE$s ENDS

And enabling the the link map for the driver shows the PAGE$s section ended up in section 5:

0004:00000000 00000240H .pdata DATA
0005:00000000 00000c62H PAGE CODE
0005:00000c70 000000fcH PAGE$s CODE
0006:00000000 000001b9H INIT CODE
0006:000001c0 00000035H INIT$s CODE
0006:000001f8 0000003cH .idata$2 CODE

The running link /dump /headers xxx.sys and looking at the section 5 attributes:

SECTION HEADER #4
.pdata name
240 virtual size
5000 virtual address (0000000140005000 to 000000014000523F)
400 size of raw data
2400 file pointer to raw data (00002400 to 000027FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
48000040 flags
Initialized Data
Not Paged
Read Only

SECTION HEADER #5
PAGE name
D6C virtual size
6000 virtual address (0000000140006000 to 0000000140006D6B)
E00 size of raw data
2800 file pointer to raw data (00002800 to 000035FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
Execute Read

SECTION HEADER #6
INIT name
432 virtual size
7000 virtual address (0000000140007000 to 0000000140007431)
600 size of raw data
3600 file pointer to raw data (00003600 to 00003BFF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
62000020 flags
Code
Discardable
Execute Read

As the attribute “Not Paged” is NOT on section 5, I have to come to the conclusion that a string constant defined inside a paged function ends up being allocated in a paged region of memory. This means it’s ok to use it from the paged code, but is NOT ok to pass a reference to it back out to some non-paged function that might be running at DISPATCH_LEVEL.

Jan

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@live.com
Sent: Saturday, September 19, 2015 6:38 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] predefined macros ( FILE ) in a KMDF driver

Hello

are we allowed to use FILE ANSI macro in a KMDF driver ? I am using DDK 8.1; the code compiles fine and the compiler expands it into string literal but I am worried of the actual location of the string in memory. Does the compiler automatically place the strings in NON PAGED or PAGED memory? I am worried about getting a PAGE FAULT when running at dispatch or above while accessing the string. is there a way I could verify that with windbg hooked up ?

Thank you.


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

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

strange why ??_C@xxxxx@Device?4c?$xxxxx@NNGAKEGL@ is in PAGE$s segment. by default string constant like this is allocated in CONST segment, which is renamed to .rdata by linker. however i not view .rdata section in you dump. may be you overwrite some linker defaults, as result you have not .rdata section. but say in my test i view some like this

CONST SEGMENT
??xxxxx@xxxxx@NEBBJFLE@?4?2FltFF?4cpp?$AA@ DB ‘.\FltFF.cpp’, 00H ; `string’
CONST ENDS

and finally this string in .rdata section (which notpaged)
however i always use cpp, when you look like use c (‘Device.c’). may be c have some specific

Impressive answer sir.

I just by deafult

On Saturday, September 19, 2015, Jan Bottorff
wrote:

> I almost just accepted Martin’s answer, but since I had VS open in front
> of me and a do nothing KMDF driver project I was just looking at assembler
> in a few days ago… (the answer way down this message, but basically “it
> depends”)
>
> I inserted this line in a paged function (i.e. #pragma alloc_text (PAGE,
> DevDriverCreateDevice):
>
> DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, “test%s\n”, FILE );
>
> And then looked at the generated assembler for that constant by setting
> the compiler output listing option:
>
> ; COMDAT ??_C@xxxxx@test?$CFs?6?$xxxxx@NNGAKEGL@
> PAGE$s SEGMENT
> ??_C@xxxxx@test?$CFs?6?$xxxxx@NNGAKEGL@ DB ‘test%s’, 0aH, 00H ; ??
> ::NNGAKEGL::string'<br>&gt; PAGE$s ENDS<br>&gt; ; COMDAT ??_C@xxxxx@Device?4c?$xxxxx@NNGAKEGL@<br>&gt; PAGE$s SEGMENT<br>&gt; ??_C@xxxxx@Device?4c?$xxxxx@NNGAKEGL@ DB 'Device.c', 00H ; ??<br>&gt; ::NNGAKEGL::string’
> PAGE$s ENDS
>
> And enabling the the link map for the driver shows the PAGE$s section
> ended up in section 5:
> …
> 0004:00000000 00000240H .pdata DATA
> 0005:00000000 00000c62H PAGE CODE
> 0005:00000c70 000000fcH PAGE$s CODE
> 0006:00000000 000001b9H INIT CODE
> 0006:000001c0 00000035H INIT$s CODE
> 0006:000001f8 0000003cH .idata$2 CODE
> …
>
> The running link /dump /headers xxx.sys and looking at the section 5
> attributes:
>
> SECTION HEADER #4
> .pdata name
> 240 virtual size
> 5000 virtual address (0000000140005000 to 000000014000523F)
> 400 size of raw data
> 2400 file pointer to raw data (00002400 to 000027FF)
> 0 file pointer to relocation table
> 0 file pointer to line numbers
> 0 number of relocations
> 0 number of line numbers
> 48000040 flags
> Initialized Data
> Not Paged
> Read Only
>
> SECTION HEADER #5
> PAGE name
> D6C virtual size
> 6000 virtual address (0000000140006000 to 0000000140006D6B)
> E00 size of raw data
> 2800 file pointer to raw data (00002800 to 000035FF)
> 0 file pointer to relocation table
> 0 file pointer to line numbers
> 0 number of relocations
> 0 number of line numbers
> 60000020 flags
> Code
> Execute Read
>
> SECTION HEADER #6
> INIT name
> 432 virtual size
> 7000 virtual address (0000000140007000 to 0000000140007431)
> 600 size of raw data
> 3600 file pointer to raw data (00003600 to 00003BFF)
> 0 file pointer to relocation table
> 0 file pointer to line numbers
> 0 number of relocations
> 0 number of line numbers
> 62000020 flags
> Code
> Discardable
> Execute Read
>
>
> As the attribute “Not Paged” is NOT on section 5, I have to come to the
> conclusion that a string constant defined inside a paged function ends up
> being allocated in a paged region of memory. This means it’s ok to use it
> from the paged code, but is NOT ok to pass a reference to it back out to
> some non-paged function that might be running at DISPATCH_LEVEL.
>
> Jan
>
>
>
> -----Original Message-----
> From: xxxxx@lists.osr.com <javascript:> [mailto:
> xxxxx@lists.osr.com <javascript:>] On Behalf Of
> xxxxx@live.com <javascript:>
> Sent: Saturday, September 19, 2015 6:38 PM
> To: Windows System Software Devs Interest List > <javascript:>>
> Subject: [ntdev] predefined macros ( FILE ) in a KMDF driver
>
> Hello
>
> are we allowed to use FILE ANSI macro in a KMDF driver ? I am using
> DDK 8.1; the code compiles fine and the compiler expands it into string
> literal but I am worried of the actual location of the string in memory.
> Does the compiler automatically place the strings in NON PAGED or PAGED
> memory? I am worried about getting a PAGE FAULT when running at dispatch or
> above while accessing the string. is there a way I could verify that with
> windbg hooked up ?
>
> Thank you.
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> 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
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> 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
></javascript:></javascript:></javascript:></javascript:>

for Jan Bottorff

Does the string location depends on the order it first shows up in the file? i.e.

In your example the function where the macro first appears is defined as PAGED. What if you have a second function, in the same source file, “defined as” NON PAGED which also uses the FILE macro ?

"Does the string location depends on the order it first shows up in the file? "
no. and data usual allocated in another section that code. if this not overwritten by some #pragma (data_seg, const_seg, code_seg )
does not matter in which segment located function where constant string used. constant data allocated in CONST (.rdata) segment. if this not overwriten by #pragma const_seg. however this can be compiler depended. what i wrote - tru for CL for cpp files

While I in no way doubt Mr. Bottorff findings and assertions, I have to say that I have a hard time squaring them with the fact that never in the many years since Windows NT was released, have I *ever* seen a driver page-fault at elevated IRQL due to FILE, DATE, or TIME. You would *think* it would happen *once* if this were the case.

You would also think it would be quickly recognized as being silly in the extreme to put such things in a pageable section in a driver.

Maybe there’s something to what Mr. Brown, who sees something different, is saying??

Peter
OSR
@OSRDrivers

FILE, DATE, and TIME expand to strings in the preprocessor stream and thus to the compiler look no differently than if you had just type the a literal string.

So really the question is about literal strings and how they are handled. It really is irrelevant where the string came from in the input stream to the compiler.

I can believe that give the correct machinations one could conspire to get a literal string stuck in a paged (or non-paged) section.

Like Peter, I have used literal strings (and FILE) in many a KM code module and have yet to break into a sweat in the middle of the night worrying that I somehow forgot to note to the compiler to put the string in a non-paged segment.

But then again I have not gone out of my way to do anything like Jan did to induce the situation.

Maybe I have been exceedingly lucky. I am surely going to have a look at what Ida says about a couple of my drivers just to keep my sleep patterns as they were.

Dave Cattley

Sent from Mail for Windows 10

There are a few weird patterns that I’ve seen over the years that will get things in paged sections – virtual destructors used to be handled differently, for example – but they still require explicit use of paged segments.

mm

From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Dave Cattley
Sent: Monday, September 21, 2015 4:36 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] predefined macros (FILE ) in a KMDF driver

FILE, DATE, and TIME expand to strings in the preprocessor stream and thus to the compiler look no differently than if you had just type the a literal string.

So really the question is about literal strings and how they are handled. It really is irrelevant where the string came from in the input stream to the compiler.

I can believe that give the correct machinations one could conspire to get a literal string stuck in a paged (or non-paged) section.

Like Peter, I have used literal strings (and FILE) in many a KM code module and have yet to break into a sweat in the middle of the night worrying that I somehow forgot to note to the compiler to put the string in a non-paged segment.

But then again I have not gone out of my way to do anything like Jan did to induce the situation.

Maybe I have been exceedingly lucky. I am surely going to have a look at what Ida says about a couple of my drivers just to keep my sleep patterns as they were.

Dave Cattley

Sent from Mail http: for Windows 10


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

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</http:>

OK, OK… Let’s look at this rationally. With no aspersions cast on Mr. Bottorff work, of course.

Mr. Cattley points out that FILE and friends simply" expand to strings in the preprocessor stream
and thus to the compiler look no differently than if you had just type the a literal string." This is an excellent observation.

Soooo… knowing this, we can ask “are string literals stored in pageable memory?” Anybody ever do a DbgPrint from their ISR or DPC under memory pressure? Of COURSE you have. Ever get a blue screen because of it? Nobody I know has.

Now… Anybody ever call the various Unicode or WCS formatting functions at IRQLs >= DISPATCH_LEVEL? Sure you have. Ever gotten a blue screen when doing this, under memory pressure? SURE you have. I have. Before it was clearly documented in the WDK docs EVERYONE got these blue screens.

But we got the BSOD on the FUNCTION, not on the STRING.

Remove the nasty wide character function one way or another (like by hand-coding the equivalent) and the BSOD goes away.

Not conclusive PROOF, of course… but darn good supporting evidence.

So, while I have nothing but respect for Mr. Bottorff, I have having difficulty trusting the conclusions of his findings on this particular topic.

I would “just try it myself” (I mean, load some driver code, look to see if the page with the string is pageable… how hard can this be, right?)… but I’m teaching a class this week and random driver-play isn’t in the cards for me.

Peter
OSR
@OSRDrivers

here nothing weird. with virtual functions also no problem. by default all constant strings and cables placed in .rdata section and it was nonpaged. and this is absolutely independent from where code (paged or not paged) it used. for simply example
#pragma code_seg(“PAGE”)

struct AAA
{
AAA()
{
DbgPrint(“%s\n”, FUNCTION);
}

virtual ~AAA()
{
DbgPrint(“%s\n”, FUNCTION);
}

void* operator new(size_t cb)
{
return ExAllocatePool(PagedPool, cb);
}

void operator delete(PVOID pv)
{
ExFreePool(pv);
}
};

#pragma code_seg()

we have here several functions - AAA::AAA, AAA::~AAA, AAA::operator new, AAA::operator delete which placed in “PAGE” section.
but strings and vtable for class AAA is placed in .rdata (CONST) section - which is NOT paged. so no any problem.

PAGE SEGMENT
??0AAA@NT@@QAE@XZ PROC ; AAA::AAA, COMDAT
push esi
mov esi, ecx
push OFFSET ??xxxxx@xxxxx@GMJMNIB@NT?3?3AAA?3?3AAA?$AA@ “AAA::AAA”
push OFFSET ??_C@_03OFAPEBGM@?$CFs?6?$AA@ ; “%s\n”
mov DWORD PTR [esi], OFFSET ??_7AAA@NT@@6B@ ; AAA::`vftable’
call DWORD PTR __imp__DbgPrint
pop ecx
pop ecx
mov eax, esi
pop esi
ret 0
??0AAA@NT@@QAE@XZ ENDP ; AAA::AAA
PAGE ENDS

CONST SEGMENT
??xxxxx@xxxxx@GMJMNIB@NT?3?3AAA?3?3AAA?$AA@ DB ‘AAA::AAA’, 00H ; `string’
CONST ENDS

CONST SEGMENT
??_7AAA@NT@@6B@ DD FLAT:??_EAAA@NT@@UAEPAXI@Z ; AAA::`vftable’
CONST ENDS

in example where strings in PAGE$s i shure author overwrite defaults for DATA place by using #pragma directive.

so my conclusion - use constant strings, macros, vtables - is absolute safe. problem can be only if you special place self data in “PAGE*” section or merge some section.

When you build a kernel mode driver, the compiler is informed that it should place string literals in the code section containing the function that they’re referenced within.

  • S (Msft)

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@osr.com
Sent: Monday, September 21, 2015 4:59 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] predefined macros ( FILE ) in a KMDF driver

OK, OK… Let’s look at this rationally. With no aspersions cast on Mr. Bottorff work, of course.

Mr. Cattley points out that FILE and friends simply" expand to strings in the preprocessor stream and thus to the compiler look no differently than if you had just type the a literal string." This is an excellent observation.

Soooo… knowing this, we can ask “are string literals stored in pageable memory?” Anybody ever do a DbgPrint from their ISR or DPC under memory pressure? Of COURSE you have. Ever get a blue screen because of it? Nobody I know has.

Now… Anybody ever call the various Unicode or WCS formatting functions at IRQLs >= DISPATCH_LEVEL? Sure you have. Ever gotten a blue screen when doing this, under memory pressure? SURE you have. I have. Before it was clearly documented in the WDK docs EVERYONE got these blue screens.

But we got the BSOD on the FUNCTION, not on the STRING.

Remove the nasty wide character function one way or another (like by hand-coding the equivalent) and the BSOD goes away.

Not conclusive PROOF, of course… but darn good supporting evidence.

So, while I have nothing but respect for Mr. Bottorff, I have having difficulty trusting the conclusions of his findings on this particular topic.

I would “just try it myself” (I mean, load some driver code, look to see if the page with the string is pageable… how hard can this be, right?)… but I’m teaching a class this week and random driver-play isn’t in the cards for me.

Peter
OSR
@OSRDrivers


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

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

“When you build a kernel mode driver, the compiler is informed that it should
place string literals in the code section containing the function that they’re
referenced within.” - may be this compiler depended, but in all my tests with cl.exe compiler for last 10 years - all string literals is placed in CONST (.rdata) by default

if i in self example add say

#pragma const_seg(“PAGEDD”)

already vftable and strings placed in “PAGEDD”, which paged. but by default - in not paged CONST
and #pragma code_seg(“*)” have no effect for data
for constant data only #pragma const_seg(“*”) have effect
or __declspec (allocate(“segname”) )

PAGEDD SEGMENT
??_7AAA@NT@@6B@ DD FLAT:??_EAAA@NT@@UAEPAXI@Z ; AAA::`vftable’
PAGEDD ENDS

PAGEDD SEGMENT
??xxxxx@xxxxx@GMJMNIB@NT?3?3AAA?3?3AAA?$xxxxx@LCBGAHHF@ DB ‘AAA::AAA’, 00H ; ?? ::LCBGAHHF::`string’
PAGEDD ENDS

The problem you run into pre win8 is that when the linker performs code folding, section name was not a uniquifier and the first instance won. This meant your virtual function could randomly land in a paged section depending on ordering and non visible criteria

Sent from Outlook Mailhttp: for Windows 10

From: xxxxx@live.com
Sent: Monday, September 21, 2015 5:34 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] predefined macros ( FILE ) in a KMDF driver

if i in self example add say

#pragma const_seg(“PAGEDD”)

already vftable and strings placed in “PAGEDD”, which paged. but by default - in not paged CONST
and #pragma code_seg(“)" have no effect for data
for constant data only #pragma const_seg("
”) have effect
or __declspec (allocate(“segname”) )

PAGEDD SEGMENT
??_7AAA@NT@@6B@ DD FLAT:??_EAAA@NT@@UAEPAXI@Z ; AAA::vftable'<br>PAGEDD ENDS<br><br>PAGEDD SEGMENT<br>??xxxxx@xxxxx@GMJMNIB@NT?3?3AAA?3?3AAA?$xxxxx@LCBGAHHF@ DB 'AAA::AAA', 00H ; ?? ::LCBGAHHF::string’
PAGEDD ENDS


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

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</http:>

I believe Jan Bottorff is correct. I looked at the assembly and header sections for a file (common.c) where some functions are defined as “pageable” and some others as “non pageable”. They all make use of the macro FILE.

There are two string literal defined: one in the text$s segment (referenced in the non pageable functions) and one in the PAGE$s segment (referenced in the pageable functions)

text$s SEGMENT
??_C@xxxxx@common?4c?$xxxxx@FNODOBFM@ DB ‘common.c’, 00H ; ?? ::FNODOBFM::`string’
text$s ENDS

; COMDAT ??_C@xxxxx@common?4c?$xxxxx@NNGAKEGL@

PAGE$s SEGMENT
??_C@xxxxx@common?4c?$xxxxx@NNGAKEGL@ DB ‘common.c’, 00H ; ?? ::NNGAKEGL::`string’
PAGE$s ENDS

0001:00000000 000037d3H .text$mn CODE
0001:000037e0 000003a4H .text$s CODE

0005:00000000 00008fddH PAGE CODE
0005:00008fe0 00000116H PAGE$s CODE

SECTION HEADER #1
.text name
3B84 virtual size
1000 virtual address (0000000140001000 to 0000000140004B83)
3C00 size of raw data
400 file pointer to raw data (00000400 to 00003FFF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
68000020 flags
Code
Not Paged
Execute Read

SECTION HEADER #5
PAGE name
90F6 virtual size
9000 virtual address (0000000140009000 to 00000001400120F5)
9200 size of raw data
5400 file pointer to raw data (00005400 to 0000E5FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
Execute Read

The project I did this test on used the production release of VS2015 Enterprise and the production Win 10 WDK. I generated a do nothing KMDF driver with the wizard, and had added a little code to hook up some hardware (the bar and MSI interrupt) for an experiment last week. Except for the listings I turned on, the options should be exactly what the KMDF wizard sets. This was C code not C++ code. I had looked at some strings in non-paged functions, and they were in a different segment (don’t remember which) that looked non-paged (but I didn’t look at the map and the final binary section attributes to be sure). Seems like there used to be a way to get the linkmap to show the section attributes.

This experiment was to see if FILE is ALWAYS safe to access from a paging incompatible context, and to record the steps to determine the correct answer. The experiment produced at least one case where a string constant lived in paged memory. This also was a debug build, so may or may not be the same on a release build. It also doesn’t say anything about how the compiler/linker might merge multiple duplicate strings.

Everybody should be able to follow the steps to determine other cases. I know Microsoft would like us to use paged code when possible. Is this documented someplace that string constants in a paged function will also be paged?

The next level of this experiment, from inside a paged function, store a pointer to the FILE string in the device context, and then access that pointer from a higher IRQL, like the device ISR. This will clearly be bad in the real world, the question is, will any of the Microsoft static analyzer tools detect this is bad. And the answer is, NO. I added the couple lines of code, checked the .asm listing to verify the string was still in PAGE$s and ran both Code Analyzer and SDV. Neither tool detected this was a violation of IRQL rules. On closer examination, the SAL declaration for a KMDF ISR function says it could be PASSIVE_LEVEL, which is true if you specify PassiveHandling in the WDF_INTERRUPT_CONFIG used when creating the WDFINTERRUPT object. It’s also true that nearly every ISR will be running at an elevated IRQL, so it seems like the SAL notation is less that helpful in this case. I manually adjusted the annotation for my ISR to say it ran at higher IRQL, and ran the static analyzer tools again, and they still didn’t detect this reference to paged data from a page fault incompatible function.

Perhaps one of you folks who knows SAL 2.0 really well (I looked at the docs, but came up empty) can tell us if there is any way to inform SDV that a field in a structure has specific IRQL constraints.

I did one more little test:

char * myPagedFunction(void)
{
static char * myString = “pagedOrNonPaged”;

return myString;
}

I found if the static myString was inside the paged function, the string was allocated in paged memory, although the string pointer variable was always non-paged. If I moved the declaration of myString outside the paged function, it became non-paged. It seems like the rule is ANY string literal declared inside a paged function is in paged memory.

It does seem like a usage scenario where this is a problem is if you have some paged (or discardable) function that has string literals that get stored in some non-paged structure, there might be a surprise. This makes me less inclined to use paged functions, as the paged data can leak out. Where might it leak out, say you have a structure to represent your ISR/DPC and you decide it would be useful for debugging/support to have a string label on the structure that tells you which of your 18 MSI-X interrupts it’s for. If you create those structures, even in non-paged pool, from a paged function, the string label may be paged if you don’t pay attention. Say you also have some ETW/WPP trace code in your ISR which among other things writes the label to the trace. The ISR is non-paged, the data structure describing it are from non-paged pool, but oops, that little text label is paged, because you initialized the structure from a paged function.

Jan

On 9/20/15, 3:04 AM, “xxxxx@lists.osr.com on behalf of xxxxx@live.com” wrote:

>strange why ??_C@xxxxx@Device?4c?$xxxxx@NNGAKEGL@ is in PAGE$s segment. by default string constant like this is allocated in CONST segment, which is renamed to .rdata by linker. however i not view .rdata section in you dump. may be you overwrite some linker defaults, as result you have not .rdata section. but say in my test i view some like this
>
>CONST SEGMENT
>??xxxxx@xxxxx@NEBBJFLE@?4?2FltFF?4cpp?$AA@ DB ‘.\FltFF.cpp’, 00H ; `string’
>CONST ENDS
>
>and finally this string in .rdata section (which notpaged)
>however i always use cpp, when you look like use c (‘Device.c’). may be c have some specific

Skywing wrote:

When you build a kernel mode driver, the compiler is informed that it should place string literals in the code section containing the function that they’re referenced within.

  • S (Msft)

That’s exactly the lesson that I learnt the hard way, back in 2000. I
kept a fixed registry path in a global WCHAR* variable, which got its
contents assigned in DriverEntry. DriverEntry was of course located in
an INIT code section, and the reward was an (occasional) Stop 0x50,
PAGE_FAULT_IN_NONPAGED_AREA, which went away after I placed the string
assignment into a separate, non-pageable MyGlobalInit function.

The analysis I did back then to understand what was going on was
dumpbin mydriver.sys /section:INIT /rawdata

“When you build a kernel mode driver, the compiler is informed that it should
place string literals in the code section containing the function that they’re
referenced within.” - very strange. all my experience say that not. this is absolutely not true. may be we use different compilers or some compiler options. i do little test, which very easy repeat. write very small separate file - test.c (special c - in real life i always use only cpp, never c)

#pragma code_seg(“PAGE”)
const char * myPagedFunction(int i)
{
static char * myString1 = “pagedOrNonPaged1”;
static const char * myString2 = “pagedOrNonPaged2”;
return i & 1 ? myString1 : myString2;
}
#pragma code_seg()

and than look for test.asm

; Listing generated by Microsoft (R) Optimizing Compiler Version 18.00.21005.1

TITLE test.c
.686P
.XMM
include listing.inc
.model flat

INCLUDELIB OLDNAMES

PUBLIC ??xxxxx@xxxxx@xxxxx@pagedOrNonPaged1?$AA@ ; string' PUBLIC ??xxxxx@xxxxx@xxxxx@pagedOrNonPaged2?$AA@ ; string’
?myString2@?1??myPagedFunction@@xxxxx@9 DD FLAT:??xxxxx@xxxxx@xxxxx@pagedOrNonPaged2?$AA@ ; myPagedFunction'::2’::myString2
?myString1@?1??myPagedFunction@@xxxxx@9 DD FLAT:??xxxxx@xxxxx@xxxxx@pagedOrNonPaged1?$AA@ ; myPagedFunction'::2’::myString1
CONST ENDS
; COMDAT ??xxxxx@xxxxx@xxxxx@pagedOrNonPaged2?$AA@
CONST SEGMENT
??xxxxx@xxxxx@xxxxx@pagedOrNonPaged2?$AA@ DB ‘pagedOrNonPaged2’, 00H ; string' CONST ENDS ; COMDAT ??xxxxx@xxxxx@xxxxx@pagedOrNonPaged1?$AA@ CONST SEGMENT ??xxxxx@xxxxx@xxxxx@pagedOrNonPaged1?$AA@ DB 'pagedOrNonPaged1', 00H ; string’
PUBLIC _myPagedFunction@4
; Function compile flags: /Ogspy
; COMDAT _myPagedFunction@4
PAGE SEGMENT
xxxxx@4 PROC ; COMDAT
; _i$ = ecx
test cl, 1
mov eax, OFFSET ??xxxxx@xxxxx@xxxxx@pagedOrNonPaged1?$AA@
mov ecx, OFFSET ??xxxxx@xxxxx@xxxxx@pagedOrNonPaged2?$AA@
cmove eax, ecx
ret 0
xxxxx@4 ENDP
PAGE ENDS
END

what we can see - myPagedFunction place in PAGE section, but literal strings in CONST segment (after link this in .rdata section) - so we obviously use different compilers or different compilers options, pragmas etc…