Writing drivers in C++

Without intending to start a discussion regarding the merits of kernel-mode C++ drivers, I want to let this list know that we’ve released our C++ exception handling runtime as open-source.

The EH++ runtime library enables C++ exception handling in kernel-mode driver code. The library does not use OS constructs to perform exception handling for native C++ exceptions - it has its own dispatcher & unwinder that is MP/thread-safe, stack-friendly, and SEH compatible. It works without source modification - ie., you can write try-catch blocks in driver code.

You can download the library at blog.hurleysoftware.com/downloads.

The point of C++ exception handling in driver code is that it enables the core language idioms of C++, like RAII. We’re on the verge of releasing our DDK++ library (also open-source) which implements a templated smart_ptr class and a unicode_string class (ala std::string) which is binary-compatible with UNICODE_STRING.

We are also in the process of winding up the WDK version of STLport (w/o iostreams, of course). These will shortly be available for download at the same URL.

Regards,
Peter Hurley

How does throwing an exception across call frames which are not C++ aware or written to your framework handle unwind? Ie if you throw from a callstack like this

Driver!ThrowingFunction
Nt!Foo
Nt!Bar
Driver!CallIntoNt

How can you guarantee state / cleanup in ntoskrnl when Foo and Bar unwind unexpectedly? Also, before anyone makes any investment in this, I want to be clear that there is no support for this in the compiler (or through MSFT) and that future compiler changes may break this library.

thx
d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Peter Hurley
Sent: Thursday, April 14, 2011 2:14 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Writing drivers in C++

Without intending to start a discussion regarding the merits of kernel-mode C++ drivers, I want to let this list know that we’ve released our C++ exception handling runtime as open-source.

The EH++ runtime library enables C++ exception handling in kernel-mode driver code. The library does not use OS constructs to perform exception handling for native C++ exceptions - it has its own dispatcher & unwinder that is MP/thread-safe, stack-friendly, and SEH compatible. It works without source modification - ie., you can write try-catch blocks in driver code.

You can download the library at blog.hurleysoftware.com/downloads.

The point of C++ exception handling in driver code is that it enables the core language idioms of C++, like RAII. We’re on the verge of releasing our DDK++ library (also open-source) which implements a templated smart_ptr class and a unicode_string class (ala std::string) which is binary-compatible with UNICODE_STRING.

We are also in the process of winding up the WDK version of STLport (w/o iostreams, of course). These will shortly be available for download at the same URL.

Regards,
Peter Hurley


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

Peter, do you support x64?

Thanks,

mm

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Peter Hurley
Sent: Thursday, April 14, 2011 5:14 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Writing drivers in C++

Without intending to start a discussion regarding the merits of kernel-mode
C++ drivers, I want to let this list know that we’ve released our C++
exception handling runtime as open-source.

The EH++ runtime library enables C++ exception handling in kernel-mode
driver code. The library does not use OS constructs to perform exception
handling for native C++ exceptions - it has its own dispatcher & unwinder
that is MP/thread-safe, stack-friendly, and SEH compatible. It works without
source modification - ie., you can write try-catch blocks in driver code.

You can download the library at blog.hurleysoftware.com/downloads.

The point of C++ exception handling in driver code is that it enables the
core language idioms of C++, like RAII. We’re on the verge of releasing our
DDK++ library (also open-source) which implements a templated smart_ptr
class and a unicode_string class (ala std::string) which is
binary-compatible with UNICODE_STRING.

We are also in the process of winding up the WDK version of STLport (w/o
iostreams, of course). These will shortly be available for download at the
same URL.

Regards,
Peter Hurley


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

You website says:

You post is essentially a commercial post, and not allowed in this forum.

You have a GPL’ed version of this framework, and a COMMERCIAL version of this package. Your GPL’ed version is essentially a demo for the commercial package.

Please don’t repeat posts on this same topic.

If ANYbody, OP or anyone else, is of a mind to discuss the whether it’s proper to call this post commercial, please contact me directly – OFF LIST – to discuss. Do not post here.

Peter
OSR

Since the thread is not locked I presume we can discus non-commercial aspects and apologize if I misunderstood this. Unless they can provide useful technical feasibility rebuttal, I also hope those who don’t like C++ simply opt out of this topic since it is not directed at them and is an area of no use to them.

I too would like to understand if the technical issues raised so far can be overcome and if there are any other downsides, gotchas, or extra scaffolding. x64 is surely an absolute must have.

From a device driver architecture perspective, a nicety would be to direct cerr to debug output. This will be wonderful to get rid of the ugly, proprietary, and error prone KdPrint kludge. Of course those who think KdPrint is great are free to continue to use it. Also some companies have shared source code modules between kernel & user mode so this would be just one more nice uniformity.

Today the most advanced C++ dealings seem to be things like extending in new/delete and static ctors/dtors. C++ exceptions alone would be a logical and a huge next step. So much driver code is deeply nested if then else that tediously deals with every possible error and all the unraveling. I see some samples in the DDK actually resort to using goto’s of all things to try to consolidate and reduce this mess. C++ exceptions would flatten and ease reading code considerably in countless source code situations I work with.

And then I just drool thinking of being able to utilize vector, list, and so on in the kernel. So much of driver development is tedious data structure management and boring list walking. All of that ugly source code would disappear in blink in favor of a diverse arsenal of fast, solid libraries that many people already know and use elsewhere. This would be a huge win for us.

> From a device driver architecture perspective, a nicety would be to direct cerr to debug output. This will be

wonderful to get rid of the ugly, proprietary, and error prone KdPrint kludge.

Why is this error prone? I had no errors with this.

I would even say that cin/cout/cerr is ugly, due to redefining << shift operator to do IO. I personally use printf and fprintf even in C++ code.

using goto’s of all things to try to consolidate and reduce this mess. C++ exceptions would flatten and ease reading

C++ exceptions just plain increase the mess, unless the whole code is exception-aware, i.e. all objects are wrapped in classes with destructors and all functions use exceptions for failures.

And then I just drool thinking of being able to utilize vector, list, and so on in the kernel.

There is a list in the kernel - RemoveEntryList and such, I cannot see why is it worse then STL’s list.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

On 04/15/2011 05:53 AM, xxxxx@gmail.com wrote:

From a device driver architecture perspective, a nicety would be to
direct cerr to debug output. This will be wonderful […]

Adding C++ exceptions to a closed-source OS without strong support
from the manufacturer seems to me like flogging a dead horse.

If you want to use c-streams, use an operating system that was designed
from the ground up with C++ in mind? E.g. ‘Haiku’ surely could use your
help… :slight_smile:

xxxxx@gmail.com” wrote in message
news:xxxxx@ntdev:

> From a device driver architecture perspective, a nicety would be to direct cerr to debug output. This will be wonderful to get rid of the ugly, proprietary, and error prone KdPrint kludge. Of course those who think KdPrint is great are free to continue to use it. Also some companies have shared source code modules between kernel & user mode so this would be just one more nice uniformity.

Since when is “printf” proprietary, KdPrint is just a mapping of the
standard printf from C with a few extended formats (like most C
implementations). Calling this proprietary, is bogus.

Don Burn (MVP, Windows DKD)
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

Correct, Mr. Eriksson.

I didn’t lock the thread to allow the discussion to continue, and particularly to allow the OP to answer Mr. Holan and MM’s queries.

Peter
OSR

> Why is this error prone (KdPrint)? I had no errors with this.

KdPrint has no compile time checks to make sure the number of parameters and parameter types match the format list. printf gets this type safe checking automatically by current compilers at compile time. Hence, KdPrint leads to crashes and garbled output because mismatches are not caught until run time starts tripping over them.

Since when is “printf” proprietary, KdPrint is just a mapping of the
standard printf from C with a few extended formats

Yes the printf style format lists are nice, but KdPrint itself is not part of the C standard and also requires two sets of parenthesis giving it even a non-standard appearance.

I would even say that cin/cout/cerr is ugly, due to redefining << shift operator to do IO

This is true–sometimes. But it is also sometimes useful to output things without having to specify their type. Using a C analogy, %p will show a 32-bit pointer value on a 32-bit build and a 64-bit pointer value on a 64-bit build. You don’t have to tell it how big the pointer is. Sometimes other data types change in size so having the type be automatic is useful for this.

C++ exceptions just plain increase the mess, unless the whole
code is exception-aware

