Skip to content

Commit 4d8e990

Browse files
Improve developer experience.
Add tests for nmMalloc(). Add EXPECT_NOT_NULL() to test_utils.h. Modify test runner to use 5s timeout normally, but 90s timeout in Valgrind. Improve documentation, style, and formatting.
1 parent 62b2652 commit 4d8e990

File tree

6 files changed

+385
-4
lines changed

6 files changed

+385
-4
lines changed

centrallix-lib/tests/t_driver.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,23 @@ start(void* v)
5959
signal(SIGSEGV, segv_handler);
6060
signal(SIGABRT, abort_handler);
6161
signal(SIGALRM, alarm_handler);
62-
alarm(10);
62+
63+
/*** Set a timer before Lockup is triggered, using a significantly
64+
*** larger value if Valgrind appears to be enabled.
65+
***/
66+
#ifndef NM_USE_SYSMALLOC
67+
alarm(90); /* Valgrind detected. */
68+
#else
69+
alarm(5); /* Normal timeout. */
70+
#endif
71+
72+
6373
times(&t);
6474
start = t.tms_utime + t.tms_stime + t.tms_cutime + t.tms_cstime;
6575
rval = test(&tname);
6676
times(&t);
6777
end = t.tms_utime + t.tms_stime + t.tms_cutime + t.tms_cstime;
78+
6879
if (rval < 0)
6980
printf("%-62.62s FAIL\n", tname);
7081
else
@@ -78,7 +89,7 @@ start(void* v)
7889
}
7990
long long ops_per_second = rval * (100 / duration);
8091
if (ops_per_second > 0) printf("%-62.62s PASS %lld\n", tname, ops_per_second);
81-
else printf("%-62.62s PASS %.4g\n", tname, rval * (100.0 / duration));
92+
else printf("%-62.62s PASS %.4lf\n", tname, rval * (100.0 / duration));
8293
}
8394

