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

systemd / systemd / 13467361532

22 Feb 2025 12:05AM UTC coverage: 71.803% (+0.1%) from 71.665%
13467361532

push

github

DaanDeMeyer
sbsign: Don't set bit in SpcPeImageData->flags

Neither sbsign nor pesign set this flag in SpcPeImageData->flags,
which is about which resources should be included specifying "Which
portions of the Windows PE file are hashed." according to the
authenticode spec. However, this is followed by "Although flags is
always present, it is ignored when calculating the file hash for both
signing and verification purposes". So as it doesn't seem to do
anything useful and the other tools don't set any of these flags
either, let's follow suite and not set this flag ourselves either.

294198 of 409731 relevant lines covered (71.8%)

717663.79 hits per line

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

95.53
/src/basic/utf8.c
1
/* SPDX-License-Identifier: LGPL-2.0-or-later */
2

3
/* Parts of this file are based on the GLIB utf8 validation functions. The original copyright follows.
4
 *
5
 * gutf8.c - Operations on UTF-8 strings.
6
 * Copyright (C) 1999 Tom Tromey
7
 * Copyright (C) 2000 Red Hat, Inc.
8
 */
9

10
#include <errno.h>
11
#include <stdbool.h>
12
#include <stdlib.h>
13

14
#include "alloc-util.h"
15
#include "gunicode.h"
16
#include "hexdecoct.h"
17
#include "macro.h"
18
#include "string-util.h"
19
#include "utf8.h"
20

21
bool unichar_is_valid(char32_t ch) {
72,180✔
22

23
        if (ch >= 0x110000) /* End of unicode space */
72,180✔
24
                return false;
25
        if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */
72,180✔
26
                return false;
27
        if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */
72,180✔
28
                return false;
29
        if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */
72,180✔
30
                return false;
6✔
31

32
        return true;
33
}
34

35
static bool unichar_is_control(char32_t ch) {
96,186,262✔
36

37
        /*
38
          0 to ' '-1 is the C0 range.
39
          DEL=0x7F, and DEL+1 to 0x9F is C1 range.
40
          '\t' is in C0 range, but more or less harmless and commonly used.
41
        */
42

43
        return (ch < ' ' && !IN_SET(ch, '\t', '\n')) ||
96,186,262✔
44
                (0x7F <= ch && ch <= 0x9F);
96,186,090✔
45
}
46

47
/* count of characters used to encode one unicode char */
48
static size_t utf8_encoded_expected_len(uint8_t c) {
624,898,293✔
49
        if (c < 0x80)
624,898,293✔
50
                return 1;
51
        if ((c & 0xe0) == 0xc0)
236,049✔
52
                return 2;
53
        if ((c & 0xf0) == 0xe0)
209,810✔
54
                return 3;
55
        if ((c & 0xf8) == 0xf0)
959✔
56
                return 4;
57
        if ((c & 0xfc) == 0xf8)
64✔
58
                return 5;
59
        if ((c & 0xfe) == 0xfc)
64✔
60
                return 6;
×
61

62
        return 0;
63
}
64

65
/* decode one unicode char */
66
int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
101,544,513✔
67
        char32_t unichar;
101,544,513✔
68
        size_t len;
101,544,513✔
69

70
        assert(str);
101,544,513✔
71

72
        len = utf8_encoded_expected_len(str[0]);
101,544,513✔
73

74
        switch (len) {
101,544,513✔
75
        case 1:
101,381,903✔
76
                *ret_unichar = (char32_t)str[0];
101,381,903✔
77
                return 1;
101,381,903✔
78
        case 2:
21,814✔
79
                unichar = str[0] & 0x1f;
21,814✔
80
                break;
21,814✔
81
        case 3:
140,258✔
82
                unichar = (char32_t)str[0] & 0x0f;
140,258✔
83
                break;
140,258✔
84
        case 4:
538✔
85
                unichar = (char32_t)str[0] & 0x07;
538✔
86
                break;
538✔
87
        case 5:
×
88
                unichar = (char32_t)str[0] & 0x03;
×
89
                break;
×
90
        case 6:
×
91
                unichar = (char32_t)str[0] & 0x01;
×
92
                break;
×
93
        default:
94
                return -EINVAL;
95
        }
96

97
        for (size_t i = 1; i < len; i++) {
466,546✔
98
                if (((char32_t)str[i] & 0xc0) != 0x80)
303,942✔
99
                        return -EINVAL;
100

101
                unichar <<= 6;
303,936✔
102
                unichar |= (char32_t)str[i] & 0x3f;
303,936✔
103
        }
104

105
        *ret_unichar = unichar;
162,604✔
106
        return len;
162,604✔
107
}
108

109
bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) {
3,176,601✔
110
        assert(str);
3,176,601✔
111

112
        for (const char *p = str; length > 0;) {
99,362,691✔
113
                int encoded_len;
96,186,263✔
114
                char32_t val;
96,186,263✔
115

116
                encoded_len = utf8_encoded_valid_unichar(p, length);
96,186,263✔
117
                if (encoded_len < 0)
96,186,263✔
118
                        return false;
173✔
119
                assert(encoded_len > 0 && (size_t) encoded_len <= length);
96,186,262✔
120

121
                if (utf8_encoded_to_unichar(p, &val) < 0 ||
96,186,262✔
122
                    unichar_is_control(val) ||
96,186,262✔
123
                    (!allow_newline && val == '\n'))
21,148,407✔
124
                        return false;
125

126
                length -= encoded_len;
96,186,090✔
127
                p += encoded_len;
96,186,090✔
128
        }
129

130
        return true;
131
}
132

133
char* utf8_is_valid_n(const char *str, size_t len_bytes) {
24,842,884✔
134
        /* Check if the string is composed of valid utf8 characters. If length len_bytes is given, stop after
135
         * len_bytes. Otherwise, stop at NUL. */
136

137
        assert(str);
24,842,884✔
138

139
        for (size_t i = 0; len_bytes != SIZE_MAX ? i < len_bytes : str[i] != '\0'; ) {
430,919,545✔
140
                int len;
406,077,790✔
141

142
                if (_unlikely_(str[i] == '\0'))
406,077,790✔
143
                        return NULL; /* embedded NUL */
144

145
                len = utf8_encoded_valid_unichar(str + i,
406,077,787✔
146
                                                 len_bytes != SIZE_MAX ? len_bytes - i : SIZE_MAX);
147
                if (_unlikely_(len < 0))
406,077,787✔
148
                        return NULL; /* invalid character */
149

150
                i += len;
406,076,661✔
151
        }
152

153
        return (char*) str;
154
}
155

156
char* utf8_escape_invalid(const char *str) {
3,184✔
157
        char *p, *s;
3,184✔
158

159
        assert(str);
3,184✔
160

161
        p = s = malloc(strlen(str) * 4 + 1);
3,184✔
162
        if (!p)
3,184✔
163
                return NULL;
164

165
        while (*str) {
71,650✔
166
                int len;
68,466✔
167

168
                len = utf8_encoded_valid_unichar(str, SIZE_MAX);
68,466✔
169
                if (len > 0) {
68,466✔
170
                        s = mempcpy(s, str, len);
68,450✔
171
                        str += len;
68,450✔
172
                } else {
173
                        s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER);
16✔
174
                        str += 1;
16✔
175
                }
176
        }
177

178
        *s = '\0';
3,184✔
179
        return str_realloc(p);
3,184✔
180
}
181

182
int utf8_char_console_width(const char *str) {
4,042,531✔
183
        char32_t c;
4,042,531✔
184
        int r;
4,042,531✔
185

186
        r = utf8_encoded_to_unichar(str, &c);
4,042,531✔
187
        if (r < 0)
4,042,531✔
188
                return r;
4,042,531✔
189

190
        if (c == '\t')
4,042,530✔
191
                return 8; /* Assume a tab width of 8 */
192

193
        /* TODO: we should detect combining characters */
194

195
        return unichar_iswide(c) ? 2 : 1;
4,034,124✔
196
}
197

