5 ms·
> Zeroing memory often means that buggy code will have consistent behavior; by definition it will not have correct behavior. And consistently incorrect behavior
by avian 11y ago
> Zeroing memory often means that buggy code will have consistent behavior; by definition it will not have correct behavior. And consistently incorrect behavior can be more difficult to track down.
I agree that using calloc should not be an excuse for writing sloppy initialization code. But in my experience, inconsistently incorrect behaviour (e.g. heisenbugs that tend to appear and disappear depending on the content of some random chunk of uninitialized memory that happens to be in an unfortunate state after malloc) are one of the hardest type of bugs to fix. It's the type of the bug that occasionally happens in production and typically can't be reproduced in a controlled manner in a development environment. I certainly prefer consistently incorrect behavior.
- XorNot 11y agoIt's also more secure. We've just this week now had an SSH bug where random chunks of memory get dumped somewhere they shouldn't (not that I'm clear on if calloc would help in this case, but the issue remains). Zeroing memory is just good habit - it's means you don't wind up accidentally leaking things when you make a mistake. And you should assume you will.
- JoachimSchipper 11y agocalloc is not relevant to that issue - it's an out-of-bounds read. (Good ASLR does help, by turning such issues into crash bugs.)
- anon1385 11y agohttps://www.qualys.com/2016/01/14/cve-2016-0777-cve-2016-0778/openssh-cve-2016-0777-cve-2016-0778.txt https://www.qualys.com/2016/01/14/cve-2016-0777-cve-2016-077... >- "out_start == out_last" (lines 205-206): no data was ever written to out_buf (and both out_start and out_last are still equal to 0) because no data was ever sent to the server after roaming_reply() was called, but the client sends (leaks) the entire uninitialized out_buf to the server (line 214), as if out_buf_size bytes of data were available.
- TazeTSchnitzel 11y agoHeartbleed wasn't an out-of-bounds read.
- user9982 11y agoThis bug isn't heartbleed. Also Heartbleed was SSL, not SSH.
- TazeTSchnitzel 11y agoI'm aware.
- notalaser 11y agoIf OpenSSL had used calloc() everywhere instead of malloc(), Heartbleed would have still happened.
- dietrichepp 11y agoThe tools for rooting out these problems have gotten a lot better, thankfully. I'm very fond of the address sanitizer. Using calloc() everywhere can prevent the address sanitizer from finding problems.
- neopallium 11y agoGCC (>=4.8) & Clang now have Address Sanitizer support for fast memory error detection. About a 2x slowdown [1]. 0. https://github.com/google/sanitizers/wiki/AddressSanitizer https://github.com/google/sanitizers/wiki/AddressSanitizer 1. https://github.com/google/sanitizers/wiki/AddressSanitizerPerformanceNumbers https://github.com/google/sanitizers/wiki/AddressSanitizerPe...
- gsg 11y agoYou could try to split the difference by using a wrapper around malloc that zeroes in production and doesn't under testing. Of course, running significantly different code in production and test has its own issues.
- DrJokepu 11y agoI mean, reading zeroed out memory is not really incorrect behaviour anyway. If you know that it was zeroed out, then you're really just reading memory that was initialised with a specific default value. That being said, zeroing out everything you allocate will make it difficult for the kernel's paging system to defer allocating you a physical page until you actually need it, so you will need to be a lot more careful with your allocations if your application uses relatively large amounts of memory and you need to work with memory constraints.
- rc4algorithm 11y agoUnless the zeroing is defined by the language, assuming it t is incorrect and shouldn't be done.
- lmm 11y agoCalloc is defined to return memory that's all-bits-zero, which in turn defines the value for many datatypes. The overwhelming majority of C implementations additionally define the values of all-bits-zero floats and pointers. IMO it's reasonable to write programs targeting only such implementations, provided such a dependency is clearly documented (just as e.g. it's reasonable to write C programs targeting only implementations on which floating-point arithmetic is IEEE 754, despite this not being required by the C standard).
- rc4algorithm 11y ago> The overwhelming majority of C implementations additionally define the values of all-bits-zero floats and pointers. So... Clang and GCC? Regardless, you're ignoring the obvious difference: that isn't POSIX- or ISO-defined at all. If you choose to use it, you're using a weird dialect. Might as well just switch to Cyclone.
- lmm 11y ago> that isn't POSIX- or ISO-defined at all. If you choose to use it, you're using a weird dialect. People used C (even on multiple compilers) long before POSIX or ISO. You're putting the standardization cart before the compatibility horse.
- appleflaxen 11y agoGreat point. This is the part I disagree with most strongly: > And consistently incorrect behavior can be more difficult to track down.
- rc4algorithm 11y agoAll of that useless zeroing is very painful from a performance perspective. It just isn't a reasonable option in performance-relevant code like kernels and core infrastructure. The Moore's Law argument doesn't apply because memory bus latencies and case pressure are lasting problems.
- efaref 11y agoOn high-performance code for an embedded PPC system I used to work on, we made all our control block a multiple of the L1 cache width. Our allocation routines then all had inline assembler to run the dcbz instruction (data cache block zero) on all the cache blocks for the control block as it was allocated. This meant the control block was always zeroed, and the memory bus wasn't touched in order to do so. Yes, things were evicted from the cache, but since we're about to start writing things into the control block, the lack of fetch was a net gain.
- ori_b 11y agoA better solution in this case is to fill the memory with junk -- 0xdeadbeef is a popular solution.