8495
return;
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/************************************************************************/
2+
/* Centrallix Application Server System */
3+
/* Centrallix Base Library */
4+
/* */
5+
/* Copyright (C) 2005 LightSys Technology Services, Inc. */
6+
/* */
7+
/* You may use these files and this library under the terms of the */
8+
/* GNU Lesser General Public License, Version 2.1, contained in the */
9+
/* included file "COPYING". */
10+
/* */
11+
/* Module: test_newmalloc_00.c */
12+
/* Author: Israel Fuller */
13+
/* Creation: November 25th, 2025 */
14+
/* Description: Test the nmSysMalloc(), nmSysFree(), nmSysRealloc(), */
15+
/* and nmSysStrDup functions from the NewMalloc library. */
16+
/************************************************************************/
17+
18+
#include <math.h>
19+
#include <stdbool.h>
20+
#include <stdio.h>
21+
#include <stdlib.h>
22+
23+
/** Test dependencies. **/
24+
#include "test_utils.h"
25+
#include "util.h"
26+
27+
/** Tested module. **/
28+
#include "newmalloc.h"
29+
30+
static unsigned int seed_counter = 0;
31+
static char* err_buf;
32+
static unsigned int err_buf_i;
33+
static unsigned int err_buf_size;
34+
35+
static int mock_error_fn(char* error_msg)
36+
{
37+
const size_t len = strlen(error_msg) + 1lu;
38+
39+
/** Ensure enough space to store the error. **/
40+
while (len > err_buf_size - err_buf_i)
41+
{
42+
err_buf_size *= 2;
43+
err_buf = check_ptr(realloc(err_buf, err_buf_size));
44+
}
45+
46+
err_buf_i += snprintf(
47+
err_buf + err_buf_i,
48+
err_buf_size - err_buf_i,
49+
"> %s\n", error_msg
50+
);
51+
52+
return 0;
53+
}
54+
55+
/** Initialize memory of a given size with random data. **/
56+
static void* random_init(void* ptr, size_t size)
57+
{
58+
if (ptr == NULL) return NULL;
59+
unsigned char* p = (unsigned char*)ptr;
60+
for (size_t i = 0; i < size; i++) {
61+
p[i] = (unsigned char)(rand() % 256);
62+
}
63+
return ptr;
64+
}
65+
66+
static bool do_tests(void)
67+
{
68+
bool success = true;
69+
70+
/** Set a consistent, distinct seed for each test iteration. **/
71+
srand(seed_counter++);
72+
73+
/** Initialize the mock error function. **/
74+
err_buf = check_ptr(malloc(err_buf_size = 256));
75+
err_buf_i = snprintf(err_buf, err_buf_size, "%s", "");
76+
nmSetErrFunction(mock_error_fn);
77+
78+
/** Baseline: Should leak. **/
79+
success &= EXPECT_NOT_NULL(nmSysMalloc(42));
80+
81+
/** Basic string data. **/
82+
char* str1;
83+
success &= EXPECT_NOT_NULL(str1 = nmSysMalloc(16));
84+
snprintf(str1, 16, "ThisIsSomeData!");
85+
char* str2;
86+
success &= EXPECT_NOT_NULL(str2 = nmSysMalloc(32));
87+
snprintf(str2, 32, "ThisDataIsDifferentStringData.\n");
88+
success &= EXPECT_STR_EQL(str1, "ThisIsSomeData!");
89+
success &= EXPECT_STR_EQL(str2, "ThisDataIsDifferentStringData.\n");
90+
91+
/** 128 MB random data, varying sizes. **/
92+
#define TEST_LIMIT 16384
93+
void** data = check_ptr(malloc(TEST_LIMIT * sizeof(void*)));
94+
void** test = check_ptr(malloc(TEST_LIMIT * sizeof(void*)));
95+
for (size_t i = 1lu; i < TEST_LIMIT; i++)
96+
{
97+
success &= EXPECT_NOT_NULL(test[i] = nmSysMalloc(i));
98+
data[i] = random_init(check_ptr(malloc(i)), i);
99+
memcpy(test[i], data[i], i);
100+
}
101+
for (size_t i = TEST_LIMIT - 1lu; i > 0lu; i--)
102+
success &= EXPECT_EQL(memcmp(data[i], test[i], i), 0, "%d");
103+
104+
/** Basic string data is unharmed. **/
105+
success &= EXPECT_STR_EQL(str1, "ThisIsSomeData!");
106+
success &= EXPECT_STR_EQL(str2, "ThisDataIsDifferentStringData.\n");
107+
108+
/** Reallocate all variably sized memory to a different size. **/
109+
for (size_t i = TEST_LIMIT - 1lu; i > 0lu; i--)
110+
success &= EXPECT_NOT_NULL(test[i] = nmSysRealloc(test[i], i));
111+
for (size_t i = 1lu; i < TEST_LIMIT; i++)
112+
success &= EXPECT_EQL(memcmp(data[i], test[i], min(i, TEST_LIMIT - i)), 0, "%d");
113+
114+
/** Basic string data is unharmed. **/
115+
success &= EXPECT_STR_EQL(str1, "ThisIsSomeData!");
116+
success &= EXPECT_STR_EQL(str2, "ThisDataIsDifferentStringData.\n");
117+
118+
/** Testing strdup. **/
119+
char* str_dup1;
120+
char* str_dup2;
121+
success &= EXPECT_NOT_NULL(str_dup1 = nmSysStrdup(str1));
122+
success &= EXPECT_NOT_NULL(str_dup2 = nmSysStrdup(str2));
123+
success &= EXPECT_STR_EQL(str_dup1, "ThisIsSomeData!");
124+
success &= EXPECT_STR_EQL(str_dup2, "ThisDataIsDifferentStringData.\n");
125+
str_dup1[12] = '\0';
126+
str_dup2[2] = 'a';
127+
str_dup2[3] = 't';
128+
success &= EXPECT_STR_EQL(str_dup1, "ThisIsSomeDa");
129+
success &= EXPECT_STR_EQL(str_dup2, "ThatDataIsDifferentStringData.\n");
130+
131+
/** Basic string data is unharmed. **/
132+
success &= EXPECT_STR_EQL(str1, "ThisIsSomeData!");
133+
success &= EXPECT_STR_EQL(str2, "ThisDataIsDifferentStringData.\n");
134+
135+
/** Free random data, varying sizes. **/
136+
for (size_t i = 1lu; i < TEST_LIMIT; i++)
137+
{
138+
free(data[i]);
139+
nmSysFree(test[i]);
140+
}
141+
142+
/** Basic string data is unharmed. **/
143+
success &= EXPECT_STR_EQL(str1, "ThisIsSomeData!");
144+
success &= EXPECT_STR_EQL(str2, "ThisDataIsDifferentStringData.\n");
145+
146+
/** Free data. **/
147+
nmSysFree(str1);
148+
nmSysFree(str2);
149+
150+
/** Dup string data is unharmed. **/
151+
success &= EXPECT_STR_EQL(str_dup1, "ThisIsSomeDa");
152+
success &= EXPECT_STR_EQL(str_dup2, "ThatDataIsDifferentStringData.\n");
153+
154+
/** Large singular allocation. **/
155+
#define _256MB 256000000lu
156+
void* large_buf;
157+
success &= EXPECT_NOT_NULL(large_buf = nmSysMalloc(_256MB));
158+
for (size_t i = _256MB - 1lu; i > 0lu; i--)
159+
*((unsigned char*)large_buf + i) = (unsigned char)(i % 255lu);
160+
*(unsigned char*)large_buf = 0u;
161+
for (size_t i = 0lu; i < _256MB; i++)
162+
success &= EXPECT_EQL(*((unsigned char*)large_buf + i), (unsigned char)(i % 255lu), "%d");
163+
164+
/** Dup string data is unharmed. **/
165+
success &= EXPECT_STR_EQL(str_dup1, "ThisIsSomeDa");
166+
success &= EXPECT_STR_EQL(str_dup2, "ThatDataIsDifferentStringData.\n");
167+
168+
/** Free dups. **/
169+
nmSysFree(str_dup1);
170+
nmSysFree(str_dup2);
171+
172+
/** Free large allocation. **/
173+
nmSysFree(large_buf);
174+
175+
/** Expect no captured errors. **/
176+
success &= EXPECT_STR_EQL(err_buf, "");
177+
178+
return success;
179+
}
180+
181+
long long test(char** tname)
182+
{
183+
*tname = "newmalloc-00 nmSysMalloc(), nmSysFree(), nmSysRealloc(), & nmSysStrdup()";
184+
return loop_tests(do_tests);
185+
}
186+
187+
/** Scope cleanup. **/
188+
#undef TEST_LIMIT
189+
#undef _256MB
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/************************************************************************/
2+
/* Centrallix Application Server System */
3+
/* Centrallix Base Library */
4+
/* */
5+
/* Copyright (C) 2005 LightSys Technology Services, Inc. */
6+
/* */
7+
/* You may use these files and this library under the terms of the */
8+
/* GNU Lesser General Public License, Version 2.1, contained in the */
9+
/* included file "COPYING". */
10+
/* */
11+
/* Module: test_newmalloc_01.c */
12+
/* Author: Israel Fuller */
13+
/* Creation: December 15th, 2025 */
14+
/* Description: Test the nmMalloc(), nmFree(), and nmClear() functions */
15+
/* from the NewMalloc library. */
16+
/************************************************************************/
17+
18+
#include <math.h>
19+
#include <stdbool.h>
20+
#include <stdio.h>
21+
#include <stdlib.h>
22+
23+
/** Test dependencies. **/
24+
#include "test_utils.h"
25+
#include "util.h"
26+
27+
/** Tested module. **/
28+
#include "newmalloc.h"
29+
30+
static unsigned int seed_counter = 0;
31+
static char* err_buf;
32+
static unsigned int err_buf_i;
33+
static unsigned int err_buf_size;
34+
35+
static int mock_error_fn(char* error_msg)
36+
{
37+
const size_t len = strlen(error_msg) + 1lu;
38+
39+
/** Ensure enough space to store the error. **/
40+
while (len > err_buf_size - err_buf_i)
41+
{
42+
err_buf_size *= 2;
43+
err_buf = check_ptr(realloc(err_buf, err_buf_size));
44+
}
45+
46+
err_buf_i += snprintf(
47+
err_buf + err_buf_i,
48+
err_buf_size - err_buf_i,
49+
"> %s\n", error_msg
50+
);
51+
52+
return 0;
53+
}
54+
55+
/** Initialize memory of a given size with random data. **/
56+
static void* random_init(void* ptr, size_t size)
57+
{
58+
if (ptr == NULL) return NULL;
59+
unsigned char* p = (unsigned char*)ptr;
60+
for (size_t i = 0; i < size; i++) {
61+
p[i] = (unsigned char)(rand() % 256);
62+
}
63+
return ptr;
64+
}
65+
66+
static bool do_tests(void)
67+
{
68+
bool success = true;
69+
70+
/** Set a consistent, distinct seed for each test iteration. **/
71+
srand(seed_counter++);
72+
73+
/** Initialize the mock error function. **/
74+
err_buf = check_ptr(malloc(err_buf_size = 256));
75+
err_buf_i = snprintf(err_buf, err_buf_size, "%s", "");
76+
nmSetErrFunction(mock_error_fn);
77+
78+
/** Baseline: Should leak. **/
79+
success &= EXPECT_NOT_NULL(nmMalloc(42));
80+
81+
/** Basic string data. **/
82+
char* str1;
83+
success &= EXPECT_NOT_NULL(str1 = nmMalloc(16));
84+
snprintf(str1, 16, "ThisIsSomeData!");
85+
char* str2;
86+
success &= EXPECT_NOT_NULL(str2 = nmMalloc(32));
87+
snprintf(str2, 32, "ThisDataIsDifferentStringData.\n");
88+
success &= EXPECT_STR_EQL(str1, "ThisIsSomeData!");
89+
success &= EXPECT_STR_EQL(str2, "ThisDataIsDifferentStringData.\n");
90+
91+
/** 128 MB random data, varying sizes. **/
92+
#define TEST_LIMIT 16384
93+
void** data = check_ptr(malloc(TEST_LIMIT * sizeof(void*)));
94+
void** test = check_ptr(malloc(TEST_LIMIT * sizeof(void*)));
95+
for (size_t i = 1lu; i < TEST_LIMIT; i++)
96+
{
97+
success &= EXPECT_NOT_NULL(test[i] = nmMalloc(i));
98+
data[i] = random_init(check_ptr(malloc(i)), i);
99+
memcpy(test[i], data[i], i);
100+
}
101+
for (size_t i = TEST_LIMIT - 1lu; i > 0lu; i--)
102+
success &= EXPECT_EQL(memcmp(data[i], test[i], i), 0, "%d");
103+
104+
/** Basic string data is unharmed. **/
105+
success &= EXPECT_STR_EQL(str1, "ThisIsSomeData!");
106+
success &= EXPECT_STR_EQL(str2, "ThisDataIsDifferentStringData.\n");
107+
108+
/** Large singular allocation. **/
109+
#define _256MB 256000000lu
110+
void* large_buf;
111+
success &= EXPECT_NOT_NULL(large_buf = nmMalloc(_256MB));
112+
for (size_t i = _256MB - 1lu; i > 0lu; i--)
113+
*((unsigned char*)large_buf + i) = (unsigned char)(i % 255lu);
114+
*(unsigned char*)large_buf = 0u;
115+
for (size_t i = 0lu; i < _256MB; i++)
116+
success &= EXPECT_EQL(*((unsigned char*)large_buf + i), (unsigned char)(i % 255lu), "%d");
117+
118+
/** Dup string data is unharmed. **/
119+
success &= EXPECT_STR_EQL(str1, "ThisIsSomeData!");
120+
success &= EXPECT_STR_EQL(str2, "ThisDataIsDifferentStringData.\n");
121+
122+
/** Free random data, varying sizes. **/
123+
for (size_t i = 1lu; i < TEST_LIMIT; i++)
124+
{
125+
free(data[i]);
126+
nmFree(test[i], i);
127+
}
128+
129+
/** Basic string data is unharmed. **/
130+
success &= EXPECT_STR_EQL(str1, "ThisIsSomeData!");
131+
success &= EXPECT_STR_EQL(str2, "ThisDataIsDifferentStringData.\n");
132+
133+
/** Free data. **/
134+
nmFree(str1, 16);
135+
nmFree(str2, 32);
136+
137+
/** Free large allocation. **/
138+
nmFree(large_buf, _256MB);
139+
140+
/** Clear cache. **/
141+
nmClear();
142+
143+
/** Debug info. **/
144+
printf("\n");
145+
nmStats();
146+
147+
/** Expect no captured errors. **/
148+
success &= EXPECT_STR_EQL(err_buf, "");
149+
150+
return success;
151+
}
152+
153+
long long test(char** tname)
154+
{
155+
*tname = "newmalloc-01 nmMalloc(), nmFree(), & nmClear()";
156+
return loop_tests(do_tests);
157+
}
158+
159+
/** Scope cleanup. **/
160+
#undef TEST_LIMIT
161+
#undef _256MB

0 commit comments

Comments
 (0)