spa: add and use spa_overflow macros

This commit is contained in:
Wim Taymans 2026-04-24 15:54:15 +02:00
parent 84f8230a47
commit 0f8d5c6e57
16 changed files with 149 additions and 50 deletions

View file

@ -0,0 +1,40 @@
/* Simple Plugin API */
/* SPDX-FileCopyrightText: Copyright © 2026 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#ifndef SPA_UTILS_OVERFLOW_H
#define SPA_UTILS_OVERFLOW_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Check for addition overflow
*
* Computes \a a + \a b and stores the result in \a *res.
* \return true if the addition overflowed, false otherwise
*/
#define spa_overflow_add(a, b, res) __builtin_add_overflow(a, b, res)
/**
* \brief Check for subtraction overflow
*
* Computes \a a - \a b and stores the result in \a *res.
* \return true if the subtraction overflowed, false otherwise
*/
#define spa_overflow_sub(a, b, res) __builtin_sub_overflow(a, b, res)
/**
* \brief Check for multiplication overflow
*
* Computes \a a * \a b and stores the result in \a *res.
* \return true if the multiplication overflowed, false otherwise
*/
#define spa_overflow_mul(a, b, res) __builtin_mul_overflow(a, b, res)
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SPA_UTILS_OVERFLOW_H */

View file

@ -5,6 +5,7 @@
#include <errno.h> #include <errno.h>
#include <spa/param/audio/format.h> #include <spa/param/audio/format.h>
#include <spa/utils/overflow.h>
#include "resample-native-impl.h" #include "resample-native-impl.h"
#ifndef RESAMPLE_DISABLE_PRECOMP #ifndef RESAMPLE_DISABLE_PRECOMP
@ -470,8 +471,9 @@ int resample_native_init(struct resample *r)
struct native_data *d; struct native_data *d;
const struct quality *q; const struct quality *q;
double scale, cutoff; double scale, cutoff;
uint32_t i, n_taps, n_phases, filter_size, in_rate, out_rate, gcd, filter_stride; uint32_t i, n_taps, n_phases, in_rate, out_rate, gcd, filter_stride;
uint32_t history_stride, history_size, oversample; uint32_t history_stride, oversample;
size_t filter_size, history_size, alloc_size;
struct resample_config *c = &r->config; struct resample_config *c = &r->config;
#ifndef RESAMPLE_DISABLE_PRECOMP #ifndef RESAMPLE_DISABLE_PRECOMP
struct resample_config def = { 0 }; struct resample_config def = { 0 };
@ -515,17 +517,21 @@ int resample_native_init(struct resample *r)
n_phases *= oversample; n_phases *= oversample;
filter_stride = SPA_ROUND_UP_N(n_taps * sizeof(float), 64); filter_stride = SPA_ROUND_UP_N(n_taps * sizeof(float), 64);
filter_size = filter_stride * (n_phases + 1); if (spa_overflow_mul((size_t)filter_stride, (size_t)(n_phases + 1), &filter_size))
return -ENOMEM;
history_stride = SPA_ROUND_UP_N(2 * n_taps * sizeof(float), 64); history_stride = SPA_ROUND_UP_N(2 * n_taps * sizeof(float), 64);
history_size = r->channels * history_stride; if (spa_overflow_mul((size_t)r->channels, (size_t)history_stride, &history_size))
return -ENOMEM;
d = calloc(1, sizeof(struct native_data) + alloc_size = sizeof(struct native_data);
filter_size + if (spa_overflow_add(alloc_size, filter_size, &alloc_size) ||
history_size + spa_overflow_add(alloc_size, history_size, &alloc_size) ||
(r->channels * sizeof(float*)) + spa_overflow_add(alloc_size, (size_t)r->channels * sizeof(float*), &alloc_size) ||
64); spa_overflow_add(alloc_size, (size_t)64, &alloc_size))
return -ENOMEM;
d = calloc(1, alloc_size);
if (d == NULL) if (d == NULL)
return -errno; return -errno;

View file

