106 lines
3.5 KiB
Diff
106 lines
3.5 KiB
Diff
# UNDF: UNDF-2026-000000002
|
|
--- a/addons/audio/kcm_sample.c
|
|
+++ b/addons/audio/kcm_sample.c
|
|
@@ -38,6 +38,8 @@ typedef struct {
|
|
bool locked;
|
|
} AUTO_SAMPLE;
|
|
|
|
+/* CWE-407 fix: stack of free slot indices for O(1) amortized slot acquisition. */
|
|
+static _AL_VECTOR free_slots = _AL_VECTOR_INITIALIZER(int);
|
|
+
|
|
static _AL_VECTOR auto_samples = _AL_VECTOR_INITIALIZER(AUTO_SAMPLE);
|
|
static ALLEGRO_MIXER *default_mixer = NULL;
|
|
|
|
@@ -205,6 +207,7 @@ bool al_reserve_samples(int reserve_samples)
|
|
int current_samples_count = (int) _al_vector_size(&auto_samples);
|
|
|
|
ASSERT(reserve_samples >= 0);
|
|
+ _al_vector_free(&free_slots);
|
|
|
|
/* If no default mixer has been set by the user, then create a voice
|
|
* and a mixer, and set them to be the default one for use with
|
|
@@ -222,6 +225,8 @@ bool al_reserve_samples(int reserve_samples)
|
|
if (!slot->instance) {
|
|
ALLEGRO_ERROR("al_create_sample failed\n");
|
|
goto Error;
|
|
}
|
|
if (!al_attach_sample_instance_to_mixer(slot->instance, default_mixer)) {
|
|
ALLEGRO_ERROR("al_attach_mixer_to_sample failed\n");
|
|
goto Error;
|
|
}
|
|
+ /* Push index of newly created slot onto free stack. */
|
|
+ {
|
|
+ int idx = current_samples_count + i;
|
|
+ int *p = _al_vector_alloc_back(&free_slots);
|
|
+ *p = idx;
|
|
+ }
|
|
}
|
|
}
|
|
else if (current_samples_count > reserve_samples) {
|
|
@@ -340,28 +345,35 @@ bool al_play_sample(ALLEGRO_SAMPLE *spl, float gain, float pan, float speed,
|
|
ALLEGRO_PLAYMODE loop, ALLEGRO_SAMPLE_ID *ret_id)
|
|
{
|
|
static int next_id = 0;
|
|
- unsigned int i;
|
|
|
|
ASSERT(spl);
|
|
|
|
if (ret_id != NULL) {
|
|
ret_id->_id = -1;
|
|
ret_id->_index = 0;
|
|
}
|
|
|
|
- for (i = 0; i < _al_vector_size(&auto_samples); i++) {
|
|
- AUTO_SAMPLE *slot = _al_vector_ref(&auto_samples, i);
|
|
-
|
|
- if (!al_get_sample_instance_playing(slot->instance) && !slot->locked) {
|
|
- if (!do_play_sample(slot->instance, spl, gain, pan, speed, loop))
|
|
- break;
|
|
-
|
|
- if (ret_id != NULL) {
|
|
- ret_id->_index = (int) i;
|
|
- ret_id->_id = slot->id = ++next_id;
|
|
- }
|
|
-
|
|
- return true;
|
|
+ /* CWE-407 fix: O(1) amortized free-slot acquisition via stack.
|
|
+ * Reclaim slots whose instances have finished playing since last pop. */
|
|
+ while (_al_vector_is_nonempty(&free_slots)) {
|
|
+ unsigned int sz = _al_vector_size(&free_slots);
|
|
+ int *idxp = _al_vector_ref(&free_slots, sz - 1);
|
|
+ int idx = *idxp;
|
|
+ AUTO_SAMPLE *slot = _al_vector_ref(&auto_samples, (unsigned int)idx);
|
|
+
|
|
+ /* Slot may have been locked or already playing (race); re-check. */
|
|
+ if (al_get_sample_instance_playing(slot->instance) || slot->locked) {
|
|
+ _al_vector_delete_at(&free_slots, sz - 1);
|
|
+ continue;
|
|
}
|
|
- }
|
|
|
|
- return false;
|
|
+ _al_vector_delete_at(&free_slots, sz - 1);
|
|
+
|
|
+ if (!do_play_sample(slot->instance, spl, gain, pan, speed, loop))
|
|
+ return false;
|
|
+
|
|
+ if (ret_id != NULL) {
|
|
+ ret_id->_index = idx;
|
|
+ ret_id->_id = slot->id = ++next_id;
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ return false; /* No free slots available. */
|
|
}
|
|
|
|
@@ -462,6 +474,12 @@ void al_stop_sample(ALLEGRO_SAMPLE_ID *spl_id)
|
|
slot = _al_vector_ref(&auto_samples, spl_id->_index);
|
|
if (slot->id == spl_id->_id) {
|
|
al_stop_sample_instance(slot->instance);
|
|
+ /* Return slot to free stack now that it's stopped. */
|
|
+ if (!slot->locked) {
|
|
+ int *p = _al_vector_alloc_back(&free_slots);
|
|
+ *p = spl_id->_index;
|
|
+ }
|
|
}
|
|
}
|