Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
test_conf_value_lifetime.c File Reference
#include "common/conf.h"
#include "darktable.h"
#include <glib.h>
#include <glib/gstdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <setjmp.h>
#include <stdint.h>
#include <cmocka.h>
+ Include dependency graph for test_conf_value_lifetime.c:

Go to the source code of this file.

Macros

#define TEST_KEY   "plugins/test/conf_value_lifetime"
 

Functions

static int _setup (void **state)
 
static int _teardown (void **state)
 
static void _borrowed_value_survives_being_replaced (void **state)
 
static void _every_displaced_value_stays_readable (void **state)
 
static void _rewriting_the_same_value_retires_nothing (void **state)
 
static void _typed_setters_retire_too (void **state)
 
int main (void)
 

Variables

static char * _rcfile = NULL
 

Macro Definition Documentation

◆ TEST_KEY

#define TEST_KEY   "plugins/test/conf_value_lifetime"

Lifetime of the string dt_conf_get_string_const() hands out.

That function returns a pointer INTO the conf hash table, and dt_conf_get_var() releases the lock before returning it. Replacing the value used to free it on the spot – the table's value_destroy_func is a free – so any reader still holding the pointer was reading freed memory. With 98 call sites and no way to tell from a signature which of them could race a writer, the fix was made in the writer: displaced values are retired and released only at cleanup.

These tests pin that. The first one is the bug: read, overwrite, read again through the ORIGINAL pointer.

Checked against the defect rather than only against the fix. Reverting the writer to its free-on-replace form and running under MALLOC_PERTURB_=170 – which fills freed memory, so a use-after-free stops being silent without needing a full ASAN build – fails three of the four, reporting the fill pattern where the value should be:

[  ERROR   ] --- "\357\277\275\357\277\275" != "11"

The fourth, _rewriting_the_same_value_retires_nothing(), passes EITHER WAY and is not a regression detector: it asserts pointer identity, and the old code frees then immediately reallocates the same size, so the allocator hands back the same address. It is here to pin the dedup property – that an unchanged write retires nothing – not the lifetime. A key with no confgen declaration, so nothing clamps or sanitises what we store.

Definition at line 59 of file test_conf_value_lifetime.c.

Function Documentation

◆ _borrowed_value_survives_being_replaced()

static void _borrowed_value_survives_being_replaced ( void **  state)
static

The bug, pinned: a borrowed pointer survives the write that displaces it.

Definition at line 88 of file test_conf_value_lifetime.c.

References dt_conf_get_string_const(), dt_conf_set_string(), state, TEST_KEY, and void().

Referenced by main().

◆ _every_displaced_value_stays_readable()

static void _every_displaced_value_stays_readable ( void **  state)
static

Many successive writes, all of them retired rather than freed.

Definition at line 108 of file test_conf_value_lifetime.c.

References dt_conf_get_string_const(), dt_conf_set_string(), i, state, TEST_KEY, value, and void().

Referenced by main().

◆ _rewriting_the_same_value_retires_nothing()

static void _rewriting_the_same_value_retires_nothing ( void **  state)
static

Rewriting a key with the value it already holds must change nothing at all.

This is what keeps the retired list proportional to real edits: GUI state is written back constantly with values that did not change, and retiring a string for each of those would make the list grow with idle churn instead. Pointer IDENTITY is the observable.

Definition at line 135 of file test_conf_value_lifetime.c.

References dt_conf_get_string_const(), dt_conf_set_string(), i, state, TEST_KEY, and void().

Referenced by main().

◆ _setup()

static int _setup ( void **  state)
static

Definition at line 63 of file test_conf_value_lifetime.c.

References _rcfile, darktable_t::conf, darktable, dt_conf_init(), state, and void().

Referenced by main().

◆ _teardown()

static int _teardown ( void **  state)
static

Definition at line 75 of file test_conf_value_lifetime.c.

References _rcfile, darktable_t::conf, darktable, dt_conf_cleanup(), state, and void().

Referenced by main().

◆ _typed_setters_retire_too()

static void _typed_setters_retire_too ( void **  state)
static

The typed setters go through the same writer, so they inherit the same guarantee.

Definition at line 149 of file test_conf_value_lifetime.c.

References dt_conf_get_int_fast(), dt_conf_get_string_const(), dt_conf_set_int(), state, TEST_KEY, and void().

Referenced by main().

◆ main()

Variable Documentation

◆ _rcfile

char* _rcfile = NULL
static

Definition at line 61 of file test_conf_value_lifetime.c.

Referenced by _setup(), and _teardown().