• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

drakenclimber / libcgroup / 22956879275

11 Mar 2026 02:11PM UTC coverage: 56.21% (+0.04%) from 56.167%
22956879275

push

github

drakenclimber
src/config: free namespace table on success and failure

The per-thread namespace table (cg_namespace_table[]) is populated by
config_order_namespace_table() / config_validate_namespaces() under
cg_mount_table_lock and then consumed by cg_build_path_locked().
Before this patch we reset the array with a bespoke loop + memset at the
front of config_order_namespace_table(), but error paths relied on the
call chain eventually unwinding into cgroup_free_config() to release
any partially populated entries. That worked, yet it meant the table
could briefly hold dangling pointers after an error while the lock was
already dropped, one subtle slip or new return path would have left stale
namespaces visible to the rest of the library.

This change introduces a small helper,
cgroup_config_free_namespaces_table(), that walks the thread-local
array, frees each string, and nulls the slot. We invoke it in three
places:

- right at the start of config_order_namespace_table(), so every run
  begins with a clean slate.
- from the error branches of both namespace helpers, guaranteeing that
  even a mid-stream failure leaves the table empty before the lock is
  released.
- and (unchanged) from cgroup_free_config(), so the happy path tears
  everything down once the config work finishes.

The end result is both cleaner and safer: we delete the redundant
set-to-NULL/memset sequence and the namespace table is always in a known
state no matter how the parser exits.

Signed-off-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>

8 of 10 new or added lines in 1 file covered. (80.0%)

1116 existing lines in 5 files now uncovered.

5621 of 10000 relevant lines covered (56.21%)

602.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

17.76
/src/parse.y
1
// SPDX-License-Identifier: LGPL-2.1-only
2
/**
3
 * Copyright IBM Corporation. 2007
4
 *
5
 * Authors:        Balbir Singh <balbir@linux.vnet.ibm.com>
6
 *
7
 * NOTE: The grammar has been modified, not to be the most efficient, but
8
 * to allow easy updation of internal data structures.
9
 */
10

11
%{
12
#include <stdlib.h>
13
#include <stdio.h>
14
#include <string.h>
15
#include <libcgroup.h>
16
#include <libcgroup-internal.h>
17

18
int yylex(void);
19
extern int line_no;
20
extern char *yytext;
21

22
static void yyerror(const char *s)
1✔
23
{
24
        fprintf(stderr, "error at line number %d at %s:%s\n", line_no, yytext, s);
1✔
25
}
1✔
26

27
int yywrap(void)
26✔
28
{
29
        return 1;
26✔
30
}
31

32
%}
33

34
%token <name> ID MOUNT GROUP PERM TASK ADMIN NAMESPACE DEFAULT TEMPLATE SYSTEMD
35

36
%union {
37
        char *name;
38
        char chr;
39
        int val;
40
        struct cgroup_dictionary *values;
41
}
42
%type <name> group_name
43
%type <val> mountvalue_conf mount task_namevalue_conf admin_namevalue_conf
44
%type <val> admin_conf task_conf task_or_admin group_conf group start
45
%type <val> namespace namespace_conf default default_conf
46
%type <values> namevalue_conf
47
%type <val> template template_conf
48
%type <val> template_task_or_admin template_task_namevalue_conf
49
%type <val> template_admin_namevalue_conf template_task_conf
50
%type <val> template_admin_conf
51
%type <val> systemdvalue_conf systemd
52
%start start
53
%%
54

55
start   : start group
56
        {
57
                $$ = $1;
16✔
58
        }
59
        | start mount
60
        {
61
                $$ = $1;
×
62
        }
63
        | start default
64
        {
65
          $$ = $1;
×
66
        }
67
        | start namespace
68
        {
69
                $$ = $1;
×
70
        }
71
        | start template
72
        {
73
                $$ = $1;
×
74
        }
75
        | start systemd
76
        {
77
                $$ = $1;
13✔
78
        }
79
        |
80
        {
81
                $$ = 1;
32✔
82
        }
83
        ;
84

85
default :       DEFAULT '{' default_conf '}'
86
        {
87
                $$ = $3;
×
88
                if ($$) {
×
89
                        cgroup_config_define_default();
×
90
                }
91
        }
92
        ;
93

94
default_conf
95
        :       PERM '{' task_or_admin '}'
96
        {
97
                $$ = $3;
×
98
        }