Even without everything rolled into objects it can be cleaner to just throw something and be done with it rather than tediously tunnel out of all the nested if/else/for/while/switch constructs to the return statement at the bottom of the function. I’ve written a lot of code without exceptions and a lot of code with them. I find code gets cleaner and more compact with them.

There is a list in the kernel - RemoveEntryList and such,
I cannot see why is it worse then STL’s list.

The DDK offers just rudimentary list functionality. In fact, just iterating a list is pretty ugly and error prone due to the blind type casting needed. On the other hand, a STL list is type safe, has a comprehensive set of member functions, iterators that can be used for further functionality, and other desirable behavior in its constructor & destructor. For instance, no need remember that you must first call InitializeListHead before doing anything else. You may say that’s just less typing but for some people that is also less complexity and less error prone. Besides what a STL list offers, you can choose from a suite of data structures including vector, deque, set, or map for the one that best fits the need. No need to reinvent the wheel.

I am anxious to hear from the OP or anyone else on the technical feasibility of these things.

Off-list, Peter Viscarola and I have resolved his concerns regarding the appearance of my original post as commercial in nature. That wasn’t my intention and I apologize to the list for that impression.

As I said at the the beginning of my original post, I don’t intend to discuss the merits of C++ drivers on this list. But I will start a thread over in NTTALK and respond there to the C++ driver issues that have been raised here.

So, onto the other questions/issues that have been raised.

Doron said:

… I want to be clear that there is no support for this in the
compiler …

Of course, the compiler is what defines and provides the necessary structures and interfaces for C++ exceptions to work at all so it’s unclear what you mean by “no support”.

Doron continued:

… and that future compiler changes may break this library.

That’s always a possibility. But I should note here that since it’s a static library, compiler changes won’t affect your existing driver binaries. Also, the compiler structures are versioned (again by the compiler) to preserve the implied ABI. The situation is akin to prior ABI changes in the VC++ compiler: an app compiled with the newest compiler version still needs to interop with DLLs compiled with previous versions.

In any event, by most, it’s considered best-practices to hold onto the DDK/WDK/compiler version with which you release.

Doron said:

How does throwing an exception across call frames which are not C++
aware or written to your framework handle unwind? Ie if you throw from
a callstack like this

Driver!ThrowingFunction
Nt!Foo
Nt!Bar
Driver!CallIntoNt

How can you guarantee state / cleanup in ntoskrnl when Foo and Bar
unwind unexpectedly?

Assuming that Nt!Foo and Nt!Bar unwind reliably when any non-continuable OS exception is ‘thrown’, such as by ExRaiseStatus, then there should be no perceptible difference with our library. That is, the Nt!Foo and Nt!Bar handlers are invoked just like they would be by the OS unwinder.

Similarly, if an OS exception unwinds across the C++ call frame, that frame is properly unwound by us, regardless of whether the exception is “handled” by that frame or not.

All that being said, raising ANY exception across different binaries is imprudent at best unless the anticipated call-stack is well-known. This is true regardless of the origin of the exception.

Also, I should be clear that this library does not perform any OS-magic. Just like an SEH handler, the C++ handler is only going to see those exceptions that are actually dispatched. So, for example, true processor faults at anything other than passive level are still going to bug check, as will processor faults that are never dispatched like bounds, divide-by-zero, etc.

Lastly, mm said:

Peter, do you support x64?

That’s currently delayed for non-technical reasons. Right now, we’re looking at mid-May. It’s hard enough getting out open-source code when we have regular duties to attend to.

Currently, the main shortcoming of our exception handling (and on our To-Do list) is that our dispatcher and unwinder does not validate the handler (ala SafeSEH). So well our handlers will properly validate with the OS, I haven’t coded the image walk yet to be able to validate other handlers.

Hope this clears some misconceptions up.

Thanks,
Peter Hurley

xxxxx@gmail.com” wrote in message
news:xxxxx@ntdev:

> > Why is this error prone (KdPrint)? I had no errors with this.
>
> KdPrint has no compile time checks to make sure the number of parameters and parameter types match the format list. printf gets this type safe checking automatically by current compilers at compile time. Hence, KdPrint leads to crashes and garbled output because mismatches are not caught until run time starts tripping over them.

And most C compilers do not have these checks either. In the DDK
prefast does give you these checks at compile time.
>
> > Since when is “printf” proprietary, KdPrint is just a mapping of the
> > standard printf from C with a few extended formats
>
> Yes the printf style format lists are nice, but KdPrint itself is not part of the C standard and also requires two sets of parenthesis giving it even a non-standard appearance.

This is just because it is a macro, many environments have the same
requirement for a number of similar situations. If you really don’t
like it use DbgPrint.

Sorry but the C++ output model is a mess, and it was argued long and
hard at the original C++ standards committee whether it should be
adopted or thrown out. Using this as an example of why C++ would be
better in the kernel is hard to believe. There are lots of good reasons
to use C++ and if it were not for the problems the current environment
with respect to the kernel has, I think it would be the normal approach.

Don Burn (MVP, Windows DKD)
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

xxxxx@gmail.com wrote:

> Why is this error prone (KdPrint)? I had no errors with this.
KdPrint has no compile time checks to make sure the number of parameters and parameter types match the format list. printf gets this type safe checking automatically by current compilers at compile time.

gcc does. Microsoft’s compilers do not.

Hence, KdPrint leads to crashes and garbled output because mismatches are not caught until run time starts tripping over them.

That is an extremely minor issue. KdPrint is, after all, a debugging
tool, not a production tool. Mismatches are usually quite evident, and
occur during development testing where the impact is low.


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

> Assuming that Nt!Foo and Nt!Bar unwind reliably when any non-continuable OS exception is ‘thrown’, such as by

ExRaiseStatus, then there should be no perceptible difference with our library. That is, the Nt!Foo and Nt!Bar
handlers are invoked just like they would be by the OS unwinder.

Huge assumption to make. I would say <1% of the kernel’s functions are safe from ExRaiseStatus raising and exception below them in the callstack and unwinding expectedly. Nevermind that <0.1% of the drivers out there might actually handle callstack unwinding via ExRaiseStatus. What happens when you throw an exception from that leaks out of the current call frame and your driver is not anywhere up the stack? Unhandled exception/bugcheck?

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Peter Hurley
Sent: Friday, April 15, 2011 7:22 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Writing drivers in C++

Off-list, Peter Viscarola and I have resolved his concerns regarding the appearance of my original post as commercial in nature. That wasn’t my intention and I apologize to the list for that impression.

As I said at the the beginning of my original post, I don’t intend to discuss the merits of C++ drivers on this list. But I will start a thread over in NTTALK and respond there to the C++ driver issues that have been raised here.

So, onto the other questions/issues that have been raised.

Doron said:

… I want to be clear that there is no support for this in the
compiler …

Of course, the compiler is what defines and provides the necessary structures and interfaces for C++ exceptions to work at all so it’s unclear what you mean by “no support”.

Doron continued:

… and that future compiler changes may break this library.

That’s always a possibility. But I should note here that since it’s a static library, compiler changes won’t affect your existing driver binaries. Also, the compiler structures are versioned (again by the compiler) to preserve the implied ABI. The situation is akin to prior ABI changes in the VC++ compiler: an app compiled with the newest compiler version still needs to interop with DLLs compiled with previous versions.

In any event, by most, it’s considered best-practices to hold onto the DDK/WDK/compiler version with which you release.

Doron said:

How does throwing an exception across call frames which are not C++
aware or written to your framework handle unwind? Ie if you throw from
a callstack like this

Driver!ThrowingFunction
Nt!Foo
Nt!Bar
Driver!CallIntoNt

How can you guarantee state / cleanup in ntoskrnl when Foo and Bar
unwind unexpectedly?

Assuming that Nt!Foo and Nt!Bar unwind reliably when any non-continuable OS exception is ‘thrown’, such as by ExRaiseStatus, then there should be no perceptible difference with our library. That is, the Nt!Foo and Nt!Bar handlers are invoked just like they would be by the OS unwinder.

Similarly, if an OS exception unwinds across the C++ call frame, that frame is properly unwound by us, regardless of whether the exception is “handled” by that frame or not.

All that being said, raising ANY exception across different binaries is imprudent at best unless the anticipated call-stack is well-known. This is true regardless of the origin of the exception.

