|
|
Subscribe / Log in / New account

Bjarne Stroustrup’s Plan for Bringing Safety to C++ (The New Stack)

Bjarne Stroustrup’s Plan for Bringing Safety to C++ (The New Stack)

Posted Nov 2, 2023 16:33 UTC (Thu) by adobriyan (subscriber, #30858)
In reply to: Bjarne Stroustrup’s Plan for Bringing Safety to C++ (The New Stack) by mathstuf
Parent article: Bjarne Stroustrup’s Plan for Bringing Safety to C++ (The New Stack)

> Considering a C implementation's `unsafe` block count is approximated by `wc -l`, what is your point?

My point, only now there will be some production Linux Rust code.

As for "wc -l" part, the statement is far from true.

Imagine you're an independent auditor tasked with reviewing Linux C binder code.
You're reading it and red-penning everything you can't prove to yourself is correct.

For example it is quite easy to verify that binder_ctl_ioctl() is OK:
* struct binderfs_device doesn't have padding -- good

even better to have builtin __builtin_type_has_padding() and refuse copy_from_user/copy_to_user on types which have padding, but OK.

* copy_from_user() is correct, although that block is verbosely written (which is not a bug).

* binderfs_binder_device_create() does some shenanigans with inodes,
quota and ACL aren't initialised.
Rust must scream here but it is OK, because Binder doesn't support quotactl and ACLs.

* req->name[BINDERFS_MAX_NAME] = '\0'; /* NUL-terminate */
Hell, yes! Comment is of "increment i by 1" variety (which is not a bug).

* first memory allocation

device = kzalloc(sizeof(*device), GFP_KERNEL);
inode->i_private = device;

Eww, scary pointers... But VFS guarantees to not touch i_private (and, god forbid, free it), so

kfree(device);
iput(inode);

is OK.

* second memory allocation
name = kmemdup(req->name, name_len + 1, GFP_KERNEL);
device->context.name = name;
device->miscdev.name = name;

Eww, sketchy territory, naked pointers, unrefcounted, but searching for "context.name" shows that only 1 is freed.
and "miscdev.name" is not freed, phew.

* backcopy
if (userp && copy_to_user(userp, req, sizeof(*req))) {

if (userp) is obviously unnecessary, because it was used to copy _from_ userspace thus a valid pointer.

"req" was mutated by clearing last byte to '\0' which doesn't leak secret kernel data, so OK.
Ergo, it safe to ship to userspace.

Now suddenly (221 - 111) + (256 - 233) = 133 LOC are most certainly safe, not unsafe.

This "all C code is unsafe" is such a non true.


to post comments

Bjarne Stroustrup’s Plan for Bringing Safety to C++ (The New Stack)

Posted Nov 2, 2023 17:05 UTC (Thu) by ojeda (subscriber, #143370) [Link] (2 responses)

> As for "wc -l" part, the statement is far from true.

From your comment, I think you misunderstand what "safe" means in Rust.

It does not mean "the lines do not have UB because I checked" (like you do in your comment). It is the other way around -- that would be "unsafe" Rust.

In C, essentially any non-trivial line may contain UB. That is why they are "unsafe" in Rust terms, and why the statement about `wc -l` is quite close to reality.

Bjarne Stroustrup’s Plan for Bringing Safety to C++ (The New Stack)

Posted Nov 2, 2023 17:29 UTC (Thu) by adobriyan (subscriber, #30858) [Link] (1 responses)

> In C, essentially any non-trivial line may contain UB.

"may contain" doesn't mean "contains". This fixation on UB is partially misguided.

> That is why they are "unsafe" in Rust terms, and why the statement about `wc -l` is quite close to reality.

C/C++ static checkers/compilers don't require to mark code with "safe" or "unsafe" and don't mark code themselves ex post facto.
Rustc requires unsafe marks thus creating the illusion that close to 100% of C/C++ code is unsafe.

I'm writing toy C compiler at the moment:
* C expressions are allocated from stable container,
* expressions form AST with pointers pointing to other expressions,
* pointers to expressions are never freed,
* references and other form of pointers aren't used,
* stable container is globally destructed when program exists (which is waste of cycles but this is for later).

It is easy to verify for a human at high level (and sanitizers confirm) that there are no leaks and
there are no bugs with pointer management despite having a awful lots of pointers.

Bjarne Stroustrup’s Plan for Bringing Safety to C++ (The New Stack)

Posted Nov 2, 2023 17:42 UTC (Thu) by mb (subscriber, #50428) [Link]

> It is easy to verify for a human at high level (and sanitizers confirm) that there are no leaks and
>there are no bugs with pointer management despite having a awful lots of pointers.

Yep. And that is what Rust calls "unsafe code, manually checked".
Safe code would be, if the compiler itself could prove that without human intervention.

Get it now?


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds