GCC Code Coverage Report


Directory: ../replacer/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 87.2% 190 / 0 / 218
Functions: 100.0% 16 / 0 / 16
Branches: 73.5% 100 / 0 / 136

stringfunc.c
Line Branch Exec Source
1 /*
2 * stringfunc.c
3 *
4 * Created on: Sep 3, 2018
5 * Author: alexey
6 */
7
8 #define _XOPEN_SOURCE 700
9 /* is required for realpath()
10 * and implies
11 * #define _POSIX_C_SOURCE 200809L
12 */
13
14 #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__clang__)
15 #define GCC_DIAGNOSTIC_AWARE 1
16 #else
17 #define GCC_DIAGNOSTIC_AWARE 0
18 #endif
19
20 #include <libgen.h>
21 #include <stdbool.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <stdint.h>
27 #include <ctype.h>
28
29 #include <limits.h>
30 #include <errno.h>
31 #include <sys/stat.h>
32
33 /* for mincore(2) */
34 #define __USE_MISC 1
35 #include <sys/mman.h>
36
37 #include <openssl/md5.h>
38 #include <openssl/sha.h>
39 #include <inttypes.h>
40
41 #ifdef UNIT_TESTING
42 #define STRINGFUNC_NOINLINE
43 #endif
44 #include "stringfunc.h"
45
46 #include "unit_test_common.h"
47
48 524 char *i360_my_strtrim(char const *string) {
49 char *trim;
50 524 int i = 0;
51 524 int len = strlen(string);
52
53
3/4
✓ Branch 1 taken 80 times.
✓ Branch 2 taken 524 times.
✓ Branch 3 taken 80 times.
✗ Branch 4 not taken.
604 while(isspace(string[i]) && len) {
54 80 ++ i;
55 80 -- len;
56 }
57
3/4
✓ Branch 1 taken 284 times.
✓ Branch 2 taken 524 times.
✓ Branch 3 taken 284 times.
✗ Branch 4 not taken.
808 while(isspace(string[len + i - 1]) && len) {
58 284 -- len;
59 }
60 524 trim = malloc(len+1); // Consider \0 byte
61
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 524 times.
524 if (!trim)
62 return NULL;
63 524 memcpy(trim, &string[i], len); // Consider \0 byte
64 524 trim[len] = '\0';
65 524 return trim;
66 }
67
68 inline
69 3 static void i360_swap(char *a, char *b) {
70 3 char temp = *a;
71 3 *a = *b;
72 3 *b = temp;
73 3 }
74
75 inline
76 3 static void i360_reverse(char str[], int length) {
77 3 int start = 0;
78 3 int end = length - 1;
79
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 while (start < end) {
80 3 i360_swap((str + start), (str + end));
81 3 start++;
82 3 end--;
83 }
84 3 }
85
86 3 int i360_itoa(int num, char *str, int base) {
87 3 int i = 0;
88
89
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
3 if (num == 0 || num < 0) {
90 2 str[i++] = '0';
91 2 str[i] = '\0';
92 2 return i;
93 }
94
95
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 while (num != 0) {
96 3 int rem = num % base;
97
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0';
98 3 num = num / base;
99 }
100 1 str[i] = '\0';
101 1 i360_reverse(str, i);
102
103 1 return i;
104 }
105
106 3 int i360_ltoa(long num, char *str, long base) {
107 3 int i = 0;
108
109
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
3 if (num == 0 || num < 0) {
110 2 str[i++] = '0';
111 2 str[i] = '\0';
112 2 return i;
113 }
114
115
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 while (num != 0) {
116 3 long rem = num % base;
117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0';
118 3 num = num / base;
119 }
120 1 str[i] = '\0';
121 1 i360_reverse(str, i);
122
123 1 return i;
124 }
125
126 3 int i360_lltoa(long long num, char *str, long base) {
127 3 int i = 0;
128
129
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
3 if (num == 0 || num < 0) {
130 2 str[i++] = '0';
131 2 str[i] = '\0';
132 2 return i;
133 }
134
135
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 while (num != 0) {
136 3 long long rem = num % base;
137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0';
138 3 num = num / base;
139 }
140 1 str[i] = '\0';
141 1 i360_reverse(str, i);
142
143 1 return i;
144 }
145
146 static
147 45 char *i360_resolve_path(const char *path, char *result) {
148 45 char *pos = result;
149 45 long left = PATH_MAX;
150
3/4
✓ Branch 0 taken 759 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 759 times.
✗ Branch 3 not taken.
804 for (; *path && (left --); ++ path, ++ pos) {
151
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 625 times.
759 if (path[0] == '/') {
152
4/4
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 127 times.
134 if (path[1] == '/' || // Double slash
153
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 (path[1] == '\0' && pos > result)) { // Slash in the end of string, but not the start of the string
154 6 -- pos;
155 6 ++ left;
156 6 continue;
157 }
158
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 111 times.
128 if (path[1] == '.') {
159
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 11 times.
17 if (path[2] == '/') {
160 6 ++ path;
161 6 -- pos;
162 6 ++ left;
163 6 continue;
164 }
165
3/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 3 times.
11 if (path[2] == '.' && path [3] == '/') {
166 8 path += 2;
167 8 *pos = '\0';
168
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 1 time.
47 while (pos >= result) {
169
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 39 times.
46 if (*pos == '/') {
170 7 -- pos;
171 7 ++ left;
172 7 break;
173 }
174 39 ++ left;
175 39 -- pos;
176 }
177 8 continue;
178 }
179 }
180 }
181 739 *pos = *path;
182 }
183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
45 if (!left) {
184 return NULL;
185 }
186 45 *pos = '\0';
187 45 return result;
188 }
189
190 28 char *i360_realpath_local(const char *path_param, char *cwd_param, char *resolved_path, int path_len) {
191 char path_copy[PATH_MAX], full_path[PATH_MAX];
192
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 17 times.
28 if (*path_param == '/') {
193 // absolute path
194
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 if (i360_resolve_path(path_param, path_copy)) {
195 11 strncpy(resolved_path, path_copy, path_len - 1);
196 }
197 else {
198 strncpy(resolved_path, path_param, path_len - 1);
199 }
200 11 return resolved_path;
201 }
202
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
17 if (!i360_resolve_path(cwd_param, full_path)) {
203 return NULL;
204 }
205 17 int cwd_param_len = strlen(full_path);
206 17 int full_size = sizeof(full_path) - cwd_param_len;
207
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 time.
17 if (full_path[0]) {
208 16 strncat(full_path, "/", full_size);
209 16 full_size --;
210 }
211 17 strncat(full_path, path_param, full_size);
212
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 if (i360_resolve_path(full_path, path_copy)) {
213 17 strncpy(resolved_path, path_copy, path_len - 1);
214 17 return resolved_path;
215 }
216 28 return NULL;
217 }
218
219 4 void i360_make_sha256_ex(const char *src, size_t src_len, char *dst) {
220 size_t i;
221 4 size_t len = SHA256_DIGEST_LENGTH;
222 unsigned char sha256digest[SHA256_DIGEST_LENGTH];
223 4 SHA256((const unsigned char *)src, src_len, sha256digest);
224
225
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 4 times.
132 for (i = 0; i < len; i++) {
226 unsigned char c;
227
228 128 c = (sha256digest[i] >> 4) & 0xF;
229
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 53 times.
128 dst[i << 1] = c + ((c < 10) ? '0' : ('a' - 10));
230
231 128 c = sha256digest[i] & 0xF;
232
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 47 times.
128 dst[(i << 1) + 1] = c + ((c < 10) ? '0' : ('a' - 10));
233 }
234 4 }
235
236 4 static void i360_get_sha256(const char *src, char *dst) {
237 4 size_t len = SHA256_DIGEST_LENGTH;
238 4 i360_make_sha256_ex(src, strlen(src), dst);
239 4 dst[len << 1] = '\0';
240 4 }
241
242 8 int i360_translate_to_real_path(const char *param, char *cur_php_fname_dir, char *file_name, int len) {
243 char absolute_path[PATH_MAX];
244
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if (!i360_realpath_local(param, cur_php_fname_dir, file_name, len))
245 return 1;
246 8 char *result = realpath(file_name, absolute_path);
247
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (!result)
248 6 return 1;
249 2 strncpy(file_name, result, len);
250 8 return 0;
251 }
252
253 4 int i360_check_if_file_marked_as_danger(char *path_to_file, char *script_executed, int path_to_cfgdirectory_fd) {
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (path_to_cfgdirectory_fd < 0)
255 return 0;
256 4 char cwd[PATH_MAX] = {0};
257 struct stat buf;
258 int rc, len;
259 4 char link_path[PATH_MAX] = "";
260 4 char script_fname_dir[PATH_MAX] = "";
261 4 strncpy(cwd, script_executed, PATH_MAX - 1);
262 4 char *dn = dirname(cwd);
263 4 size_t dn_len = strlen(dn);
264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (dn != cwd) {
265 /* using strncpy safely to avoid -Wstringop-truncation (GCC 8) */
266 memcpy(cwd, dn, dn_len + 1);
267 }
268 char result_file_name[PATH_MAX];
269
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (!i360_realpath_local(path_to_file, cwd, result_file_name, PATH_MAX)) {
270 return 0;
271 }
272
273 char config_file_name[(SHA256_DIGEST_LENGTH * 2) + 1];
274 4 i360_get_sha256(result_file_name, config_file_name);
275
276 struct stat info;
277
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 time.
4 if (fstatat(path_to_cfgdirectory_fd, config_file_name, &info, 0) == 0) {
278 3 return 1;
279 }
280 // check if file is symlink
281 1 rc = lstat(result_file_name, &buf);
282
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (-1 != rc && S_ISLNK(buf.st_mode)) {
283 if ((len = readlink(result_file_name, link_path, PATH_MAX - 1)) != -1) {
284 link_path[len] = '\0';
285 if (len > 0) {
286 if (link_path[0] == '/') {
287 i360_get_sha256(link_path, config_file_name);
288 if (fstatat(path_to_cfgdirectory_fd, config_file_name, &info, 0) == 0) {
289 return 1;
290 }
291 else {
292 return 0;
293 }
294 }
295 else {
296 strncpy(script_fname_dir, result_file_name, PATH_MAX);
297 char *last_slash = strrchr(script_fname_dir, '/');
298 if (last_slash)
299 *last_slash = 0;
300 else
301 strcpy(script_fname_dir, "/");
302 if (!i360_realpath_local(link_path, script_fname_dir, cwd, PATH_MAX))
303 return 0;
304 i360_get_sha256(cwd, config_file_name);
305 if (fstatat(path_to_cfgdirectory_fd, config_file_name, &info, 0) == 0) {
306 return 1;
307 }
308 else {
309 return 0;
310 }
311 }
312 }
313 }
314 }
315 4 return 0;
316 }
317
318 /**
319 * i360_strnadd - strncat alternative that is more adaptive than strncpy
320 * as for performance
321 * @srclen: Length of the src string
322 * @buflen: Buffer length
323 * @bufleft: Buffer capacity (shrinks by min(strlen, bufleft) on each iteration)
324 */
325 5 void i360_strnadd(char *dest, const char *src, size_t srclen, size_t buflen, size_t *buf_left) {
326 5 size_t cpylen = srclen < *buf_left ? srclen : *buf_left;
327
328 5 memcpy(dest + buflen - *buf_left, src, cpylen);
329 5 *buf_left -= cpylen;
330
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 if (*buf_left) {
331 // keep close to strncpy behavior
332 3 dest[buflen - *buf_left] = '\0';
333 }
334 5 }
335
336 6 int i360_is_valid_ptr(const void *ptr) {
337 static long int page_size = 0;
338 static uintptr_t page_mask = 0;
339 static uintptr_t page_seen_min = UINTPTR_MAX;
340 static uintptr_t page_seen_max = 0;
341
342 int ret;
343 6 char vec = 0;
344
345
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 5 times.
6 if (!page_size) {
346 1 page_size = sysconf(_SC_PAGESIZE);
347 1 page_mask = ~((uintptr_t)page_size - 1);
348 }
349
350 6 uintptr_t page = ((uintptr_t)ptr) & page_mask;
351
352
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 5 times.
6 if (!page)
353 1 return 0;
354
355
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 2 times.
5 if (page >= page_seen_min && page <= page_seen_max)
356 1 return 1;
357
358 again:
359 4 ret = mincore((void *)page, page_size, (unsigned char *)&vec);
360
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 if (ret) {
361
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (errno == EAGAIN)
362 goto again;
363
364 3 return 0;
365 }
366
367
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (page < page_seen_min)
368 1 page_seen_min = page;
369
370
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (page > page_seen_max)
371 1 page_seen_max = page;
372
373 6 return 1;
374 }
375
376 4 size_t i360_hex(uint64_t val, char *buffer) {
377 static const char *hex_array_translate = "0123456789abcdef";
378
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 int counter = val ? ((64 - __builtin_clzll(val) + 3) / 4) * 4 : 0;
379 4 size_t l = counter / 4;
380
381
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 4 times.
31 while (counter) {
382 27 counter -= 4;
383 27 uint64_t h = (val >> counter) & 0xF;
384 27 *buffer++ = hex_array_translate[h];
385 }
386 4 *buffer = 0;
387 4 return l;
388 }
389
390 8 int i360_has_prefix(char *str, char *substr)
391 {
392
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 6 times.
8 if (str == NULL || substr == NULL)
393 2 return -1;
394
395
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (strncmp(str, substr, strlen(substr)) == 0)
396 4 return 1;
397
398 2 return 0;
399 }
400