C++ for kernel drivers

Hi Experts

Their is a Microsoft document “C++ for Kernel Mode Drivers: Pros and Cons”

Using the C++ compiler in this way is typically expected to work for kernel-mode code. It is ?advanced? C++ features such as non-POD (?plain ol? data?, as defined by the C++ standard) classes and inheritance, templates, and exceptions that present problems for kernel-mode code. These problems are due more to the C++ implementation and the kernel environment than to the inherent properties of the C++ language.

But I am not able to fully grasp why some C++ will have issues in kernel mode.
Can someone with more insight explain in simple terms what are the problems of using C++ in kernel mode.

xxxxx@hotmail.com wrote:

Their is a Microsoft document “C++ for Kernel Mode Drivers: Pros and Cons”

Please note that this document was written in 2004. That is practically
the stone age, in kernel programming terms. The reality today is quite
significantly different. Remember, for example, that KMDF is all
written in C++.

Using the C++ compiler in this way is typically expected to work for kernel-mode code. It is ?advanced? C++ features such as non-POD (?plain ol? data?, as defined by the C++ standard) classes and inheritance, templates, and exceptions that present problems for kernel-mode code. These problems are due more to the C++ implementation and the kernel environment than to the inherent properties of the C++ language.

But I am not able to fully grasp why some C++ will have issues in kernel mode.
Can someone with more insight explain in simple terms what are the problems of using C++ in kernel mode.

Today, the only big problem is exceptions. Exception handling in Visual
Studio requires processor-specific support in the run-time library that
the kernel does not provide. And, unfortunately, the STL relies heavily
on exceptions. It would be really nice to have std::vector and
std::list in driver code.

I did once see a hacked-up library that added support for C++ exceptions
to the kernel written by one of the former luminaries of this list, but
it frightened me and I backed slowly away.

In the past, the big problem was with compiler-generated code, like
templates and automatic constructors and destructors, because the
compiler did not provide any way to specify where such code would be
placed. In a driver that carefully balanced code between paged- and
non-paged sections, it was easy to have the compiler make the wrong
choice. This problem has largely been solved.


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

Microsoft officially supports a subset of C++ in the kernel. The specific features that are missing are documented here: https://docs.microsoft.com/en-us/cpp/build/reference/kernel-create-kernel-mode-binary

As Mr Roberts said, parts of the OS are now written in kernel C++, so it definitely works.

Also as Mr Roberts said, a major problem is the lack of libraries. I’m slowly trying to pull something together, but it’ll be a while before it’s ready for consumption.

> I’m slowly trying to pull something together

Whatever you do, do it it in the realm of std:: The last thing we need is some oddball, proprietary library introduced in the 21st century.

> Whatever you do, do it it in the realm of std::

Point taken.

The complicating factor, and the reason we didn’t just publish the usermode STL as-is, is that much of std:: assumes that C++ exceptions work. Of course there are odds and ends that *do* work without C++ exceptions, (like std::move, std::unique_ptr or all the traits stuff), and I do want to cherry-pick those unmodified. But std::vector, for example, has no way to report errors. We need some new thing to represent a variable-sized array. Or I suppose, do the work to get C++ exceptions onto the kernel’s C runtime. (Although I’m not wild about that idea.)

There’s also some kernel-specific concerns. For example, usermode is pretty okay with assuming a single default allocator for all things. The usermode CRT gives you a default “operator new” that just goes to malloc. But in kernel there is no single pool that’s the right default for everyone. We experimented a bit here. One option is to make the caller always specify the pool:

new (NonPagedNx) Thing();

but that gets difficult when the caller is buried inside some infrastructure, like std::make_unique. Another approach I’ve looked at is to hardcode the pool into the object’s type:

struct Thing : AllocNonPagedNx { };

That lets you call new without additional arguments. But now it’s inflexible – if you implement a string class, you don’t want it to hardcode paged or nonpaged.

This ends up being foundational stuff, so I want to get it right. There really needs to be one set of types that everyone uses, or else you wind up with a fight over which header implements “member operator new” or “global operator new”.

Anyway, we have some C++ headers internally, and I’m slowly improving them. When I get the time, I’m planning on publishing them in a more reusable fashion. (A few of the headers are already on github, buried in a sample driver.)

Kudos to Mr, Tippett for doing ANYthing in this space. It’s not like it’s his day job, and anything that’ll move Windows kernel-mode programming into the 21st century is truly Gxd’s work.

If we’re voting, I vote for making the GSL work in kernel mode and scoring a victory for code quality.

Peter
OSR
@OSRDrivers

As an employer endorsed hobby project, I’ve been working on porting a subset of libc++ to the Windows kernel. Libc++ is the standard library associated with clang / llvm, and is used in the various Apple platforms and BSD platforms.

Here’s a link to the initial RFC I made on the developer’s mailing list, back in March. There’s some responses and commentary from the Libc++ maintainers, as well as several of the (user mode) Microsoft C++ library maintainers.
http://lists.llvm.org/pipermail/cfe-dev/2017-March/053313.html

The project has been rather slow going, because I only spend 3-4 hours a week working on it. Most of my current efforts on this project have been setting up infrastructure for running the upstream tests.

Benefits of my approach:
All the things that get ported will have 100% standard semantics.

Downside of my approach:
Nothing that requires exceptions will be included in the port. No vector, no list, no shared_ptr, no std::thread.

Eventually, I want to have enough implementation experience with this approach to try to get this subset standardized as the “freestanding” implementation. C++ already has a definition for a freestanding implementation, but it requires the and headers to be implemented.

Jeffrey Tippet wrote:

The complicating factor, and the reason we didn’t just publish the usermode STL as-is, is that much of std:: assumes that C++ exceptions work. Of course there are odds and ends that *do* work without C++ exceptions, (like std::move, std::unique_ptr or all the traits stuff), and I do want to cherry-pick those unmodified. But std::vector, for example, has no way to report errors. We need some new thing to represent a variable-sized array.

Years ago – at least through the 3790 DDK – Microsoft shipped an
exception-free version of STL in the DDK, produced by Dinkumware. It
wouldn’t be standard-compliant today, but it was a great start.

Or I suppose, do the work to get C++ exceptions onto the kernel’s C runtime. (Although I’m not wild about that idea.)

It can be done. Walter Oney created such a monster near the turn of the
century.


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