198
char* utf8_escape_non_printable_full(const char *str, size_t console_width, bool force_ellipsis) {
521✔
199
        char *p, *s, *prev_s;
521✔
200
        size_t n = 0; /* estimated print width */
521✔
201

202
        assert(str);
521✔
203

204
        if (console_width == 0)
521✔
205
                return strdup("");
9✔
206

207
        p = s = prev_s = malloc(strlen(str) * 4 + 1);
512✔
208
        if (!p)
512✔
209
                return NULL;
210

211
        for (;;) {
19,575✔
212
                int len;
19,575✔
213
                char *saved_s = s;
19,575✔
214

215
                if (!*str) { /* done! */
19,575✔
216
                        if (force_ellipsis)
438✔
217
                                goto truncation;
73✔
218
                        else
219
                                goto finish;
365✔
220
                }
221

222
                len = utf8_encoded_valid_unichar(str, SIZE_MAX);
19,137✔
223
                if (len > 0) {
19,137✔
224
                        if (utf8_is_printable(str, len)) {
19,041✔
225
                                int w;
18,878✔
226

227
                                w = utf8_char_console_width(str);
18,878✔
228
                                assert(w >= 0);
18,878✔
229
                                if (n + w > console_width)
18,878✔
230
                                        goto truncation;
34✔
231

232
                                s = mempcpy(s, str, len);
18,844✔
233
                                str += len;
18,844✔
234
                                n += w;
18,844✔
235

236
                        } else {
237
                                for (; len > 0; len--) {
288✔
238
                                        if (n + 4 > console_width)
163✔
239
                                                goto truncation;
38✔
240

241
                                        *(s++) = '\\';
125✔
242
                                        *(s++) = 'x';
125✔
243
                                        *(s++) = hexchar((int) *str >> 4);
125✔
244
                                        *(s++) = hexchar((int) *str);
125✔
245

246
                                        str += 1;
125✔
247
                                        n += 4;
125✔
248
                                }
249
                        }
250
                } else {
251
                        if (n + 1 > console_width)
96✔
252
                                goto truncation;
2✔
253

254
                        s = mempcpy(s, UTF8_REPLACEMENT_CHARACTER, strlen(UTF8_REPLACEMENT_CHARACTER));
94✔
255
                        str += 1;
94✔
256
                        n += 1;
94✔
257
                }
258

259
                prev_s = saved_s;
260
        }
261

262
 truncation:
147✔
263
        /* Try to go back one if we don't have enough space for the ellipsis */
264
        if (n + 1 > console_width)
147✔
265
                s = prev_s;
88✔
266

267
        s = mempcpy(s, "…", strlen("…"));
147✔
268

269
 finish:
512✔
270
        *s = '\0';
512✔
271
        return str_realloc(p);
512✔
272
}
273

274
char* ascii_is_valid_n(const char *str, size_t len) {
59,039✔
275
        /* Check whether the string consists of valid ASCII bytes, i.e values between 1 and 127, inclusive.
276
         * Stops at len, or NUL byte if len is SIZE_MAX. */
277

278
        assert(str);
59,039✔
279

280
        for (size_t i = 0; len != SIZE_MAX ? i < len : str[i] != '\0'; i++)
1,500,123✔
281
                if ((unsigned char) str[i] >= 128 || str[i] == '\0')
1,443,719✔
282
                        return NULL;
283

284
        return (char*) str;
285
}
286

287
int utf8_to_ascii(const char *str, char replacement_char, char **ret) {
28✔
288
        /* Convert to a string that has only ASCII chars, replacing anything that is not ASCII
289
         * by replacement_char. */
290

291
        _cleanup_free_ char *ans = new(char, strlen(str) + 1);
56✔
292
        if (!ans)
28✔
293
                return -ENOMEM;
294

295
        char *q = ans;
296

297
        for (const char *p = str; *p; q++) {
182✔
298
                int l;
156✔
299

300
                l = utf8_encoded_valid_unichar(p, SIZE_MAX);
156✔
301
                if (l < 0)  /* Non-UTF-8, let's not even try to propagate the garbage */
156✔
302
                        return l;
303

304
                if (l == 1)
154✔
305
                        *q = *p;
137✔
306
                else
307
                        /* non-ASCII, we need to replace it */
308
                        *q = replacement_char;
17✔
309

310
                p += l;
154✔
311
        }
312
        *q = '\0';
26✔
313

314
        *ret = TAKE_PTR(ans);
26✔
315
        return 0;
26✔
316
}
317

