java-topology/defects/allegro5/patch/allegro5-0001.patch

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;
+ }
}
}