Fix ASCII protocol bug when writing to uint8_t

When writing to uint8_t properties or equivalently
sized enum properties, the ASCII protocol handler would
write beyond the variable itself and overwrite adjacent
memory.

This manifested for instance in the following:

    r axis0.controller.config.input_mode 1
    w axis0.controller.config.control_mode 3
    r axis0.controller.config.input_mode 0

This boils down to what appears to be misbehavior of
`sscanf`.

This fix adds an intermediate union to provide a safe
memory area for the `sscanf` call.
This commit is contained in:
Samuel Sadok
2020-07-01 12:42:01 +02:00
parent 006ac8228f
commit 60482c9e8b
+11 -1
View File
@@ -591,7 +591,17 @@ static bool to_string(const T& value, char * buffer, size_t length, ...) {
template<typename T, typename = typename format_traits_t<T>::type>
static bool from_string(const char * buffer, size_t length, T* property, int) {
return sscanf(buffer, format_traits_t<T>::fmt, property) == 1;
// Note for T == uint8_t: Even though we supposedly use the correct format
// string sscanf treats our pointer as pointer-to-int instead of
// pointer-to-uint8_t. To avoid an unexpected memory access we first read
// into a union.
union { T t; int i; } val;
if (sscanf(buffer, format_traits_t<T>::fmt, &val.t) == 1) {
*property = val.t;
return true;
} else {
return false;
}
}
// Special case for float because printf promotes float to double, and we get warnings
template<typename T = float>