feat(libxce-alloc-preason-equality): NULL-safe str_eq helper in libxce utils (task 1.1)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-09-28 09:21:04 +00:00
parent 094577f245
commit 8f25c1c3f3
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
4 changed files with 56 additions and 2 deletions

View file

@ -2,8 +2,8 @@
Test-first throughout (red → green → refactor). Every sub-task leaves the build and all test suites green: consumers move to the public API before the private comparators are deleted, test fixtures are brought in line before `from` starts being compared, and each change updates the tests it affects.
- [ ] 1. Foundation: shared NULL-safe string equality
- [ ] 1.1 Provide a NULL-safe string-equality helper in libxce
- [x] 1. Foundation: shared NULL-safe string equality
- [x] 1.1 Provide a NULL-safe string-equality helper in libxce
- Write the tests first: two NULL strings are equal; one NULL and one non-NULL are not equal in either order; equal strings are equal; different strings are not.
- Add the helper beside the existing floating-point comparison helper in the shared utilities, as described in design.md (Decision 5).
- Done when the libxce utility tests include these cases and the libxce suite passes under ASAN.
@ -84,3 +84,6 @@ Test-first throughout (red → green → refactor). Every sub-task leaves the bu
- Done when the test passes and the live replay reports zero mismatches; then mark bug-1881 fixed through the buglog skill with the fix commit.
- _Requirements: 4.3, 5.4_
- _Depends: spec scheduler-sim-discrete-clock_
## Implementation Notes
- `xce-build.sh` resolves a relative build dir under `src/`: `bash src/tools/xce-build.sh lib asan xce.build.alloceq` builds into `src/xce.build.alloceq`, so iterate with `meson test -C src/xce.build.alloceq`.

View file

@ -57,6 +57,11 @@
#define float_equal(a, b) (fabs((a) - (b)) < float_near_zero)
/* NULL-safe string equality: non-zero iff a and b are both NULL, or both
* non-NULL and strcmp(a, b) == 0; zero otherwise (exactly one NULL, or
* different contents). Reads only; never modifies either argument. */
extern int str_eq(const char* a, const char* b);
#define STR(x) _STR(x)
#define _STR(x) #x

View file

@ -426,6 +426,42 @@ test_xce_format_units_value_both_mode_renders_raw_and_human(void)
TEST_ASSERT_EQUAL_STRING(expected, buf);
}
/* str_eq: NULL-safe string equality (libxce-alloc-preason-equality
* task 1.1, Requirements 1.5 / 2.3, design Decision 5). */
static void test_str_eq_both_null_are_equal(void)
{
TEST_ASSERT_TRUE(str_eq(NULL, NULL));
}
static void test_str_eq_one_null_is_not_equal_either_order(void)
{
TEST_ASSERT_FALSE(str_eq(NULL, "cpu"));
TEST_ASSERT_FALSE(str_eq("cpu", NULL));
/* An empty string is still non-NULL: it must not equal NULL. */
TEST_ASSERT_FALSE(str_eq(NULL, ""));
TEST_ASSERT_FALSE(str_eq("", NULL));
}
static void test_str_eq_equal_strings_are_equal(void)
{
/* Distinct buffers with the same content, so the result cannot come
* from pointer identity. */
char a[] = "node01";
char b[] = "node01";
TEST_ASSERT_TRUE(str_eq(a, b));
TEST_ASSERT_TRUE(str_eq(a, a));
TEST_ASSERT_TRUE(str_eq("", ""));
}
static void test_str_eq_different_strings_are_not_equal(void)
{
TEST_ASSERT_FALSE(str_eq("node01", "node02"));
TEST_ASSERT_FALSE(str_eq("node0", "node01"));
TEST_ASSERT_FALSE(str_eq("node01", "node0"));
TEST_ASSERT_FALSE(str_eq("", "x"));
}
void test_utils(void)
{
printf("\n>> utils test\n\n");
@ -455,4 +491,8 @@ void test_utils(void)
RUN_TEST(test_xce_format_units_value_raw_mode_renders_bare_value);
RUN_TEST(test_xce_format_units_value_human_mode_renders_scaled_string_alone);
RUN_TEST(test_xce_format_units_value_both_mode_renders_raw_and_human);
RUN_TEST(test_str_eq_both_null_are_equal);
RUN_TEST(test_str_eq_one_null_is_not_equal_either_order);
RUN_TEST(test_str_eq_equal_strings_are_equal);
RUN_TEST(test_str_eq_different_strings_are_not_equal);
}

View file

@ -146,6 +146,12 @@ void free_argv(char** argv, int argc) { FREE_ARGV(argv, argc); }
int get_myname(char* name, size_t size) { return gethostname(name, size); }
int str_eq(const char* a, const char* b)
{
if (a == NULL || b == NULL) return a == b;
return strcmp(a, b) == 0;
}
char* frame_symbol(int k)
{
#if defined(__linux__)