#include <cstdlib>
#include <span>
__attribute__((annotate("realtime")))
void process_floats(std::span<float> vec)
{
auto filter = (float*) malloc(sizeof(float) * vec.size());
/* fill filter with values */
for(int i = 0; i < vec.size(); i++)
vec[i] *= filter[i];
free(filter);
}
$ stoat-compile++ -c foo.cpp -emit-llvm -std=c++20
$ stoat foo.bc
Parsing 'foo.bc'...
Error #1:
process_floats(std::span<float, 18446744073709551615ul>) _Z14process_floatsSt4spanIfLm18446744073709551615EE
##The Deduction Chain:
##The Contradiction Reasons:
- malloc : NonRealtime (Blacklist)
- free : NonRealtime (Blacklist)
oh noes :((The bullshit about oh my embedded systems doesn't have dynamic memory is bullshit. You either know how big your stack is and how many elements there are, and you make the array that big. Or you don't know and you're fucked.
You can't clever your way out of not knowing how big to make the array with magic stack fairy pretend dynamic memory. You can only fuck up. Is there room for 16 elements? The array is 16. Is there room for 32? It's 32.
Though I do wonder why there can't be a form of malloc that allocates in a stack like fashion in real time to satisfy the formal verifier?
But strictly speaking the only problem is a malloc/free that can lock (you can end up with priority inversion). So a lock-free malloc would be realtime just fine, it doesn't have to be stack growth only.
I think you meant to say something else? Real-time is a property of the system indicating a constraint on the latency from the input to the output—it doesn't constrain the input itself. (Otherwise even 'cat' wouldn't be real-time!)
`cat` can be realtime, but only by fixing the size of its internal buffer where it reads to and writes from. In this case it can in theory bound the time needed to process the fixed block of input.
But if for some reason `cat` tried to read/write by lines of unknown in advance size, it would fail to be realtime.
As I see it, it leads to a contradiction. `cat` have unbounded time of execution. It depends on a size of input. It means that `cat` cannot be realtime. But this logic leads us to a conclusion, that any OS kernel cannot be realtime, because it works for an unbounded time.
It is a non sense. Realtime is about latency: how much it takes time to react to an input. `cat` may be realtime or may be not, it depends on how we define "input". We need to define it in a way that it is bounded. I mean 4Kb chunks of bytes for example.
> Like your function might receive an arbitrarily large n-element array a[] and just return a[a[n-1]], and it would be constant time.
No. Receiving n-element array is an O(n) operation. It needs to be copied to memory. We can of course pick one function that just get a pointer to an array, but if real-time is a property of the whole system, then this system needs to copy the array from the outside world into memory. And it is an O(n) operation. So for any latency requirement exists such N so when n>N this requirement would not be met. So unbounded array as an input is incompatible with a real-time.
I think that's basically what the LLVM SafeStack pass does -- stack variables that might be written out of bounds are moved to a separate stack so they can't smash the return address.
I imagine you could you allocate it at the same time as you allocate the thread's own stack?
that's in most systems I target a run-time property, not a compile-time one