/* DF-1353 vega12_force_clock_level OOB dpm_levels[16+] */
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define MAX_REGULAR_DPM_NUMBER 16
struct dpm_table { uint32_t count; uint32_t levels[MAX_REGULAR_DPM_NUMBER]; };

static uint32_t read_oob_count_vuln;
static int force_lvl_vuln(struct dpm_table *t, uint32_t mask, uint32_t *out){
    /* soft_min_level = ffs(mask)-1 ; soft_max_level = fls(mask)-1 */
    uint32_t soft_min = mask ? (__builtin_ffs(mask)-1) : 0;
    uint32_t soft_max = mask ? (31 - __builtin_clz(mask)) : 0;
    if (soft_max >= MAX_REGULAR_DPM_NUMBER) read_oob_count_vuln++;
    if (soft_min >= MAX_REGULAR_DPM_NUMBER) read_oob_count_vuln++;
    /* dpm_levels[soft_min/max].value */
    *out = t->levels[soft_min] + t->levels[soft_max];    /* OOB read if mask bit >= 16 */
    return 0;
}
static int force_lvl_fixed(struct dpm_table *t, uint32_t mask, uint32_t *out){
    uint32_t soft_min = mask ? (__builtin_ffs(mask)-1) : 0;
    uint32_t soft_max = mask ? (31 - __builtin_clz(mask)) : 0;
    if (soft_min >= t->count || soft_max >= t->count) return -1;
    *out = t->levels[soft_min] + t->levels[soft_max];
    return 0;
}

int main(void){
    struct dpm_table t; memset(&t, 0, sizeof(t)); t.count = 5;
    printf("== BEFORE-FIX (vulnerable) ==\n");
    uint32_t out;
    read_oob_count_vuln = 0;
    force_lvl_vuln(&t, 0x80000000, &out);   /* bit 31 set -> soft_max=31, OOB read dpm_levels[31] */
    printf("BUG: mask=0x80000000 -> soft_max=31, reads dpm_levels[31] past 16-element array (OOB reads: %u)\n",
           read_oob_count_vuln);
    printf("== AFTER-FIX ==\n");
    int rc = force_lvl_fixed(&t, 0x80000000, &out);
    printf("FIX: soft_max=31 >= count=%u -> return -EINVAL (rc=%d)\n", t.count, rc);
    return 0;
}
