diff --git a/meson.build b/meson.build index e7a1d8590..a65f1ee7d 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project('pipewire', ['c' ], license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ], meson_version : '>= 0.59.0', default_options : [ 'warning_level=3', - 'c_std=gnu99', + 'c_std=gnu11', 'cpp_std=c++17', 'b_pie=true', #'b_sanitize=address,undefined', diff --git a/spa/include/spa/buffer/alloc.h b/spa/include/spa/buffer/alloc.h index 641707383..ec8554153 100644 --- a/spa/include/spa/buffer/alloc.h +++ b/spa/include/spa/buffer/alloc.h @@ -161,8 +161,9 @@ static inline int spa_buffer_alloc_fill_info(struct spa_buffer_alloc_info *info, *target += info->chunk_size; for (i = 0, size = 0; i < n_datas; i++) { + int64_t align = data_aligns[i]; info->max_align = SPA_MAX(info->max_align, data_aligns[i]); - size = SPA_ROUND_UP_N(size, data_aligns[i]); + size = SPA_ROUND_UP_N(size, align); size += datas[i].maxsize; } info->data_size = size; diff --git a/spa/include/spa/pod/parser.h b/spa/include/spa/pod/parser.h index f8942aa7b..59987e232 100644 --- a/spa/include/spa/pod/parser.h +++ b/spa/include/spa/pod/parser.h @@ -82,12 +82,20 @@ spa_pod_parser_reset(struct spa_pod_parser *parser, struct spa_pod_parser_state static inline struct spa_pod * spa_pod_parser_deref(struct spa_pod_parser *parser, uint32_t offset, uint32_t size) { - if (offset + 8 <= size) { - struct spa_pod *pod = SPA_PTROFF(parser->data, offset, struct spa_pod); - if (offset + SPA_POD_SIZE(pod) <= size) - return pod; + /* Cast to uint64_t to avoid wraparound. Add 8 for the pod itself. */ + const uint64_t long_offset = (uint64_t)offset + 8; + if (long_offset <= size && (offset & 7) == 0) { + /* Use void* because creating a misaligned pointer is undefined. */ + void *pod = SPA_PTROFF(parser->data, offset, void); + /* + * Check that the pointer is aligned and that the size (rounded + * to the next multiple of 8) is in bounds. + */ + if (SPA_IS_ALIGNED(pod, 8) && + long_offset + SPA_ROUND_UP_N((uint64_t)SPA_POD_BODY_SIZE(pod), 8) <= size) + return (struct spa_pod *)pod; } - return NULL; + return NULL; } static inline struct spa_pod *spa_pod_parser_frame(struct spa_pod_parser *parser, struct spa_pod_frame *frame) diff --git a/spa/include/spa/pod/pod.h b/spa/include/spa/pod/pod.h index 0b2f3b7ee..1864b19b9 100644 --- a/spa/include/spa/pod/pod.h +++ b/spa/include/spa/pod/pod.h @@ -39,7 +39,7 @@ extern "C" { #define SPA_POD_BODY_SIZE(pod) (((struct spa_pod*)(pod))->size) #define SPA_POD_TYPE(pod) (((struct spa_pod*)(pod))->type) -#define SPA_POD_SIZE(pod) (sizeof(struct spa_pod) + SPA_POD_BODY_SIZE(pod)) +#define SPA_POD_SIZE(pod) ((uint64_t)sizeof(struct spa_pod) + SPA_POD_BODY_SIZE(pod)) #define SPA_POD_CONTENTS_SIZE(type,pod) (SPA_POD_SIZE(pod)-sizeof(type)) #define SPA_POD_CONTENTS(type,pod) SPA_PTROFF((pod),sizeof(type),void) diff --git a/spa/include/spa/support/system.h b/spa/include/spa/support/system.h index 8076ceb4b..79127d906 100644 --- a/spa/include/spa/support/system.h +++ b/spa/include/spa/support/system.h @@ -119,7 +119,7 @@ struct spa_system_methods { #define spa_system_method_r(o,method,version,...) \ ({ \ - int _res = -ENOTSUP; \ + volatile int _res = -ENOTSUP; \ struct spa_system *_o = o; \ spa_interface_call_res(&_o->iface, \ struct spa_system_methods, _res, \ diff --git a/spa/include/spa/utils/defs.h b/spa/include/spa/utils/defs.h index d1ed83ec9..686ee86b4 100644 --- a/spa/include/spa/utils/defs.h +++ b/spa/include/spa/utils/defs.h @@ -27,8 +27,18 @@ #ifdef __cplusplus extern "C" { +# if __cplusplus >= 201103L +# define SPA_STATIC_ASSERT static_assert +# endif #else -#include +# include +# if __STDC_VERSION__ >= 201112L +# define SPA_STATIC_ASSERT _Static_assert +# endif +#endif +#ifndef SPA_STATIC_ASSERT +#define SPA_STATIC_ASSERT(a, b) \ + ((void)sizeof(struct { int spa_static_assertion_failed : 2 * !!(a) - 1; })) #endif #include #include @@ -74,8 +84,16 @@ extern "C" { #define SPA_FLAG_MASK(field,mask,flag) (((field) & (mask)) == (flag)) #define SPA_FLAG_IS_SET(field,flag) SPA_FLAG_MASK(field,flag,flag) #define SPA_FLAG_SET(field,flag) ((field) |= (flag)) -#define SPA_FLAG_CLEAR(field,flag) ((field) &= ~(flag)) -#define SPA_FLAG_UPDATE(field,flag,val) ((val) ? SPA_FLAG_SET(field,flag) : SPA_FLAG_CLEAR(field,flag)) +#define SPA_FLAG_CLEAR(field, flag) \ +({ \ + SPA_STATIC_ASSERT(__builtin_constant_p(flag) ? \ + (__typeof__(flag))(__typeof__(field))(__typeof__(flag))(flag) == (flag) : \ + sizeof(field) >= sizeof(flag), \ + "truncation problem when masking " #field \ + " with ~" #flag); \ + ((field) &= ~(__typeof__(field))(flag)); \ +}) +#define SPA_FLAG_UPDATE(field,flag,val) ((val) ? SPA_FLAG_SET((field),(flag)) : SPA_FLAG_CLEAR((field),(flag))) enum spa_direction { SPA_DIRECTION_INPUT = 0, @@ -239,7 +257,17 @@ struct spa_fraction { #define SPA_ROUND_DOWN(num,value) ((num) - ((num) % (value))) #define SPA_ROUND_UP(num,value) ((((num) + (value) - 1) / (value)) * (value)) -#define SPA_ROUND_DOWN_N(num,align) ((num) & ~((align) - 1)) +#define SPA_MASK_NEGATED(num1, num2) \ +({ \ + SPA_STATIC_ASSERT(__builtin_constant_p(num2) ? \ + (__typeof__(num2))(__typeof__(num1))(__typeof__(num2))(num2) == (num2) : \ + sizeof(num1) >= sizeof(num2), \ + "truncation problem when masking " #num1 \ + " with ~" #num2); \ + ((num1) & ~(__typeof__(num1))(num2)); \ +}) + +#define SPA_ROUND_DOWN_N(num,align) SPA_MASK_NEGATED((num), (align) - 1) #define SPA_ROUND_UP_N(num,align) SPA_ROUND_DOWN_N((num) + ((align) - 1),align) #define SPA_PTR_ALIGNMENT(p,align) ((intptr_t)(p) & ((align)-1)) diff --git a/src/modules/module-protocol-native/defs.h b/src/modules/module-protocol-native/defs.h index 60adad027..dc3c62594 100644 --- a/src/modules/module-protocol-native/defs.h +++ b/src/modules/module-protocol-native/defs.h @@ -31,13 +31,19 @@ int pw_protocol_native_connect_portal_screencast(struct pw_protocol_client *clie void (*done_callback) (void *data, int res), void *data); -static inline void *get_first_pod_from_data(void *data, size_t maxsize, off_t offset) +static inline void *get_first_pod_from_data(void *data, uint32_t maxsize, uint64_t offset) { void *pod; - if (offset + sizeof(struct spa_pod) > maxsize) + if (maxsize <= offset) return NULL; + + /* spa_pod_parser_advance() rounds up, so round down here to compensate */ + maxsize = SPA_ROUND_DOWN_N(maxsize - offset, 8); + if (maxsize < sizeof(struct spa_pod)) + return NULL; + pod = SPA_PTROFF(data, offset, void); - if (offset + SPA_POD_SIZE(pod) > maxsize) + if (SPA_POD_BODY_SIZE(pod) > maxsize - sizeof(struct spa_pod)) return NULL; return pod; }