318
/**
319
 * utf8_encode_unichar() - Encode single UCS-4 character as UTF-8
320
 * @out_utf8: output buffer of at least 4 bytes or NULL
321
 * @g: UCS-4 character to encode
322
 *
323
 * This encodes a single UCS-4 character as UTF-8 and writes it into @out_utf8.
324
 * The length of the character is returned. It is not zero-terminated! If the
325
 * output buffer is NULL, only the length is returned.
326
 *
327
 * Returns: The length in bytes that the UTF-8 representation does or would
328
 *          occupy.
329
 */
330
size_t utf8_encode_unichar(char *out_utf8, char32_t g) {
68,416✔
331

332
        if (g < (1 << 7)) {
68,416✔
333
                if (out_utf8)
68,292✔
334
                        out_utf8[0] = g & 0x7f;
68,292✔
335
                return 1;
68,292✔
336
        } else if (g < (1 << 11)) {
124✔
337
                if (out_utf8) {
17✔
338
                        out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f);
17✔
339
                        out_utf8[1] = 0x80 | (g & 0x3f);
17✔
340
                }
341
                return 2;
17✔
342
        } else if (g < (1 << 16)) {
107✔
343
                if (out_utf8) {
96✔
344
                        out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f);
96✔
345
                        out_utf8[1] = 0x80 | ((g >> 6) & 0x3f);
96✔
346
                        out_utf8[2] = 0x80 | (g & 0x3f);
96✔
347
                }
348
                return 3;
96✔
349
        } else if (g < (1 << 21)) {
11✔
350
                if (out_utf8) {
11✔
351
                        out_utf8[0] = 0xf0 | ((g >> 18) & 0x07);
11✔
352
                        out_utf8[1] = 0x80 | ((g >> 12) & 0x3f);
11✔
353
                        out_utf8[2] = 0x80 | ((g >> 6) & 0x3f);
11✔
354
                        out_utf8[3] = 0x80 | (g & 0x3f);
11✔
355
                }
356
                return 4;
11✔
357
        }
358

359
        return 0;
360
}
361

362
char* utf16_to_utf8(const char16_t *s, size_t length /* bytes! */) {
1,933✔
363
        const uint8_t *f;
1,933✔
364
        char *r, *t;
1,933✔
365

366
        if (length == 0)
1,933✔
367
                return new0(char, 1);
×
368

369
        assert(s);
1,933✔
370

371
        if (length == SIZE_MAX) {
1,933✔
372
                length = char16_strlen(s);
6✔
373

374
                if (length > SIZE_MAX/2)
6✔
375
                        return NULL; /* overflow */
376

377
                length *= 2;
6✔
378
        }
379

380
        /* Input length is in bytes, i.e. the shortest possible character takes 2 bytes. Each unicode character may
381
         * take up to 4 bytes in UTF-8. Let's also account for a trailing NUL byte. */
382
        if (length > (SIZE_MAX - 1) / 2)
1,933✔
383
                return NULL; /* overflow */
384

385
        r = new(char, length * 2 + 1);
1,933✔
386
        if (!r)
1,933✔
387
                return NULL;
388

389
        f = (const uint8_t*) s;
390
        t = r;
391

392
        while (f + 1 < (const uint8_t*) s + length) {
70,160✔
393
                char16_t w1, w2;
68,227✔
394

395
                /* see RFC 2781 section 2.2 */
396

397
                w1 = f[1] << 8 | f[0];
68,227✔
398
                f += 2;
68,227✔
399

400
                if (!utf16_is_surrogate(w1)) {
68,227✔
401
                        t += utf8_encode_unichar(t, w1);
68,220✔
402
                        continue;
68,220✔
403
                }
404

405
                if (utf16_is_trailing_surrogate(w1))
7✔
406
                        continue; /* spurious trailing surrogate, ignore */
1✔
407

408
                if (f + 1 >= (const uint8_t*) s + length)
6✔
409
                        break;
410

411
                w2 = f[1] << 8 | f[0];
6✔
412
                f += 2;
6✔
413

414
                if (!utf16_is_trailing_surrogate(w2)) {
6✔
415
                        f -= 2;
1✔
416
                        continue; /* surrogate missing its trailing surrogate, ignore */
1✔
417
                }
418

419
                t += utf8_encode_unichar(t, utf16_surrogate_pair_to_unichar(w1, w2));
5✔
420
        }
421

422
        *t = 0;
1,933✔
423
        return r;
1,933✔
424
}
425

