/* DF-1354 vega12_apply_clocks_adjust_rules mclk_latency count underflow */
#include <stdio.h>
#include <stdint.h>
#include <string.h>

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

static uint32_t oob_reads_vuln;
static void apply_vuln(struct dpm_table *d, struct mclk_lat *m){
    /* count is uint32, defaults 0 ; count - 1 wraps to 0xFFFFFFFF */
    for (uint32_t i = 0; i < m->count - 1; i++){
        if (i >= MAX_REGULAR_DPM_NUMBER) oob_reads_vuln++;
        /* reads m->entries[i] and d->levels[i] OOB */
    }
}
static int apply_fixed(struct dpm_table *d, struct mclk_lat *m){
    if (d->count == 0) return -1;
    for (uint32_t i = 0; i < m->count && i < d->count && i < MAX_REGULAR_DPM_NUMBER - 1; i++){
        /* safe */
    }
    return 0;
}

int main(void){
    struct dpm_table d; struct mclk_lat m;
    memset(&d, 0, sizeof(d)); memset(&m, 0, sizeof(m));
    /* count == 0 from kzalloc -> wraps */
    printf("== BEFORE-FIX (vulnerable) ==\n");
    /* simulate the wrap by capping iterations to avoid real hang */
    m.count = 0;
    /* emulate: count-1 = 0xFFFFFFFF; we stop at 100 to demo OOB */
    for (uint32_t i=0; i<100; i++) if (i >= MAX_REGULAR_DPM_NUMBER) oob_reads_vuln++;
    printf("BUG: count=%u, count-1 wraps to %u, loop reads entries[i]/dpm_levels[i] OOB (OOB reads in first 100 iters: %u)\n",
           m.count, m.count - 1, oob_reads_vuln);
    printf("== AFTER-FIX ==\n");
    int rc = apply_fixed(&d, &m);
    printf("FIX: count==0 -> return -EINVAL, no OOB reads (rc=%d)\n", rc);
    return 0;
}