Also, I should be clear that this library does not perform any OS-magic. Just like an SEH handler, the C++ handler is only going to see those exceptions that are actually dispatched. So, for example, true processor faults at anything other than passive level are still going to bug check, as will processor faults that are never dispatched like bounds, divide-by-zero, etc.

Lastly, mm said:

Peter, do you support x64?

That’s currently delayed for non-technical reasons. Right now, we’re looking at mid-May. It’s hard enough getting out open-source code when we have regular duties to attend to.

Currently, the main shortcoming of our exception handling (and on our To-Do list) is that our dispatcher and unwinder does not validate the handler (ala SafeSEH). So well our handlers will properly validate with the OS, I haven’t coded the image walk yet to be able to validate other handlers.

Hope this clears some misconceptions up.

Thanks,
Peter Hurley


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’m not a big fan of C++ exception handling, but if you throw an exception
in your driver that 'leaks out of the current call frame" you have a bug and
the results are unspecified, as with any other bug. In other words, if you
are using c++ exceptions, you have to have handlers for all the exceptions
that can be thrown.

Also, as per the other example:

Driver!ThrowingFunction
Nt!Foo
Nt!Bar
Driver!CallIntoNt

Don’t do that either. :slight_smile:

Mark Roddy

On Fri, Apr 15, 2011 at 4:08 PM, Doron Holan wrote:

> > Assuming that Nt!Foo and Nt!Bar unwind reliably when any non-continuable
> OS exception is ‘thrown’, such as by
> > ExRaiseStatus, then there should be no perceptible difference with our
> library. That is, the Nt!Foo and Nt!Bar
> > handlers are invoked just like they would be by the OS unwinder.
>
> Huge assumption to make. I would say <1% of the kernel’s functions are safe
> from ExRaiseStatus raising and exception below them in the callstack and
> unwinding expectedly. Nevermind that <0.1% of the drivers out there might
> actually handle callstack unwinding via ExRaiseStatus. What happens when
> you throw an exception from that leaks out of the current call frame and
> your driver is not anywhere up the stack? Unhandled exception/bugcheck?
>
> d
>
>
> -----Original Message-----
> From: xxxxx@lists.osr.com [mailto:
> xxxxx@lists.osr.com] On Behalf Of Peter Hurley
> Sent: Friday, April 15, 2011 7:22 AM
> To: Windows System Software Devs Interest List
> Subject: RE:[ntdev] Writing drivers in C++
>
> Off-list, Peter Viscarola and I have resolved his concerns regarding the
> appearance of my original post as commercial in nature. That wasn’t my
> intention and I apologize to the list for that impression.
>
> As I said at the the beginning of my original post, I don’t intend to
> discuss the merits of C++ drivers on this list. But I will start a thread
> over in NTTALK and respond there to the C++ driver issues that have been
> raised here.
>
> So, onto the other questions/issues that have been raised.
>
> Doron said:
> > … I want to be clear that there is no support for this in the
> > compiler …
>
> Of course, the compiler is what defines and provides the necessary
> structures and interfaces for C++ exceptions to work at all so it’s unclear
> what you mean by “no support”.
>
> Doron continued:
> > … and that future compiler changes may break this library.
>
> That’s always a possibility. But I should note here that since it’s a
> static library, compiler changes won’t affect your existing driver binaries.
> Also, the compiler structures are versioned (again by the compiler) to
> preserve the implied ABI. The situation is akin to prior ABI changes in the
> VC++ compiler: an app compiled with the newest compiler version still needs
> to interop with DLLs compiled with previous versions.
>
> In any event, by most, it’s considered best-practices to hold onto the
> DDK/WDK/compiler version with which you release.
>
> Doron said:
> > How does throwing an exception across call frames which are not C++
> > aware or written to your framework handle unwind? Ie if you throw from
> > a callstack like this
> >
> > Driver!ThrowingFunction
> > Nt!Foo
> > Nt!Bar
> > Driver!CallIntoNt
> >
> > How can you guarantee state / cleanup in ntoskrnl when Foo and Bar
> > unwind unexpectedly?
>
> Assuming that Nt!Foo and Nt!Bar unwind reliably when any non-continuable OS
> exception is ‘thrown’, such as by ExRaiseStatus, then there should be no
> perceptible difference with our library. That is, the Nt!Foo and Nt!Bar
> handlers are invoked just like they would be by the OS unwinder.
>
> Similarly, if an OS exception unwinds across the C++ call frame, that frame
> is properly unwound by us, regardless of whether the exception is “handled”
> by that frame or not.
>
> All that being said, raising ANY exception across different binaries is
> imprudent at best unless the anticipated call-stack is well-known. This is
> true regardless of the origin of the exception.
>
> Also, I should be clear that this library does not perform any OS-magic.
> Just like an SEH handler, the C++ handler is only going to see those
> exceptions that are actually dispatched. So, for example, true processor
> faults at anything other than passive level are still going to bug check, as
> will processor faults that are never dispatched like bounds, divide-by-zero,
> etc.
>
> Lastly, mm said:
> > Peter, do you support x64?
>
> That’s currently delayed for non-technical reasons. Right now, we’re
> looking at mid-May. It’s hard enough getting out open-source code when we
> have regular duties to attend to.
>
>
> Currently, the main shortcoming of our exception handling (and on our To-Do
> list) is that our dispatcher and unwinder does not validate the handler (ala
> SafeSEH). So well our handlers will properly validate with the OS, I haven’t
> coded the image walk yet to be able to validate other handlers.
>
> Hope this clears some misconceptions up.
>
> Thanks,
> Peter Hurley
>
>
> —
> 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
>

