examples/configdata: exercise unregister/register lifetime

Add a regression test for apache/nuttx#20166 to the configdata
example, which runs automatically in every sim:configdata build.
After the normal configdata test loops, close the long-lived
descriptor and run a full lifetime cycle on /dev/config:

- mtdconfig_unregister() must succeed,
- the unregistered device must no longer be openable (ENOENT),
- the same MTD device must be registerable again and usable,
- a final unregister must succeed, leaving the device unregistered.

Before the driver fix this crashes deterministically: the old
mtdconfig_unregister_by_path() freed the private device structure
before closing its temporary file, so the subsequent open() faults
in mm_malloc on the corrupted heap (SIGSEGV observed on sim right
after unregister returns).  With the fix the whole example,
934706/934706 checks included, completes cleanly.

The test uses only generic configdata APIs, so it also passes
unchanged under CONFIG_MTD_CONFIG_NVS, whose open/close callbacks
are no-ops.

Assisted-by: Claude:claude-opus
Signed-off-by: Arnav Sharma <2006arnavsharma@gmail.com>
This commit is contained in:
Arnav Sharma 2026-09-16 23:12:10 +05:30 • committed by Xiang Xiao
parent 73a9c9a697
commit 642720e9b4

View file

@ -342,11 +342,11 @@ static int configdata_fillconfig(void)
}
#if CONFIG_EXAMPLES_CONFIGDATA_VERBOSE != 0
printf(" Created entry %04X, %d Len=%d\n",
entry->id, entry->instance, entry->len);
printf(" Created entry %04X, %d Len=%d\n",
entry->id, entry->instance, entry->len);
#endif
g_nentries++;
g_ntotalalloc++;
g_nentries++;
g_ntotalalloc++;
}
}
@ -477,6 +477,7 @@ static int configdata_delentries(void)
/* Are there any files to be deleted? */
int nentries = g_nentries - g_ndeleted;
if (nentries < 1)
{
return 0;
@ -609,6 +610,80 @@ static void configdata_cleardeleted(void)
g_ndeleted = 0;
}
/****************************************************************************
* Name: configdata_testunregister
*
* Description:
* Exercise the /dev/config register/unregister lifetime. Unregister
* the device, verify that it can no longer be opened, then register
* it again and verify that it is usable. This is a regression test:
* freeing the private device structure before the temporary file used
* during unregister is closed corrupts the heap and crashes the open
* below.
*
* Input Parameters:
* mtd - Pointer to the MTD device bound to the /dev/config device
*
****************************************************************************/
static void configdata_testunregister(FAR struct mtd_dev_s *mtd)
{
int fd;
int ret;
close(g_fd);
g_fd = -1;
ret = mtdconfig_unregister();
if (ret < 0)
{
printf("ERROR: /dev/config unregistration failed: %d\n", ret);
fflush(stdout);
exit(3);
}
fd = open("/dev/config", O_RDONLY);
if (fd >= 0 || errno != ENOENT)
{
printf("ERROR: /dev/config still accessible after unregister: "
"fd=%d errno=%d\n", fd, errno);
fflush(stdout);
if (fd >= 0)
{
close(fd);
}
exit(3);
}
ret = mtdconfig_register(mtd);
if (ret < 0)
{
printf("ERROR: /dev/config re-registration failed: %d\n", ret);
fflush(stdout);
exit(3);
}
fd = open("/dev/config", O_RDONLY);
if (fd < 0)
{
printf("ERROR: Failed to re-open /dev/config %d\n", errno);
fflush(stdout);
exit(3);
}
close(fd);
ret = mtdconfig_unregister();
if (ret < 0)
{
printf("ERROR: /dev/config final unregistration failed: %d\n", ret);
fflush(stdout);
exit(3);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -786,6 +861,8 @@ int main(int argc, FAR char *argv[])
configdata_delallfiles();
#endif
configdata_testunregister(mtd);
configdata_endmemusage();
fflush(stdout);
return 0;