mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
pod: Add validation to spa_pod_get_values()
Return no values if the size is too small for its type. Return at most one value if the size is misaligned for its type. Document all of this.
This commit is contained in:
parent
0b08468035
commit
42098fd8c1
3 changed files with 78 additions and 17 deletions
|
|
@ -435,10 +435,14 @@ spa_pod_parser_get_object(&p,
|
|||
\endcode
|
||||
|
||||
`spa_pod_get_values()` is a useful function. It returns a
|
||||
`struct spa_pod*` with and array of values. For normal POD's
|
||||
and choice none values, it simply returns the POD and one value.
|
||||
For other choice values it returns the choice type and an array
|
||||
of values:
|
||||
`struct spa_pod*` with and array of values. For invalid PODs
|
||||
it returns the POD and no values. For normal PODs it returns
|
||||
the POD and one value. For choice values it returns the choice
|
||||
type and an array of values. If the choice doesn't fit even a
|
||||
single value, the array will have no values. If the choice is
|
||||
of the `SPA_CHOICE_None` or the length of each element is
|
||||
misaligned, the array will have one value. Otherwise,
|
||||
the array will have the same length as the choice.
|
||||
|
||||
\code{.c}
|
||||
struct spa_pod *value;
|
||||
|
|
|
|||
|
|
@ -78,6 +78,44 @@ SPA_API_POD_BODY uint32_t spa_pod_type_size(uint32_t type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
SPA_API_POD_BODY uint32_t spa_pod_type_align(uint32_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case SPA_TYPE_None:
|
||||
case SPA_TYPE_Bytes:
|
||||
case SPA_TYPE_String:
|
||||
case SPA_TYPE_Bitmap:
|
||||
return 1;
|
||||
case SPA_TYPE_Bool:
|
||||
case SPA_TYPE_Int:
|
||||
return SPA_ALIGNOF(int32_t);
|
||||
case SPA_TYPE_Id:
|
||||
return SPA_ALIGNOF(uint32_t);
|
||||
case SPA_TYPE_Long:
|
||||
return SPA_ALIGNOF(int64_t);
|
||||
case SPA_TYPE_Float:
|
||||
return SPA_ALIGNOF(float);
|
||||
case SPA_TYPE_Double:
|
||||
return SPA_ALIGNOF(double);
|
||||
case SPA_TYPE_Rectangle:
|
||||
return SPA_ALIGNOF(struct spa_rectangle);
|
||||
case SPA_TYPE_Fraction:
|
||||
return SPA_ALIGNOF(struct spa_fraction);
|
||||
case SPA_TYPE_Pointer:
|
||||
return SPA_ALIGNOF(struct spa_pod_pointer_body);
|
||||
case SPA_TYPE_Fd:
|
||||
return SPA_ALIGNOF(int64_t);
|
||||
case SPA_TYPE_Sequence:
|
||||
case SPA_TYPE_Choice:
|
||||
case SPA_TYPE_Struct:
|
||||
case SPA_TYPE_Pod:
|
||||
case SPA_TYPE_Object:
|
||||
case SPA_TYPE_Array:
|
||||
default:
|
||||
return SPA_POD_ALIGN;
|
||||
}
|
||||
}
|
||||
|
||||
SPA_API_POD_BODY int spa_pod_body_from_data(void *data, size_t maxsize, off_t offset, size_t size,
|
||||
struct spa_pod *pod, const void **body)
|
||||
{
|
||||
|
|
@ -326,13 +364,22 @@ SPA_API_POD_BODY int spa_pod_body_get_array(const struct spa_pod *pod, const voi
|
|||
*arr_body = SPA_PTROFF(body, sizeof(struct spa_pod_array_body), void);
|
||||
return 0;
|
||||
}
|
||||
SPA_API_POD_BODY const void *spa_pod_array_body_get_values(const struct spa_pod_array *arr,
|
||||
SPA_API_POD_BODY const void *spa_pod_array_body_get_values(const struct spa_pod_array *pod,
|
||||
const void *body, uint32_t *n_values, uint32_t *val_size, uint32_t *val_type)
|
||||
{
|
||||
uint32_t child_size = arr->body.child.size;
|
||||
*n_values = child_size ? (arr->pod.size - sizeof(arr->body)) / child_size : 0;
|
||||
*val_size = child_size;
|
||||
*val_type = arr->body.child.type;
|
||||
uint32_t child_size = *val_size = pod->body.child.size;
|
||||
uint32_t child_type = *val_type = pod->body.child.type;
|
||||
uint32_t child_type_size = spa_pod_type_size(child_size);
|
||||
uint32_t max_body_size = pod->pod.size - sizeof(pod->body);
|
||||
|
||||
if (SPA_UNLIKELY(child_size < child_type_size) ||
|
||||
child_size == 0) {
|
||||
*n_values = 0;
|
||||
} else if (SPA_UNLIKELY(child_size != child_type_size) &&
|
||||
SPA_UNLIKELY((child_size & (spa_pod_type_align(child_type) - 1)) != 0))
|
||||
*n_values = max_body_size >= child_size ? 1u : 0u;
|
||||
else
|
||||
*n_values = max_body_size / child_size;
|
||||
return body;
|
||||
}
|
||||
|
||||
|
|
@ -366,13 +413,23 @@ SPA_API_POD_BODY const void *spa_pod_choice_body_get_values(const struct spa_pod
|
|||
const void *body, uint32_t *n_values, uint32_t *choice,
|
||||
uint32_t *val_size, uint32_t *val_type)
|
||||
{
|
||||
uint32_t child_size = pod->body.child.size;
|
||||
*val_size = child_size;
|
||||
*val_type = pod->body.child.type;
|
||||
*n_values = child_size ? (pod->pod.size - sizeof(pod->body)) / child_size : 0;
|
||||
*choice = pod->body.type;
|
||||
if (*choice == SPA_CHOICE_None)
|
||||
*n_values = SPA_MIN(1u, *n_values);
|
||||
/* precondition check */
|
||||
spa_assert_se(pod->pod.size >= sizeof(pod->body));
|
||||
uint32_t child_size = *val_size = pod->body.child.size;
|
||||
uint32_t child_type = *val_type = pod->body.child.type;
|
||||
uint32_t child_type_size = spa_pod_type_size(child_size);
|
||||
uint32_t choice_type = *choice = pod->body.type;
|
||||
uint32_t max_body_size = pod->pod.size - sizeof(pod->body);
|
||||
|
||||
if (SPA_UNLIKELY(child_size < child_type_size) ||
|
||||
child_size == 0) {
|
||||
*n_values = 0;
|
||||
} else if (choice_type == SPA_CHOICE_None ||
|
||||
(SPA_UNLIKELY(child_size != child_type_size) &&
|
||||
SPA_UNLIKELY((child_size & (spa_pod_type_align(child_type) - 1)) != 0)))
|
||||
*n_values = max_body_size >= child_size ? 1 : 0;
|
||||
else
|
||||
*n_values = max_body_size / child_size;
|
||||
return body;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ SPA_API_POD_ITER struct spa_pod *spa_pod_get_values(const struct spa_pod *pod,
|
|||
spa_pod_choice_body_get_values(p, SPA_POD_BODY_CONST(p), n_vals, choice, &size, &type);
|
||||
return (struct spa_pod*)&p->body.child;
|
||||
} else {
|
||||
*n_vals = 1;
|
||||
*n_vals = (pod->size >= spa_pod_type_size(pod->type) ? 1u : 0u);
|
||||
*choice = SPA_CHOICE_None;
|
||||
return (struct spa_pod*)pod;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue