(as noted at the end of the last log...)
Since the attributes can be moved to the Flex types, the terminal byte does not need to be kept. But I keep it for a different reason: now it's a canary.
The fixed/constant ones can be trusted (usually) and the compiler usually adds a NULL terminator byte that can't be easily changed. So the default canary is 0.
However a good canary can be changed arbitrarily: updated arbitrarily by a counter, PID or by a PRNG. Flex types must be postfixed by something else than 0. There is a global variable that contains the current canary that is set and tested at each update of a Flex type:
uint8_t aStrA_canary_value = 42;
It's "good for security" and of course, for now, for safety as it could help spot bugs faster and prevent the propagation of altered data. Can we say now that aStrA is more secure than the rest ? :-)
Transmitting strings from one software module to another creates the problem that the canary's value is different between the modules (unless agreed on otherwise). The "portable" way is to clear the canary before transmission, then updating it while/after the validation upon reception, when the attributes are (re)computed, because, you know, you never know.
I think it's a better use of the trailing byte than what I intended a few days before. The attributes are easier to address and the canary is where it is meant to be, less used than the attributes.
Consequence: the library must provide at least the following functions
int aStrA_set_canary(p, c);
int aStrA_check_canary(p);
int aStrA_clear_canary(p);
such that a string can be moved to/from POSIX domains.
...
aligned_strings.20240908.h shows how far it's going. I managed to add the canary to strings constants though (damned CPP macros and their weird limitations!) at the price of a compile-time value and an extra character (the NULL just takes useless room).
But you can compile with a different canary with
-DCANARY_BYTE_OCTAL=123
That's a decent compromise.
....
Finaly I reduced the "helper" functions to only two, more general, ones:
int aStrA_set_canary(aStr_t p, uint8_t c) {
ASTRA_CHECK_STRING(p, (MASK_LSB_UP|MASK_LSB_LIST) )
// update the attribute
*(uint8_t *)(p+len_p)=c;
return 0;
}
int aStrA_get_canary(aStr_t p) {
ASTRA_CHECK_STRING(p, (MASK_LSB_UP|MASK_LSB_LIST) )
// read the attribute
return *(uint8_t *)(p+len_p);
};
That should work.
They share the same code defined in the macro ASTRA_CHECK_STRING which can be reused in other places and could be optimised at one location for all users. Yay.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.