99
        ;
100

101
group   :       GROUP group_name '{' group_conf '}'
102
        {
103
                $$ = $4;
16✔
104
                if ($$) {
16✔
105
                        $$ = cgroup_config_insert_cgroup($2);
16✔
106
                        if (!$$) {
16✔
107
                                fprintf(stderr, "failed to insert group check size and memory");
×
108
                                $$ = ECGOTHER;
×
109
                                return $$;
×
110
                        }
111
                } else {
112
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
113
                        $$ = ECGCONFIGPARSEFAIL;
×
114
                        return $$;
×
115
                }
116
        }
117
        ;
118

119
group_name
120
        :        ID
121
        {
122
                $$ = $1;
16✔
123
        }
124
        |        DEFAULT
125
        {
126
                $$ = $1;
×
127
        }
128

129
group_conf
130
        :       ID '{' namevalue_conf '}'
131
        {
132
                $$ = cgroup_config_parse_controller_options($1, $3);
16✔
133
                cgroup_dictionary_free($3);
16✔
134
                if (!$$) {
16✔
135
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
136
                        $$ = ECGCONFIGPARSEFAIL;
×
137
                        return $$;
×
138
                }
139
        }
140
        |       group_conf ID '{' namevalue_conf '}'
141
        {
142
                $$ = cgroup_config_parse_controller_options($2, $4);
×
143
                cgroup_dictionary_free($4);
×
144
                if (!$$) {
×
145
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
146
                        $$ = ECGCONFIGPARSEFAIL;
×
147
                        return $$;
×
148
                }
149
        }
150
        |       PERM '{' task_or_admin '}'
151
        {
152
                $$ = $3;
×
153
                if (!$$) {
×
154
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
155
                        $$ = ECGCONFIGPARSEFAIL;
×
156
                        return $$;
×
157
                }
158
        }
159
        ;
160

161
template  :     TEMPLATE ID '{' template_conf '}'
162
        {
163
                $$ = $4;
×
164
                if ($$) {
×
165
                        $$ = template_config_insert_cgroup($2);
×
166
                        if (!$$) {
×
167
                                fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
168
                                $$ = ECGOTHER;
×
169
                                return $$;
×
170
                        }
171
                } else {
172
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
173
                        $$ = ECGCONFIGPARSEFAIL;
×
174
                        return $$;
×
175
                }
176
        }
177
        ;
178

179

180
template_conf
181
        :       ID '{' namevalue_conf '}'
182
        {
183
                $$ = template_config_parse_controller_options($1, $3);
×
184
                cgroup_dictionary_free($3);
×
185
                if (!$$) {
×
186
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
187
                        $$ = ECGCONFIGPARSEFAIL;
×
188
                        return $$;
×
189
                }
190
        }
191
        |       template_conf ID '{' namevalue_conf '}'
192
        {
193
                $$ = template_config_parse_controller_options($2, $4);
×
194
                cgroup_dictionary_free($4);
×
195
                if (!$$) {
×
196
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
197
                        $$ = ECGCONFIGPARSEFAIL;
×
198
                        return $$;
×
199
                }
200
        }
201
        |       PERM '{' template_task_or_admin '}'
202
        {
203
                $$ = $3;
×
204
                if (!$$) {
×
205
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
206
                        $$ = ECGCONFIGPARSEFAIL;
×
207
                        return $$;
×
208
                }
209
        }
210
        ;
211

212
template_task_or_admin
213
        :        TASK '{' template_task_namevalue_conf '}' template_admin_conf
214
        {
215
        $$ = $3 && $5;
×
216
                if (!$$) {
×
217
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
218
                        $$ = ECGCONFIGPARSEFAIL;
×
219
                        return $$;
×
220
                }
221
        }
222
        |       ADMIN '{' template_admin_namevalue_conf '}' template_task_conf
223
        {
224
                $$ = $3 && $5;
×
225
                if (!$$) {
×
226
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
227
                        $$ = ECGCONFIGPARSEFAIL;
×
228
                return $$;
×
229
                }
230
        }
231
        ;
232

233

234
namevalue_conf
235
        :       ID '=' ID ';'