The LIST_ENTRY support provided by the WDK has some important properties that STL linked lists don’t have – notably that once you have allocated an element, you are guaranteed to be able to insert the element into its list without having to acquire more memory.

Unlike some portions of user mode code, kernel mode code often has an absolute requirement to allocation failure safe (and in particular, forward-progress-safe even in the face of allocation failures, such that even if the system has no memory available, already in-flight operations can continue to completion).

With datastructures that require additional memory allocations at insertion time, these problems (which are already often quite complicated) become significantly more difficult to manage. For example, with STL datastructures, one cannot transfer an element from one list to another without taking an allocation failure (potentially). If moving the element from one list to another happened to be important for actually being able to complete the associated request (and thus properly release the resources associated the request), you’ve got a serious problem if you can take an allocation failure on that path; if you can’t complete the request (and release resources) without grabbing more memory, but you can’t grab more memory, you’re essentially fundamentally sunk.

Given these complexities, I would generally recommend avoiding the use of STL datastructures and containers in forward-progress required situations. such as what a significant portion of well-written kernel mode code falls under. Trying to support guaranteed forward progress with the STL is something I have found to be very painful due to their common design where essentially all of the containers must allocate resources in order to link an object into them.

I’ll also note that there’s a substantial amount of logic that one would necessarily have to reinvent from scratch in order to support full CL try/catch semantics (as far as I know, there isn’t documentation describing the underlying implementation). That’s quite a lot of tricky code to reverse engineer the interface for and build up from scratch where getting anything wrong is likely to result in rather painful debugging sessions. (Even with full documentation and access to the compiler team, that’s still a rather arcane and complex chunk of code.)

  • S

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Friday, April 15, 2011 7:13 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Writing drivers in C++

Why is this error prone (KdPrint)? I had no errors with this.

KdPrint has no compile time checks to make sure the number of parameters and parameter types match the format list. printf gets this type safe checking automatically by current compilers at compile time. Hence, KdPrint leads to crashes and garbled output because mismatches are not caught until run time starts tripping over them.

Since when is “printf” proprietary, KdPrint is just a mapping of the
standard printf from C with a few extended formats

Yes the printf style format lists are nice, but KdPrint itself is not part of the C standard and also requires two sets of parenthesis giving it even a non-standard appearance.

I would even say that cin/cout/cerr is ugly, due to redefining <<
shift operator to do IO

This is true–sometimes. But it is also sometimes useful to output things without having to specify their type. Using a C analogy, %p will show a 32-bit pointer value on a 32-bit build and a 64-bit pointer value on a 64-bit build. You don’t have to tell it how big the pointer is. Sometimes other data types change in size so having the type be automatic is useful for this.

C++ exceptions just plain increase the mess, unless the whole
code is exception-aware

Even without everything rolled into objects it can be cleaner to just throw something and be done with it rather than tediously tunnel out of all the nested if/else/for/while/switch constructs to the return statement at the bottom of the function. I’ve written a lot of code without exceptions and a lot of code with them. I find code gets cleaner and more compact with them.

