←back to thread

837 points turrini | 3 comments | | HN request time: 0.276s | source
Show context
titzer ◴[] No.43971962[source]
I like to point out that since ~1980, computing power has increased about 1000X.

If dynamic array bounds checking cost 5% (narrator: it is far less than that), and we turned it on everywhere, we could have computers that are just a mere 950X faster.

If you went back in time to 1980 and offered the following choice:

I'll give you a computer that runs 950X faster and doesn't have a huge class of memory safety vulnerabilities, and you can debug your programs orders of magnitude more easily, or you can have a computer that runs 1000X faster and software will be just as buggy, or worse, and debugging will be even more of a nightmare.

People would have their minds blown at 950X. You wouldn't even have to offer 1000X. But guess what we chose...

Personally I think the 1000Xers kinda ruined things for the rest of us.

replies(20): >>43971976 #>>43971990 #>>43972050 #>>43972107 #>>43972135 #>>43972158 #>>43972246 #>>43972469 #>>43972619 #>>43972675 #>>43972888 #>>43972915 #>>43973104 #>>43973584 #>>43973716 #>>43974422 #>>43976383 #>>43977351 #>>43978286 #>>43978303 #
card_zero ◴[] No.43972675[source]
I don't trust that shady-looking narrator. 5% of what exactly? Do you mean that testing for x >= start and < end is only 5% as expensive as assigning an int to array[x]?

Or would bounds checking in fact more than double the time to insert a bunch of ints separately into the array, testing where each one is being put? Or ... is there some gimmick to avoid all those individual checks, I don't know.

replies(2): >>43975158 #>>43989229 #
1. timbit42 ◴[] No.43975158[source]
You only need to bounds check once before a for loop starts, not every iteration.
replies(2): >>43976236 #>>43988812 #
2. card_zero ◴[] No.43976236[source]
If they're all being inserted contiguously.

Anyway that's a form of saying "I know by reasoning that none of these will be outside the bounds, so let's not check".

3. ryao ◴[] No.43988812[source]
It depends on the loop. Here are a bunch of loops that need bounds checks on every loop iteration:

https://github.com/openzfs/zfs/commit/303678350a7253c7bee9d6...

You could argue otherwise and you would not be wrong since the codebase had not given this code inputs that would overrun the buffer. However, any case where you loop until the string is built needs a check on each iteration unless you can both prove that the buffer will always be long enough for any possible output and guarantee that future changes will preserve this property. The former is a pain (but doable) while the latter was infeasible, which is why the bounds checks were added.

That said, something as innocuous as printing a floating value could print 308 characters where you only expected 10 or less:

https://github.com/openzfs/zfs/commit/f954ea26a615cecc8573bb...

Edge cases causing things to print beyond what was expected are a good reason why people should use bounds checks when building strings, since truncation is fail safe, while overrunning the buffer is fail dangerous. I am a fan of the silent truncation done in both patches, since in both cases, truncation is harmless. For cases where silent truncation is not harmless, you can use detect the truncation by checking the return value of `snprintf()` and react accordingly. It should be said that the scnprintf() function's return value does not permit truncation detection and `snprintf()` should be used if you want that.

Note that I am the author of those two patches, so it is natural that I like the approach I used. They were written as part of an audit of the OpenZFS codebase I did when bug hunting for fun.