236
        {
237
                struct cgroup_dictionary *dict;
238
                int ret;
239
                ret = cgroup_dictionary_create(&dict, 0);
12✔
240
                if (ret == 0)
12✔
241
                        ret = cgroup_dictionary_add(dict, $1, $3);
12✔
242
                if (ret) {
12✔
243
                        fprintf(stderr, "parsing failed at line number %d:%s\n", line_no,
×
244
                                cgroup_strerror(ret));
245
                        $$ = NULL;
×
246
                        cgroup_dictionary_free(dict);
×
247
                        return ECGCONFIGPARSEFAIL;
×
248
                }
249
                $$ = dict;
12✔
250
        }
251
        |       namevalue_conf ID '=' ID ';'
252
        {
253
                int ret = 0;
12✔
254
                ret = cgroup_dictionary_add($1, $2, $4);
12✔
255
                if (ret != 0) {
12✔
UNCOV
256
                        fprintf(stderr, "parsing failed at line number %d: %s\n", line_no,
×
257
                                cgroup_strerror(ret));
UNCOV
258
                        $$ = NULL;
×
259
                        return ECGCONFIGPARSEFAIL;
×
260
                }
261
                $$ = $1;
12✔
262
        }
263
        |
264
        {
265
                $$ = NULL;
4✔
266
        }
267
        ;
268

269
task_namevalue_conf
270
        :       ID '=' ID ';'
271
        {
UNCOV
272
                $$ = cgroup_config_group_task_perm($1, $3);
×
UNCOV
273
                if (!$$) {
×
UNCOV
274
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
275
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
276
                        return $$;
×
277
                }
278
        }
279
        |       task_namevalue_conf ID '=' ID ';'
280
        {
281
                $$ = $1 && cgroup_config_group_task_perm($2, $4);
×
UNCOV
282
                if (!$$) {
×
UNCOV
283
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
284
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
285
                        return $$;
×
286
                }
287
        }
288
        ;
289

290
admin_namevalue_conf
291
        :       ID '=' ID ';'
292
        {
UNCOV
293
                $$ = cgroup_config_group_admin_perm($1, $3);
×
UNCOV
294
                if (!$$) {
×
UNCOV
295
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
296
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
297
                        return $$;
×
298
                }
299
        }
300
        |       admin_namevalue_conf ID '=' ID ';'
301
        {
302
                $$ = $1 && cgroup_config_group_admin_perm($2, $4);
×
UNCOV
303
                if (!$$) {
×
UNCOV
304
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
305
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
306
                        return $$;
×
307
                }
308
        }
309
        ;
310

311
template_task_namevalue_conf
312
        :       ID '=' ID ';'
313
        {
UNCOV
314
                $$ = template_config_group_task_perm($1, $3);
×
UNCOV
315
                if (!$$) {
×
UNCOV
316
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
317
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
318
                        return $$;
×
319
                }
320
        }
321
        |       template_task_namevalue_conf ID '=' ID ';'
322
        {
323
                $$ = $1 && template_config_group_task_perm($2, $4);
×
UNCOV
324
                if (!$$) {
×
UNCOV
325
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
326
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
327
                        return $$;
×
328
                }
329
        }
330
        ;
331

332
template_admin_namevalue_conf
333
        :       ID '=' ID ';'
334
        {
UNCOV
335
                $$ = template_config_group_admin_perm($1, $3);
×
UNCOV
336
                if (!$$) {
×
UNCOV
337
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
338
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
339
                        return $$;
×
340
                }
341
        }
342
        |       template_admin_namevalue_conf ID '=' ID ';'
343
        {
344
                $$ = $1 && template_config_group_admin_perm($2, $4);
×
UNCOV
345
                if (!$$) {
×
UNCOV
346
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
347
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
348
                        return $$;
×
349
                }
350
        }
351
        ;
352

353

354
task_or_admin
355
        :       TASK '{' task_namevalue_conf '}' admin_conf
356
        {
UNCOV
357
                $$ = $3 && $5;
×
UNCOV
358
                if (!$$) {
×
UNCOV
359
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
360
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
361
                        return $$;
×
362
                }
363
        }
364
        |       ADMIN '{' admin_namevalue_conf '}' task_conf
365
        {
366
                $$ = $3 && $5;
×
UNCOV
367
                if (!$$) {
×
UNCOV
368
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
369
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
370
                        return $$;
×
371
                }
372
        }
373
        ;
374