There is a list in the kernel - RemoveEntryList and such, I cannot see
why is it worse then STL’s list.

The DDK offers just rudimentary list functionality. In fact, just iterating a list is pretty ugly and error prone due to the blind type casting needed. On the other hand, a STL list is type safe, has a comprehensive set of member functions, iterators that can be used for further functionality, and other desirable behavior in its constructor & destructor. For instance, no need remember that you must first call InitializeListHead before doing anything else. You may say that’s just less typing but for some people that is also less complexity and less error prone. Besides what a STL list offers, you can choose from a suite of data structures including vector, deque, set, or map for the one that best fits the need. No need to reinvent the wheel.

I am anxious to hear from the OP or anyone else on the technical feasibility of these things.


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

Good comments all. If guaranteed forward progress is needed, which doesn’t come into play for the vast majority of drivers I may add, a STL list or other appropriate container can still be leveraged. For instance, reserve elements can be put on tap when needed through custom allocators or advance resizing techniques. KMDF employs a similar strategy to guarantee forward progress. But in any situation it just comes down to choosing the right tool for the job and sometimes that could even be to use a LIST_ENTRY as usual.

Doron,

Sorry, I interpreted your original question about the call stack assuming that you were asking how the unwinder would invoke the exception handlers of Nt!Foo and Nt!Bar. Based on your response to my answer, I see now that you mean if Nt!Foo and Nt!Bar don’t have exception handlers, how would the unwinder undo what those functions had done?

So, for example, if Nt!Foo acquired a spinlock, would the unwinder automatically release the spinlock, even in the absence of an exception handler to explicitly perform that?

No - the unwinder is not going to do that. That would be significantly outside of the scope of any exception unwinder. But realistically I don’t think anyone would have expected that to work. User-mode exception handling doesn’t work like that. If you create a file in user-mode C++ and assign the resultant file handle to a local POD variable, leaving the scope is not going to close the file for you.

As Mark suggested, don’t let the exception leave Driver!ThrowingFunction. And yeah, we get that the vast majority of k-mode OS and most drivers are not exception-safe. A good rule-of-thumb to follow when using C++ exceptions in kernel-mode code is that it will work whenever __try/__except/__finally would have worked.

Also, I just want to clear up that we don’t actually use ExRaiseStatus to generate exceptions.

In fact, quoting Ken:

I’ll also note that there’s a substantial amount of logic that one would necessarily have to reinvent from scratch in order to support full CL try/catch semantics (as far as I know, there isn’t documentation describing the underlying implementation). That’s quite a lot of tricky code to reverse engineer the interface for and build up from scratch where getting anything wrong is likely to result in rather painful debugging sessions. (Even with full documentation and access to the compiler team, that’s still a rather arcane and complex chunk of code.)

That is exactly what this library is/does (without access to the compiler team).

The only area we diverged was in SEH translation: rather than calling a user-defined function which throws, we generate a library-defined type (system_exception) as the thrown type.

Regards,
Peter Hurley

>function. I’ve written a lot of code without exceptions and a lot of code with them. I find code gets cleaner and more

compact with them.

Cleaner - yes, more compact - yes, but this does not mean more correct.

If some resource is not wrapped to the class with destructor - then exceptions can trivially introduce a hard-to-catch bug.

The DDK offers just rudimentary list functionality. In fact, just iterating a list is pretty ugly and error prone due to >the blind type casting needed. On the other hand, a STL list is type safe, has a comprehensive set of member functions, iterators that can be used for further functionality, and other desirable behavior in its constructor & destructor. For instance, no need remember that you must first call InitializeListHead before doing anything else. You may say that’s just less typing but for some people that is also less complexity and less error prone. Besides what a STL list offers, you can choose from a suite of data structures including vector, deque, set, or map for the one that best fits the need. No need to reinvent the wheel.

I am anxious to hear from the OP or anyone else on the technical feasibility of these things.

> The DDK offers just rudimentary list functionality. In fact, just iterating a list is pretty ugly and error prone due to

the blind type casting needed.

In the good hands - not error-prone at all.

The danger of type-insafety is aggravated a lot. Absolutely a lot.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com