426
size_t utf16_encode_unichar(char16_t *out, char32_t c) {
16✔
427

428
        /* Note that this encodes as little-endian. */
429

430
        switch (c) {
16✔
431

432
        case 0 ... 0xd7ffU:
12✔
433
        case 0xe000U ... 0xffffU:
434
                out[0] = htole16(c);
12✔
435
                return 1;
12✔
436

437
        case 0x10000U ... 0x10ffffU:
4✔
438
                c -= 0x10000U;
4✔
439
                out[0] = htole16((c >> 10) + 0xd800U);
4✔
440
                out[1] = htole16((c & 0x3ffU) + 0xdc00U);
4✔
441
                return 2;
4✔
442

443
        default: /* A surrogate (invalid) */
444
                return 0;
445
        }
446
}
447

448
char16_t *utf8_to_utf16(const char *s, size_t length) {
108✔
449
        char16_t *n, *p;
108✔
450
        int r;
108✔
451

452
        if (length == 0)
108✔
453
                return new0(char16_t, 1);
×
454

455
        assert(s);
108✔
456

457
        if (length == SIZE_MAX)
108✔
458
                length = strlen(s);
107✔
459

460
        if (length > SIZE_MAX - 1)
107✔
461
                return NULL; /* overflow */
462

463
        n = new(char16_t, length + 1);
108✔
464
        if (!n)
108✔
465
                return NULL;
466

467
        p = n;
468

469
        for (size_t i = 0; i < length;) {
1,144✔
470
                char32_t unichar;
1,036✔
471
                size_t e;
1,036✔
472

473
                e = utf8_encoded_expected_len(s[i]);
1,036✔
474
                if (e <= 1) /* Invalid and single byte characters are copied as they are */
1,036✔
475
                        goto copy;
1,020✔
476

477
                if (i + e > length) /* sequence longer than input buffer, then copy as-is */
16✔
478
                        goto copy;
×
479

480
                r = utf8_encoded_to_unichar(s + i, &unichar);
16✔
481
                if (r < 0) /* sequence invalid, then copy as-is */
16✔
482
                        goto copy;
×
483

484
                p += utf16_encode_unichar(p, unichar);
16✔
485
                i += e;
16✔
486
                continue;
16✔
487

488
        copy:
1,020✔
489
                *(p++) = htole16(s[i++]);
1,020✔
490
        }
491

492
        *p = 0;
108✔
493
        return n;
108✔
494
}
495

496
size_t char16_strlen(const char16_t *s) {
334✔
497
        size_t n = 0;
334✔
498

499
        assert(s);
334✔
500

501
        while (*s != 0)
4,107✔
502
                n++, s++;
3,773✔
503

504
        return n;
334✔
505
}
506

507
size_t char16_strsize(const char16_t *s) {
3✔
508
        return s ? (char16_strlen(s) + 1) * sizeof(*s) : 0;
3✔
509
}
510

511
/* expected size used to encode one unicode char */
512
static int utf8_unichar_to_encoded_len(char32_t unichar) {
72,170✔
513

514
        if (unichar < 0x80)
72,170✔
515
                return 1;
516
        if (unichar < 0x800)
72,170✔
517
                return 2;
518
        if (unichar < 0x10000)
68,072✔
519
                return 3;
520
        if (unichar < 0x200000)
351✔
521
                return 4;
522
        if (unichar < 0x4000000)
×
523
                return 5;
×
524

525
        return 6;
526
}
527

528
/* validate one encoded unicode char and return its length */
529
int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) {
523,352,744✔
530
        char32_t unichar;
523,352,744✔
531
        size_t len;
523,352,744✔
532
        int r;
523,352,744✔
533

534
        assert(str);
523,352,744✔
535
        assert(length > 0);
523,352,744✔
536

537
        /* We read until NUL, at most length bytes. SIZE_MAX may be used to disable the length check. */
538

539
        len = utf8_encoded_expected_len(str[0]);
523,352,744✔
540
        if (len == 0)
523,352,744✔
541
                return -EINVAL;
523,352,744✔
542

543
        /* Do we have a truncated multi-byte character? */
544
        if (len > length)
523,352,680✔
545
                return -EINVAL;
546

547
        /* ascii is valid */
548
        if (len == 1)
523,352,672✔
549
                return 1;
550

551
        /* check if expected encoded chars are available */
552
        for (size_t i = 0; i < len; i++)
287,759✔
553
                if ((str[i] & 0x80) != 0x80)
215,584✔
554
                        return -EINVAL;
555

556
        r = utf8_encoded_to_unichar(str, &unichar);
72,175✔
557
        if (r < 0)
72,175✔
558
                return r;
559

560
        /* check if encoded length matches encoded value */
561
        if (utf8_unichar_to_encoded_len(unichar) != (int) len)
72,170✔
562
                return -EINVAL;
563

564
        /* check if value has valid range */
565
        if (!unichar_is_valid(unichar))
72,170✔
566
                return -EINVAL;
6✔
567

568
        return (int) len;
569
}
570

571
size_t utf8_n_codepoints(const char *str) {
6✔
572
        size_t n = 0;
6✔
573

574
        /* Returns the number of UTF-8 codepoints in this string, or SIZE_MAX if the string is not valid UTF-8. */
575

576
        while (*str != 0) {
34✔
577
                int k;
29✔
578

579
                k = utf8_encoded_valid_unichar(str, SIZE_MAX);
29✔
580
                if (k < 0)
29✔
581
                        return SIZE_MAX;
582

583
                str += k;
28✔
584
                n++;
28✔
585
        }
586

587
        return n;
588
}
589

590
size_t utf8_console_width(const char *str) {
273,921✔
591

592
        if (isempty(str))
273,921✔
593
                return 0;
594

595
        /* Returns the approximate width a string will take on screen when printed on a character cell
596
         * terminal/console. */
597

598
        size_t n = 0;
599
        while (*str) {
3,790,613✔
600
                int w;
3,528,394✔
601

602
                w = utf8_char_console_width(str);
3,528,394✔
603
                if (w < 0)
3,528,394✔
604
                        return SIZE_MAX;
605

606
                n += w;
3,528,393✔
607
                str = utf8_next_char(str);
3,528,393✔
608
        }
609

610
        return n;
611
}
612

613
size_t utf8_last_length(const char *s, size_t n) {
9✔
614
        int r;
9✔
615

616
        assert(s);
9✔
617

618
        if (n == SIZE_MAX)
9✔
619
                n = strlen(s);
7✔
620

621
        /* Determines length in bytes of last UTF-8 codepoint in string. If the string is empty, returns
622
         * zero. Treats invalid UTF-8 codepoints as 1 sized ones. */
623

624
        for (size_t last = 0;;) {
19✔
625
                if (n == 0)
28✔
626
                        return last;
9✔
627

628
                r = utf8_encoded_valid_unichar(s, n);
19✔
629
                if (r <= 0)
19✔
630
                        r = 1; /* treat invalid UTF-8 as byte-wide */
×
631

632
                s += r;
19✔
633
                n -= r;
19✔
634
                last = r;
19✔
635
        }
636
}
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