/*
 * DF-3685 harness: parse-legal NULL subtables reach unconditional derefs at
 * smu7 backend init.  This is a control-flow reproduction (no fault is
 * executed) of the chain:
 *
 *  1. process_pptables_v1_0.c init_clock_voltage_dependency (:794-845) only
 *     fills vdd_dep_on_sclk/mclk, mm_dep_table, pcie_table when the
 *     corresponding VBIOS offset != 0; result stays 0 otherwise ->
 *     pp_tables_v1_0_initialize SUCCEEDS with NULL subtables.
 *  2. init_dpm_2_parameters (:281-297) only fills vddc/vddgfx_lookup_table
 *     when usVddcLookupTableOffset / usVddgfxLookupTableOffset != 0.
 *  3. get_cac_tdp_table only runs when usPowerTuneTableOffset != 0 ->
 *     table_info->cac_dtp_table NULL.
 *  4. smu7_hwmgr_backend_init (:2560-2566) calls smu7_complete_dependency_tables()
 *     and smu7_set_private_data_based_on_pptable_v1() and IGNORES both return
 *     values; smu7_complete_dependency_tables unconditionally dereferences
 *     table_info->mm_dep_table->count (:1878), vddc_lookup_table->entries[]
 *     (:1862/1868/1875/1881) via smu7_patch_lookup_table_with_leakage
 *     (:1823).
 *
 * The harness emulates the parser side (offset==0 => NULL, rc=0) and then
 * walks the same dereference chain, flagging each NULL deref point.
 */
#include <stdio.h>
#include <stddef.h>

struct dep_table { int dummy; };
struct mm_table { int dummy; };
struct lookup_table { int dummy; };

struct phm_ppt_v1_information {
	struct dep_table *vdd_dep_on_sclk;
	struct dep_table *vdd_dep_on_mclk;
	struct mm_table *mm_dep_table;
	struct lookup_table *vddc_lookup_table;
	struct lookup_table *vddgfx_lookup_table;
	struct { int x; } *cac_dtp_table;
};

/* parser: offset==0 -> subtable stays NULL, result stays 0 (verbatim logic) */
static int init_clock_voltage_dependency(struct phm_ppt_v1_information *ti,
		unsigned short mm_off, unsigned short sclk_off,
		unsigned short mclk_off, unsigned short pt_off)
{
	ti->vdd_dep_on_sclk = NULL;
	ti->vdd_dep_on_mclk = NULL;
	ti->mm_dep_table = NULL;

	if (mm_off != 0)
		ti->mm_dep_table = (struct mm_table *)1;	/* would parse */
	if (sclk_off != 0)
		ti->vdd_dep_on_sclk = (struct dep_table *)1;
	if (mclk_off != 0)
		ti->vdd_dep_on_mclk = (struct dep_table *)1;
	if (pt_off != 0)
		ti->cac_dtp_table = (void *)1;
	return 0;	/* success regardless */
}

static int deref_at(int *p, const char *site)
{
	if (!p) {
		printf("  NULL DEREF at %s\n", site);
		return 1;
	}
	return 0;
}

int main(void)
{
	struct phm_ppt_v1_information ti = {0};
	int faults = 0;

	/* crafted VBIOS: MM/PowerTune/lookup offsets zeroed, SCLK dep present */
	int rc = init_clock_voltage_dependency(&ti, /*mm*/0, /*sclk*/0x100,
					       /*mclk*/0x200, /*powertune*/0);
	printf("pp_tables_v1_0_initialize returned %d (parse SUCCEEDS)\n", rc);

	printf("smu7_complete_dependency_tables (smu7_hwmgr.c:2047):\n");
	/* :1878 */ faults += deref_at((int *)ti.mm_dep_table, "smu7_hwmgr.c:1878  mm_table->count");
	/* :1823 via :2036-37 */ faults += deref_at((int *)ti.vddc_lookup_table, "smu7_hwmgr.c:1823  vddc_lookup_table->count (via :2036)");
	/* :2027-28 */ faults += deref_at((int *)ti.vddgfx_lookup_table, "smu7_hwmgr.c:1823  vddgfx_lookup_table->count (via :2027)");

	printf("smu7_thermal_parameter_init (smu7_hwmgr.c:2590 -> :2183):\n");
	faults += deref_at((int *)ti.cac_dtp_table, "smu7_hwmgr.c:2183  cac_dtp_table->usDefaultTargetOperatingTemp");

	printf("smu7_get_thermal_temperature_range (sysfs temp read -> :4764):\n");
	faults += deref_at((int *)ti.cac_dtp_table, "smu7_hwmgr.c:4764  cac_dtp_table->usSoftwareShutdownTemp");

	if (faults) {
		printf("RESULT: %d NULL-deref sites reachable at load/runtime with a "
		       "parse-legal crafted VBIOS (kernel panics; return codes at "
		       ":2560-2566 are ignored)\n", faults);
		return 0;
	}
	fprintf(stderr, "RESULT: no reachable NULL deref\n");
	return 1;
}