@ -6,6 +6,7 @@
#include <errno.h> #include <errno.h>
#include <spa/param/audio/format.h> #include <spa/param/audio/format.h>
#include <spa/utils/overflow.h>
#include "peaks-ops.h" #include "peaks-ops.h"
#include "resample.h" #include "resample.h"
@ -113,7 +114,12 @@ int resample_peaks_init(struct resample *r)
r->free = impl_peaks_free; r->free = impl_peaks_free;
r->update_rate = impl_peaks_update_rate; r->update_rate = impl_peaks_update_rate;
d = calloc(1, sizeof(struct peaks_data) + sizeof(float) * r->channels); size_t alloc_size;
if (spa_overflow_mul(sizeof(float), (size_t)r->channels, &alloc_size) ||
spa_overflow_add(alloc_size, sizeof(struct peaks_data), &alloc_size))
return -ENOMEM;
d = calloc(1, alloc_size);
if (d == NULL) if (d == NULL)
return -errno; return -errno;

View file

@ -39,6 +39,7 @@
#include <bluetooth/bluetooth.h> #include <bluetooth/bluetooth.h>
#include <spa/utils/defs.h> #include <spa/utils/defs.h>
#include <spa/utils/overflow.h>
#include <spa/support/log.h> #include <spa/support/log.h>
#include "rate-control.h" #include "rate-control.h"
@ -107,9 +108,12 @@ static inline int spa_bt_decode_buffer_init(struct spa_bt_decode_buffer *this, s
this->frame_size = frame_size; this->frame_size = frame_size;
this->rate = rate; this->rate = rate;
this->log = log; this->log = log;
this->buffer_reserve = this->frame_size * reserve; if (spa_overflow_mul(this->frame_size, reserve, &this->buffer_reserve))
this->buffer_size = this->frame_size * quantum_limit * 2; return -ENOMEM;
this->buffer_size += this->buffer_reserve; if (spa_overflow_mul(this->frame_size, quantum_limit, &this->buffer_size) ||
spa_overflow_mul(this->buffer_size, 2u, &this->buffer_size) ||
spa_overflow_add(this->buffer_size, this->buffer_reserve, &this->buffer_size))
return -ENOMEM;
this->corr = 1.0; this->corr = 1.0;
this->prev_match_rate = 1.0; this->prev_match_rate = 1.0;
this->target = 0; this->target = 0;

View file

@ -12,6 +12,7 @@
#include <spa/utils/list.h> #include <spa/utils/list.h>
#include <spa/utils/string.h> #include <spa/utils/string.h>
#include <spa/utils/overflow.h>
#define PW_TELEPHONY_SERVICE "org.pipewire.Telephony" #define PW_TELEPHONY_SERVICE "org.pipewire.Telephony"
@ -1100,10 +1101,11 @@ telephony_ag_new(struct spa_bt_telephony *telephony, size_t user_data_size)
{ {
struct impl *impl = SPA_CONTAINER_OF(telephony, struct impl, this); struct impl *impl = SPA_CONTAINER_OF(telephony, struct impl, this);
struct agimpl *agimpl; struct agimpl *agimpl;
size_t alloc_size;
spa_assert(user_data_size < SIZE_MAX - sizeof(*agimpl)); spa_assert(!spa_overflow_add(sizeof(*agimpl), user_data_size, &alloc_size));
agimpl = calloc(1, sizeof(*agimpl) + user_data_size); agimpl = calloc(1, alloc_size);
if (agimpl == NULL) if (agimpl == NULL)
return NULL; return NULL;
@ -1334,10 +1336,11 @@ struct spa_bt_telephony_call *
telephony_call_new(struct spa_bt_telephony_ag *ag, size_t user_data_size) telephony_call_new(struct spa_bt_telephony_ag *ag, size_t user_data_size)
{ {
struct callimpl *callimpl; struct callimpl *callimpl;
size_t alloc_size;
spa_assert(user_data_size < SIZE_MAX - sizeof(*callimpl)); spa_assert(!spa_overflow_add(sizeof(*callimpl), user_data_size, &alloc_size));
callimpl = calloc(1, sizeof(*callimpl) + user_data_size); callimpl = calloc(1, alloc_size);
if (callimpl == NULL) if (callimpl == NULL)
return NULL; return NULL;

View file

@ -19,6 +19,7 @@
#include <spa/utils/json.h> #include <spa/utils/json.h>
#include <spa/utils/result.h> #include <spa/utils/result.h>
#include <spa/utils/cleanup.h> #include <spa/utils/cleanup.h>
#include <spa/utils/overflow.h>
#include <spa/support/cpu.h> #include <spa/support/cpu.h>
#include <spa/support/log.h> #include <spa/support/log.h>
#include <spa/support/loop.h> #include <spa/support/loop.h>
@ -1533,7 +1534,13 @@ static void *delay_instantiate(const struct spa_fga_plugin *plugin, const struct
spa_log_info(impl->log, "max-delay:%f seconds rate:%lu samples:%d latency:%f", spa_log_info(impl->log, "max-delay:%f seconds rate:%lu samples:%d latency:%f",
max_delay, impl->rate, impl->buffer_samples, impl->latency); max_delay, impl->rate, impl->buffer_samples, impl->latency);
impl->buffer = calloc(impl->buffer_samples * 2 + 64, sizeof(float)); size_t buf_count;
if (spa_overflow_mul((size_t)impl->buffer_samples, (size_t)2, &buf_count) ||
spa_overflow_add(buf_count, (size_t)64, &buf_count)) {
delay_cleanup(impl);
return NULL;
}
impl->buffer = calloc(buf_count, sizeof(float));
if (impl->buffer == NULL) { if (impl->buffer == NULL) {
delay_cleanup(impl); delay_cleanup(impl);
return NULL; return NULL;

View file

@ -28,6 +28,7 @@
#include <spa/support/plugin.h> #include <spa/support/plugin.h>
#include <spa/utils/json.h> #include <spa/utils/json.h>
#include <spa/utils/names.h> #include <spa/utils/names.h>
#include <spa/utils/overflow.h>
#include <spa/utils/result.h> #include <spa/utils/result.h>
#include <spa/utils/ringbuffer.h> #include <spa/utils/ringbuffer.h>
#include <spa/utils/string.h> #include <spa/utils/string.h>
@ -1179,9 +1180,16 @@ static int setup_streams(struct impl *impl)
spa_pod_dynamic_builder_clean(&b); spa_pod_dynamic_builder_clean(&b);
impl->rec_ringsize = (size_t)sizeof(float) * impl->max_buffer_size * impl->rec_info.rate / 1000; if (spa_overflow_mul(impl->max_buffer_size, impl->rec_info.rate / 1000, &impl->rec_ringsize) ||
impl->play_ringsize = (size_t)sizeof(float) * ((size_t)impl->max_buffer_size * impl->play_info.rate / 1000 + impl->buffer_delay); spa_overflow_mul(impl->rec_ringsize, (uint32_t)sizeof(float), &impl->rec_ringsize))
impl->out_ringsize = (size_t)sizeof(float) * impl->max_buffer_size * impl->out_info.rate / 1000; return -ENOMEM;
if (spa_overflow_mul(impl->max_buffer_size, impl->play_info.rate / 1000, &impl->play_ringsize) ||
spa_overflow_add(impl->play_ringsize, impl->buffer_delay, &impl->play_ringsize) ||
spa_overflow_mul(impl->play_ringsize, (uint32_t)sizeof(float), &impl->play_ringsize))
return -ENOMEM;
if (spa_overflow_mul(impl->max_buffer_size, impl->out_info.rate / 1000, &impl->out_ringsize) ||
spa_overflow_mul(impl->out_ringsize, (uint32_t)sizeof(float), &impl->out_ringsize))
return -ENOMEM;
for (i = 0; i < impl->rec_info.channels; i++) { for (i = 0; i < impl->rec_info.channels; i++) {
impl->rec_buffer[i] = malloc(impl->rec_ringsize); impl->rec_buffer[i] = malloc(impl->rec_ringsize);
if (impl->rec_buffer[i] == NULL) if (impl->rec_buffer[i] == NULL)

View file

@ -15,6 +15,7 @@
#include <spa/param/latency-utils.h> #include <spa/param/latency-utils.h>
#include <spa/param/tag-utils.h> #include <spa/param/tag-utils.h>
#include <spa/utils/overflow.h>
#include <spa/param/audio/raw-json.h> #include <spa/param/audio/raw-json.h>
#include <spa/pod/dynamic.h> #include <spa/pod/dynamic.h>
#include <spa/filter-graph/filter-graph.h> #include <spa/filter-graph/filter-graph.h>
@ -1764,7 +1765,13 @@ static int setup_streams(struct impl *impl)
res = -ENOMEM; res = -ENOMEM;
goto done; goto done;
} }
if ((params = calloc(n_params+1, sizeof(struct spa_pod*))) == NULL) { size_t params_alloc;
if (spa_overflow_add((size_t)n_params, (size_t)1, &params_alloc) ||
spa_overflow_mul(params_alloc, sizeof(struct spa_pod*), &params_alloc)) {
res = -ENOMEM;
goto done;
}
if ((params = calloc(1, params_alloc)) == NULL) {
res = -errno; res = -errno;
goto done; goto done;
} }

View file

@ -16,6 +16,7 @@
#include <spa/utils/string.h> #include <spa/utils/string.h>
#include <spa/utils/json.h> #include <spa/utils/json.h>
#include <spa/utils/ringbuffer.h> #include <spa/utils/ringbuffer.h>
#include <spa/utils/overflow.h>
#include <spa/param/latency-utils.h> #include <spa/param/latency-utils.h>
#include <spa/param/audio/raw-json.h> #include <spa/param/audio/raw-json.h>
#include <spa/debug/types.h> #include <spa/debug/types.h>
@ -578,14 +579,14 @@ static void recalculate_buffer(struct impl *impl)
void *data; void *data;
size_t alloc_size; size_t alloc_size;
if (delay > (UINT32_MAX / 4) - (1u<<15)) { if (spa_overflow_add(delay, 1u << 15, &impl->buffer_size) ||
spa_overflow_mul(impl->buffer_size, 4u, &impl->buffer_size)) {
pw_log_warn("delay too large, delay disabled"); pw_log_warn("delay too large, delay disabled");
impl->buffer_size = 0; impl->buffer_size = 0;
free(impl->buffer_data); free(impl->buffer_data);
impl->buffer_data = NULL; impl->buffer_data = NULL;
goto done; goto done;
} }
impl->buffer_size = (delay + (1u<<15)) * 4;
alloc_size = (size_t)impl->buffer_size * impl->channels; alloc_size = (size_t)impl->buffer_size * impl->channels;
data = realloc(impl->buffer_data, alloc_size); data = realloc(impl->buffer_data, alloc_size);
if (data == NULL) { if (data == NULL) {

View file

@ -1,5 +1,6 @@
#include <spa/utils/endian.h> #include <spa/utils/endian.h>
#include <spa/utils/overflow.h>
#include <spa/control/ump-utils.h> #include <spa/control/ump-utils.h>
#ifdef HAVE_OPUS_CUSTOM #ifdef HAVE_OPUS_CUSTOM
@ -142,11 +143,11 @@ static int netjack2_init(struct netjack2_peer *peer)
max_midi_ch = SPA_MAX(peer->params.send_midi_channels, peer->params.recv_midi_channels); max_midi_ch = SPA_MAX(peer->params.send_midi_channels, peer->params.recv_midi_channels);
if (max_midi_ch > MAX_CHANNELS || if (max_midi_ch > MAX_CHANNELS ||
peer->params.period_size > UINT32_MAX / sizeof(float) / SPA_MAX(max_midi_ch, 1u)) { spa_overflow_mul(peer->params.period_size, (uint32_t)sizeof(float), &peer->midi_size) ||
spa_overflow_mul(peer->midi_size, max_midi_ch, &peer->midi_size)) {
errno = EINVAL; errno = EINVAL;
goto error_errno; goto error_errno;
} }
peer->midi_size = peer->params.period_size * sizeof(float) * max_midi_ch;
if ((peer->midi_data = calloc(1, peer->midi_size)) == NULL && peer->midi_size > 0) if ((peer->midi_data = calloc(1, peer->midi_size)) == NULL && peer->midi_size > 0)
goto error_errno; goto error_errno;
@ -157,13 +158,11 @@ static int netjack2_init(struct netjack2_peer *peer)
} }
if (peer->params.sample_encoder == NJ2_ENCODER_INT) { if (peer->params.sample_encoder == NJ2_ENCODER_INT) {
peer->max_encoded_size = peer->params.period_size * sizeof(int16_t); if (spa_overflow_mul(peer->params.period_size, (uint32_t)sizeof(int16_t), &peer->max_encoded_size) ||
if (peer->params.period_size > UINT32_MAX / sizeof(int16_t) || spa_overflow_mul(peer->max_encoded_size, max_audio_ch, &peer->encoded_size)) {
(max_audio_ch > 0 && peer->max_encoded_size > UINT32_MAX / max_audio_ch)) {
errno = EINVAL; errno = EINVAL;
goto error_errno; goto error_errno;
} }
peer->encoded_size = peer->max_encoded_size * max_audio_ch;
if ((peer->encoded_data = calloc(1, peer->encoded_size)) == NULL) if ((peer->encoded_data = calloc(1, peer->encoded_size)) == NULL)
goto error_errno; goto error_errno;
} else if (peer->params.sample_encoder == NJ2_ENCODER_OPUS) { } else if (peer->params.sample_encoder == NJ2_ENCODER_OPUS) {
@ -175,11 +174,10 @@ static int netjack2_init(struct netjack2_peer *peer)
} }
peer->max_encoded_size = ((uint64_t)peer->params.kbps * peer->params.period_size * 1024) / peer->max_encoded_size = ((uint64_t)peer->params.kbps * peer->params.period_size * 1024) /
(peer->params.sample_rate * 8) + sizeof(uint16_t); (peer->params.sample_rate * 8) + sizeof(uint16_t);
if (max_audio_ch > 0 && peer->max_encoded_size > UINT32_MAX / max_audio_ch) { if (spa_overflow_mul(peer->max_encoded_size, max_audio_ch, &peer->encoded_size)) {
errno = EINVAL; errno = EINVAL;
goto error_errno; goto error_errno;
} }
peer->encoded_size = peer->max_encoded_size * max_audio_ch;
if ((peer->encoded_data = calloc(1, peer->encoded_size)) == NULL) if ((peer->encoded_data = calloc(1, peer->encoded_size)) == NULL)
goto error_errno; goto error_errno;
if ((peer->opus_config = opus_custom_mode_create(peer->params.sample_rate, if ((peer->opus_config = opus_custom_mode_create(peer->params.sample_rate,
@ -800,9 +798,8 @@ static int netjack2_recv_midi(struct netjack2_peer *peer, struct nj2_packet_head
peer->sync.num_packets = ntohl(header->num_packets); peer->sync.num_packets = ntohl(header->num_packets);
max_size = peer->params.mtu - sizeof(*header); max_size = peer->params.mtu - sizeof(*header);
if (sub_cycle > 0 && max_size > UINT32_MAX / sub_cycle) if (spa_overflow_mul(max_size, sub_cycle, &offset))
return -EOVERFLOW; return -EOVERFLOW;
offset = max_size * sub_cycle;
data += sizeof(*header); data += sizeof(*header);
len -= sizeof(*header); len -= sizeof(*header);

View file

@ -11,6 +11,7 @@
#include <netdb.h> #include <netdb.h>
#include <spa/utils/result.h> #include <spa/utils/result.h>
#include <spa/utils/overflow.h>
#include <spa/debug/mem.h> #include <spa/debug/mem.h>
#include "config.h" #include "config.h"
@ -644,9 +645,8 @@ static int handle_input(struct pw_websocket_connection *conn)
current)) < 0) current)) < 0)
return res; return res;
if (conn->data_wanted > SIZE_MAX - res) if (spa_overflow_add(conn->data_wanted, (size_t)res, &conn->data_wanted))
return -EOVERFLOW; return -EOVERFLOW;
conn->data_wanted += res;
} }
} }
return 0; return 0;
@ -1020,14 +1020,14 @@ int pw_websocket_connection_send(struct pw_websocket_connection *conn, uint8_t o
size_t payload_length = 0; size_t payload_length = 0;
for (i = 0; i < iov_len; i++) { for (i = 0; i < iov_len; i++) {
if (payload_length > SIZE_MAX - iov[i].iov_len) if (spa_overflow_add(payload_length, iov[i].iov_len, &payload_length))
return -EOVERFLOW; return -EOVERFLOW;
payload_length += iov[i].iov_len;
} }
if (payload_length > SIZE_MAX - sizeof(*msg) - 14) size_t alloc_size;
if (spa_overflow_add(payload_length, sizeof(*msg) + 14, &alloc_size))
return -EOVERFLOW; return -EOVERFLOW;
if ((msg = calloc(1, sizeof(*msg) + 14 + payload_length)) == NULL) if ((msg = calloc(1, alloc_size)) == NULL)
return -errno; return -errno;
d = msg->data; d = msg->data;

View file

@ -8,6 +8,7 @@
#include <errno.h> #include <errno.h>
#include <spa/utils/defs.h> #include <spa/utils/defs.h>
#include <spa/utils/overflow.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -111,7 +112,8 @@ PW_API_ARRAY int pw_array_ensure_size(struct pw_array *arr, size_t size)
size_t alloc, need; size_t alloc, need;
alloc = arr->alloc; alloc = arr->alloc;
need = arr->size + size; if (SPA_UNLIKELY(spa_overflow_add(arr->size, size, &need)))
return -ENOMEM;
if (SPA_UNLIKELY(alloc < need)) { if (SPA_UNLIKELY(alloc < need)) {
void *data; void *data;

View file

@ -6,6 +6,7 @@
#include <spa/pod/iter.h> #include <spa/pod/iter.h>
#include <spa/param/param.h> #include <spa/param/param.h>
#include <spa/buffer/alloc.h> #include <spa/buffer/alloc.h>
#include <spa/utils/overflow.h>
#include <spa/debug/types.h> #include <spa/debug/types.h>
#include "pipewire/keys.h" #include "pipewire/keys.h"
@ -71,7 +72,12 @@ static int alloc_buffers(struct pw_mempool *pool,
spa_buffer_alloc_fill_info(&info, n_metas, metas, n_datas, datas, data_aligns); spa_buffer_alloc_fill_info(&info, n_metas, metas, n_datas, datas, data_aligns);
/* allocate the skeleton, depending on SHARED flag, meta/chunk/data is included */ /* allocate the skeleton, depending on SHARED flag, meta/chunk/data is included */
buffers = calloc(1, info.max_align + n_buffers * (sizeof(struct spa_buffer *) + info.skel_size)); size_t skel_alloc;
if (spa_overflow_mul((size_t)n_buffers, sizeof(struct spa_buffer *) + info.skel_size, &skel_alloc) ||
spa_overflow_add(skel_alloc, (size_t)info.max_align, &skel_alloc))
return -ENOMEM;
buffers = calloc(1, skel_alloc);
if (buffers == NULL) if (buffers == NULL)
return -errno; return -errno;
@ -80,12 +86,18 @@ static int alloc_buffers(struct pw_mempool *pool,
if (SPA_FLAG_IS_SET(flags, PW_BUFFERS_FLAG_SHARED)) { if (SPA_FLAG_IS_SET(flags, PW_BUFFERS_FLAG_SHARED)) {
/* For shared data we use MemFd for meta/chunk/data */ /* For shared data we use MemFd for meta/chunk/data */
size_t mem_alloc;
if (spa_overflow_mul((size_t)n_buffers, (size_t)info.mem_size, &mem_alloc)) {
free(buffers);
return -ENOMEM;
}
m = pw_mempool_alloc(pool, m = pw_mempool_alloc(pool,
PW_MEMBLOCK_FLAG_READWRITE | PW_MEMBLOCK_FLAG_READWRITE |
PW_MEMBLOCK_FLAG_SEAL | PW_MEMBLOCK_FLAG_SEAL |
PW_MEMBLOCK_FLAG_MAP, PW_MEMBLOCK_FLAG_MAP,
SPA_DATA_MemFd, SPA_DATA_MemFd,
n_buffers * info.mem_size); mem_alloc);
if (m == NULL) { if (m == NULL) {
free(buffers); free(buffers);
return -errno; return -errno;

View file

@ -5,6 +5,7 @@
#ifndef PIPEWIRE_MEM_H #ifndef PIPEWIRE_MEM_H
#define PIPEWIRE_MEM_H #define PIPEWIRE_MEM_H
#include <spa/utils/overflow.h>
#include <pipewire/properties.h> #include <pipewire/properties.h>
struct spa_hook; struct spa_hook;
@ -184,14 +185,15 @@ PW_API_MEM int pw_map_range_init(struct pw_map_range *range,
uint32_t offset, uint32_t size, uint32_t offset, uint32_t size,
uint32_t page_size) uint32_t page_size)
{ {
uint32_t sum, tmp;
range->offset = SPA_ROUND_DOWN_N(offset, page_size); range->offset = SPA_ROUND_DOWN_N(offset, page_size);
range->start = offset - range->offset; range->start = offset - range->offset;
if (size > UINT32_MAX - range->start) if (spa_overflow_add(range->start, size, &sum))
return -EOVERFLOW; return -EOVERFLOW;
/* Check that rounding up to page_size won't overflow */ /* Check that rounding up to page_size won't overflow */
if (range->start + size > UINT32_MAX - (page_size - 1)) if (spa_overflow_add(sum, page_size - 1, &tmp))
return -EOVERFLOW; return -EOVERFLOW;
range->size = SPA_ROUND_UP_N(range->start + size, page_size); range->size = SPA_ROUND_UP_N(sum, page_size);
return 0; return 0;
} }

View file

@ -14,6 +14,7 @@
#include <time.h> #include <time.h>
#include <spa/utils/json.h> #include <spa/utils/json.h>
#include <spa/utils/overflow.h>
#include <spa/debug/log.h> #include <spa/debug/log.h>
#include <pipewire/array.h> #include <pipewire/array.h>
@ -368,10 +369,11 @@ void* pw_reallocarray(void *ptr, size_t nmemb, size_t size)
#ifdef HAVE_REALLOCARRAY #ifdef HAVE_REALLOCARRAY
return reallocarray(ptr, nmemb, size); return reallocarray(ptr, nmemb, size);
#else #else
if (size > 0 && nmemb > SIZE_MAX / size) { size_t total;
if (spa_overflow_mul(nmemb, size, &total)) {
errno = ENOMEM; errno = ENOMEM;
return NULL; return NULL;
} }
return realloc(ptr, nmemb * size); return realloc(ptr, total);
#endif #endif
} }

View file

@ -11,6 +11,7 @@
#include <math.h> #include <math.h>
#include <spa/utils/string.h> #include <spa/utils/string.h>
#include <spa/utils/overflow.h>
#include "dsffile.h" #include "dsffile.h"
@ -96,10 +97,11 @@ static int read_fmt(struct dsf_file *f)
if (size > s) if (size > s)
f_skip(f, size - s); f_skip(f, size - s);
size_t buf_size;
if (f->info.blocksize == 0 || f->info.channels == 0 || if (f->info.blocksize == 0 || f->info.channels == 0 ||
f->info.channels > SIZE_MAX / f->info.blocksize) spa_overflow_mul((size_t)f->info.channels, (size_t)f->info.blocksize, &buf_size))
return -EINVAL; return -EINVAL;
f->buffer = calloc(f->info.channels, f->info.blocksize); f->buffer = calloc(1, buf_size);
if (f->buffer == NULL) if (f->buffer == NULL)
return -errno; return -errno;