1 /*
2 * SPDX-License-Identifier: ISC
3 *
4 * Copyright (c) 2016-2018 Todd C. Miller <Todd.Miller@sudo.ws>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * This is an open source non-commercial project. Dear PVS-Studio, please check it.
21 * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
22 */
23
24 #include <config.h>
25
26 #include <stddef.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "sudo_compat.h"
31 #include "sudo_debug.h"
32 #include "sudo_util.h"
33
34 /* Trivial reference-counted strings. */
35 struct rcstr {
36 int refcnt;
37 char str[1]; /* actually bigger */
38 };
39
40 /*
41 * Allocate a reference-counted string and copy src to it.
42 * Returns the newly-created string with a refcnt of 1.
43 */
44 char *
sudo_rcstr_dup(const char * src)45 sudo_rcstr_dup(const char *src)
46 {
47 size_t len = strlen(src);
48 char *dst;
49 debug_decl(sudo_rcstr_dup, SUDO_DEBUG_UTIL);
50
51 dst = sudo_rcstr_alloc(len);
52 memcpy(dst, src, len);
53 dst[len] = '\0';
54 debug_return_ptr(dst);
55 }
56
57 char *
sudo_rcstr_alloc(size_t len)58 sudo_rcstr_alloc(size_t len)
59 {
60 struct rcstr *rcs;
61 debug_decl(sudo_rcstr_dup, SUDO_DEBUG_UTIL);
62
63 /* Note: sizeof(struct rcstr) includes space for the NUL */
64 rcs = malloc(sizeof(struct rcstr) + len);
65 if (rcs == NULL)
66 return NULL;
67
68 rcs->refcnt = 1;
69 rcs->str[0] = '\0';
70 /* cppcheck-suppress memleak */
71 debug_return_ptr(rcs->str); // -V773
72 }
73
74 char *
sudo_rcstr_addref(const char * s)75 sudo_rcstr_addref(const char *s)
76 {
77 struct rcstr *rcs;
78 debug_decl(sudo_rcstr_dup, SUDO_DEBUG_UTIL);
79
80 if (s == NULL)
81 debug_return_ptr(NULL);
82
83 rcs = __containerof((const void *)s, struct rcstr, str);
84 rcs->refcnt++;
85 debug_return_ptr(rcs->str);
86 }
87
88 void
sudo_rcstr_delref(const char * s)89 sudo_rcstr_delref(const char *s)
90 {
91 struct rcstr *rcs;
92 debug_decl(sudo_rcstr_dup, SUDO_DEBUG_UTIL);
93
94 if (s != NULL) {
95 rcs = __containerof((const void *)s, struct rcstr, str);
96 if (--rcs->refcnt == 0) {
97 rcs->str[0] = '\0';
98 free(rcs);
99 }
100 }
101 debug_return;
102 }
103