4 ms·
Really sad to see so many people rail on this. Here's all the examples I've seen shitting on it and why MISRA is correct despite their objections. 1. ""no ear
by maldev 3y ago
Really sad to see so many people rail on this.
Here's all the examples I've seen shitting on it and why MISRA is correct despite their objections.
1. ""no early return" rule"
In C, you have to be really careful with your flow control and memory allocations. So basically ALL good C programmers and styles dictate that you use GOTO's for one location, a "cleanup" location, in which you check and free memory. So if you do
if(!ptr)
return;
You do
if(!ptr)
{
DEBUGLOG("Error allocation ptr");//Also prints out file, line, function etc.
bRet = FALSE;
goto cleanup;
}
Very common, and you can't ever mess up freeing memory. This is why it's used.
2. No magic numbers.
Another person complains about not being able to do magic numbers. While it can get tedious, you really shouldn't. They use the most insane example of #define ONE 1. BUT, even in this case you can argue that if the requirements were changed for a base 8 or other numbers system, you could easily port the app by just changing these define macro's rather than scouring through the code. It's not that tedious, and it can make the codebase more flexible and solve issues and porting.
3. Not able to use 'int'
You should always be explicit with your types. Even rust mainly makes you use sized variables. Why just do int, be specific, you may want int32. The C standard is pretty flexible with things like "long" just being bigger or the same size than "int". So porting things like this makes it robust. You also have the fact that if you do any networking or messages of any kind, this makes the datastructures easily portable since you know exactly what size.
- almostnormal 3y ago> Very common, and you can't ever mess up freeing memory. Except that where misra is applied, there often is no dynamic allocation at all.
- RealityVoid 3y agoMost of the times, not always. They sometimes don't use malloc or free but their own special little memory pools.
- BeetleB 3y agoFrom my experience in automotive, the ISO standard is against dynamic allocation if your system is classified high enough in terms of their safety levels. As an example, we weren't allowed to use the C++ string class, and had to find a "safer" string class for C++. (Not sure about MISRA - most of my experience is with the ISO standard, and MISRA is not mandated by it).
- RealityVoid 3y agoYeah, so what they do is they don't use free and malloc, but use a bunch of buffers they free. Tadaa! We don't have dynamic allocation, just buffers, see? I've seen it, I can count in AUTOSAR systems like... 20 different hand spun allocators, 10 ques and 50 special little hierarchical state machines.
- DaiPlusPlus 3y agoForgive my lack of exposure to safety-critical C, but without dynamic allocation how does a program handle large state with indeterminate lifetimes? Or when you need a temporary buffer that’s too big to live on the stack?
- RealityVoid 3y agoYou make the stack bigger. You might think I'm joking, but I'm not. Or you make it static. You can work around it just fine.
- BeetleB 3y ago> but without dynamic allocation how does a program handle large state with indeterminate lifetimes? If you haven't, I strongly encourage taking a workshop/course on requirements engineering (not specific to SW nor safety). One thing that stood out is a requirement that says things like "indeterminate" or "large" are red flags. A requirement should state bounds on what sizes it should handle. > Or when you need a temporary buffer that’s too big to live on the stack? Do you have an example of where this may occur in a safety critical system? I've forgotten the details, but many/most forbidden things are allowed in the code provided you have watchdogs for mitigation - so if things did fail it could safely shut down. I don't recall if dynamic allocation fell into that category.
- deleted 3y ago[deleted]
- RealityVoid 3y agoMISRA is sometimes unfairly shat on, sure, but some things do require you to use your brain. Regarding magic numbers, if my memory is not playing tricks on me, MISRA does not include 0 or 1 as magic numbers. Regardless, 1 is 1 regardless the number system you work in, I have never ever seen someone "yes, let's make 1 not be 1" (not in a sane way at least) and defining stuff like that for "improved flexibility" is an antipattern in my book. It makes code bigger, harder to navigate and understand. That kind of code does unexpected stuff, is hard to work with and has more bugs. The less surprises, the less indirection I get in a code base, the better. I also feel it makes refactoring harder not easier. I speak from experience, I've worked with codebases like that, they suck. (Hello Vector, if anyone working for them is out there!)
- bluGill 3y ago#define ONE 1 is bad code. good code would be #define MAX_FOO 1 #define TOTAL_SUPPORTED_BAR_COUNT 1 #define STATUS_BYTE_OFFSET 1 The important thing there is even though all are one we have both given them a unique name, and indicated why they are one.
- lordfrito 3y ago> 2. No magic numbers. > > Another person complains about not being able to do magic numbers. While it can get tedious, you really shouldn't. They use the most insane example of #define ONE 1. BUT, even in this case you can argue that if the requirements were changed for a base 8 or other numbers system, you could easily port the app by just changing these define macro's rather than scouring through the code. It's not that tedious, and it can make the codebase more flexible and solve issues and porting. I agree with you on magic numbers in general, but there have to be practical limits. I was paid to deliver tight production code that was performant, often interfacing with assembly because that was what we had to do with the cheap micro our project used. I wasn't worried about other number systems, it wasn't worth spending R&D $$$ to make the code compatible with other number systems. I'm not writing code that will last 100 years. I deliver to schedules and budgets. Your arguments strike me as a bit too rigid, too academic. Not practical in the real world. In my mind if (condition) num_found = num_found + 1 is clearly superior than this MISRA version if (condition) num_found = num_found + ONE Because the first case is the simplest implementation, incredibly explicit as it. We're counting something. That's abundantly clear. The second case is inferior because, as a reviewer doing their job, I have to go and lookup what ONE actually is. In case someone defined it weird. I start thinking "Maybe it's not 1, maybe it's 1.0". or "maybe its fixed point like (1.0 * 256)." The moment I'm wondering what ONE is actually defined as, I'm no longer thinking about the code I'm reviewing. I have to interrupt my mental process to go find ONE, understand that, and then come back and pick up with what I was reviewing. This stuff matters. Clarity matters. When 1 might not be 1, well then I have to think harder. Compounded, all these little complications dilutes the quality of the code overall. And programmer resources and time are limited. Also, not to nitpick but your example "goto cleanup" is also not MISRA compliant. I'd argue that use of gotos is a greater sin than returning early. I'm pragmatic. I've used gotos, where it makes sense, which is almost never. But never say never. Gotos are nearly always bad. Early returns are useful sometimes. Assembly should be avoided when possible. Code is a tradeoff. When writing interrupt service routines, performance matters, and I found this is where I broke the MISRA rules the most. Because the code had to be tight. That was the value my company brought to the customer. We could get out of the interrupt quick enough to guarantee deadlines in the rest of the code. You do this by letting yourself write complex code in some places, the places that matter. And you scrutinize those more than you do the rest of the code. MISRA (as misapplied by mid level managers) pretends the above statement doesn't matter.
- Krssst 3y ago> In C, you have to be really careful with your flow control and memory allocations I was going to ask if an early return could still be called "early" if there were resources to free, but I would say error checking after locking an object would still qualify (releasing the lock being necessary). C++ helps with this with RAII.