375
admin_conf:        ADMIN '{' admin_namevalue_conf '}'
376
        {
UNCOV
377
                $$ = $3;
×
UNCOV
378
                if (!$$) {
×
UNCOV
379
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
380
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
381
                        return $$;
×
382
                }
383
        }
384
        ;
385

386
task_conf:        TASK '{' task_namevalue_conf '}'
387
        {
UNCOV
388
                $$ = $3;
×
UNCOV
389
                if (!$$) {
×
UNCOV
390
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
391
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
392
                        return $$;
×
393
                }
394
        }
395
        ;
396

397
template_admin_conf:        ADMIN '{' template_admin_namevalue_conf '}'
398
        {
UNCOV
399
                $$ = $3;
×
UNCOV
400
                if (!$$) {
×
UNCOV
401
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
402
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
403
                        return $$;
×
404
                }
405
        }
406
        ;
407

408
template_task_conf:        TASK '{' template_task_namevalue_conf '}'
409
        {
UNCOV
410
                $$ = $3;
×
UNCOV
411
                if (!$$) {
×
UNCOV
412
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
413
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
414
                        return $$;
×
415
                }
416
        }
417
        ;
418

419
mountvalue_conf
420
        :       ID '=' ID ';'
421
        {
UNCOV
422
                if (!cgroup_config_insert_into_mount_table($1, $3)) {
×
UNCOV
423
                        cgroup_config_cleanup_mount_table();
×
UNCOV
424
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
425
                        return $$;
×
426
                }
427
                $$ = 1;
×
428
        }
429
        |       mountvalue_conf ID '=' ID ';'
430
        {
UNCOV
431
                if (!cgroup_config_insert_into_mount_table($2, $4)) {
×
432
                        cgroup_config_cleanup_mount_table();
×
UNCOV
433
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
434
                        return $$;
×
435
                }
436
                $$ = 1;
×
437
        }
438
        ;
439

440
mount   :       MOUNT '{' mountvalue_conf '}'
441
        {
UNCOV
442
                $$ = $3;
×
UNCOV
443
                if (!$$) {
×
UNCOV
444
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
445
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
446
                        return $$;
×
447
                }
448
        }
449
        ;
450

451
namespace_conf
452
        :       ID '=' ID ';'
453
        {
UNCOV
454
                if (!cgroup_config_insert_into_namespace_table($1, $3)) {
×
UNCOV
455
                        cgroup_config_cleanup_namespace_table();
×
UNCOV
456
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
457
                        return $$;
×
458
                }
459
                $$ = 1;
×
460
        }
461
        |       namespace_conf ID '=' ID ';'
462
        {
UNCOV
463
                if (!cgroup_config_insert_into_namespace_table($2, $4)) {
×
464
                        cgroup_config_cleanup_namespace_table();
×
UNCOV
465
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
466
                        return $$;
×
467
                }
468
                $$ = 1;
×
469
        }
470
        ;
471

472
namespace   :       NAMESPACE '{' namespace_conf '}'
473
        {
UNCOV
474
                $$ = $3;
×
UNCOV
475
                if (!$$) {
×
UNCOV
476
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
477
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
478
                        return $$;
×
479
                }
480
        }
481
        ;
482

483
systemdvalue_conf
484
        :        ID '=' ID ';'
485
        {
486
                if (!cgroup_alloc_systemd_opts($1, $3)) {
18✔
487
                        cgroup_cleanup_systemd_opts();
3✔
488
                        $$ = ECGCONFIGPARSEFAIL;
3✔
489
                        return $$;
3✔
490
                }
491
                $$ = 1;
15✔
492
        }
493
        |        systemdvalue_conf ID '=' ID ';'
494
        {
495
                if (!cgroup_add_systemd_opts($2, $4)) {
28✔
496
                        cgroup_cleanup_systemd_opts();
2✔
497
                        $$ = ECGCONFIGPARSEFAIL;
2✔
498
                        return $$;
2✔
499
                }
500
                $$ = 1;
26✔
501
        }
502
        ;
503

504
systemd   :          SYSTEMD '{' systemdvalue_conf '}'
505
        {
506
                $$ = $3;
13✔
507
                if (!$$) {
13✔
UNCOV
508
                        fprintf(stderr, "parsing failed at line number %d\n", line_no);
×
UNCOV
509
                        $$ = ECGCONFIGPARSEFAIL;
×
UNCOV
510
                        return $$;
×
511
                }
512
        }
513
        ;
514
%%
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc