Changeset 29e7cc7 in mainline for uspace/lib/c
- Timestamp:
- 2025-04-18T15:14:10Z (8 months ago)
- Children:
- e77c3ed
- Parents:
- 800d188 (diff), 25fdb2d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Location:
- uspace/lib/c
- Files:
-
- 1 added
- 2 deleted
- 13 edited
-
arch/arm32/src/atomic.c (modified) (2 diffs)
-
generic/async/ports.c (modified) (3 diffs)
-
generic/async/server.c (modified) (2 diffs)
-
generic/io/asprintf.c (modified) (2 diffs)
-
generic/io/kio.c (modified) (4 diffs)
-
generic/io/vprintf.c (modified) (2 diffs)
-
generic/io/vsnprintf.c (deleted)
-
include/io/kio.h (modified) (2 diffs)
-
include/stdio.h (modified) (1 diff)
-
include/types/adt/odict.h (deleted)
-
meson.build (modified) (4 diffs)
-
test/adt/odict.c (modified) (1 diff)
-
test/main.c (modified) (1 diff)
-
test/sprintf.c (modified) (4 diffs)
-
test/str.c (modified) (3 diffs)
-
test/uchar.c (added)
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/arch/arm32/src/atomic.c
r800d188 r29e7cc7 38 38 volatile unsigned *ras_page; 39 39 40 bool __atomic_compare_exchange_4(volatile void *mem0, void *expected0, 41 unsigned desired, bool weak, int success, int failure) 40 unsigned long long __atomic_load_8(const volatile void *mem0, int model) 41 { 42 const volatile unsigned *mem = mem0; 43 44 (void) model; 45 46 union { 47 unsigned long long a; 48 unsigned b[2]; 49 } ret; 50 51 /* 52 * The following instructions between labels 1 and 2 constitute a 53 * Restartable Atomic Seqeunce. Should the sequence be non-atomic, 54 * the kernel will restart it. 55 */ 56 asm volatile ( 57 "1:\n" 58 " adr %[ret0], 1b\n" 59 " str %[ret0], %[rp0]\n" 60 " adr %[ret0], 2f\n" 61 " str %[ret0], %[rp1]\n" 62 63 " ldr %[ret0], %[addr0]\n" 64 " ldr %[ret1], %[addr1]\n" 65 "2:\n" 66 : [ret0] "=&r" (ret.b[0]), 67 [ret1] "=&r" (ret.b[1]), 68 [rp0] "=m" (ras_page[0]), 69 [rp1] "=m" (ras_page[1]) 70 : [addr0] "m" (mem[0]), 71 [addr1] "m" (mem[1]) 72 ); 73 74 ras_page[0] = 0; 75 ras_page[1] = 0xffffffff; 76 77 return ret.a; 78 } 79 80 void __atomic_store_8(volatile void *mem0, unsigned long long val, int model) 42 81 { 43 82 volatile unsigned *mem = mem0; 44 unsigned *expected = expected0; 83 84 (void) model; 85 86 union { 87 unsigned long long a; 88 unsigned b[2]; 89 } v; 90 91 v.a = val; 92 93 /* scratch register */ 94 unsigned tmp; 95 96 /* 97 * The following instructions between labels 1 and 2 constitute a 98 * Restartable Atomic Seqeunce. Should the sequence be non-atomic, 99 * the kernel will restart it. 100 */ 101 asm volatile ( 102 "1:\n" 103 " adr %[tmp], 1b\n" 104 " str %[tmp], %[rp0]\n" 105 " adr %[tmp], 2f\n" 106 " str %[tmp], %[rp1]\n" 107 108 " str %[val0], %[addr0]\n" 109 " str %[val1], %[addr1]\n" 110 "2:\n" 111 : [tmp] "=&r" (tmp), 112 [rp0] "=m" (ras_page[0]), 113 [rp1] "=m" (ras_page[1]), 114 [addr0] "=m" (mem[0]), 115 [addr1] "=m" (mem[1]) 116 : [val0] "r" (v.b[0]), 117 [val1] "r" (v.b[1]) 118 ); 119 120 ras_page[0] = 0; 121 ras_page[1] = 0xffffffff; 122 } 123 124 bool __atomic_compare_exchange_1(volatile void *mem0, void *expected0, 125 unsigned char desired, bool weak, int success, int failure) 126 { 127 volatile unsigned char *mem = mem0; 128 unsigned char *expected = expected0; 45 129 46 130 (void) success; … … 48 132 (void) weak; 49 133 134 unsigned char ov = *expected; 135 unsigned ret; 136 137 /* 138 * The following instructions between labels 1 and 2 constitute a 139 * Restartable Atomic Sequence. Should the sequence be non-atomic, 140 * the kernel will restart it. 141 */ 142 asm volatile ( 143 "1:\n" 144 " adr %[ret], 1b\n" 145 " str %[ret], %[rp0]\n" 146 " adr %[ret], 2f\n" 147 " str %[ret], %[rp1]\n" 148 149 " ldrb %[ret], %[addr]\n" 150 " cmp %[ret], %[ov]\n" 151 " streqb %[nv], %[addr]\n" 152 "2:\n" 153 : [ret] "=&r" (ret), 154 [rp0] "=m" (ras_page[0]), 155 [rp1] "=m" (ras_page[1]), 156 [addr] "+m" (*mem) 157 : [ov] "r" (ov), 158 [nv] "r" (desired) 159 ); 160 161 ras_page[0] = 0; 162 ras_page[1] = 0xffffffff; 163 164 if (ret == ov) 165 return true; 166 167 *expected = ret; 168 return false; 169 } 170 171 bool __atomic_compare_exchange_4(volatile void *mem0, void *expected0, 172 unsigned desired, bool weak, int success, int failure) 173 { 174 volatile unsigned *mem = mem0; 175 unsigned *expected = expected0; 176 177 (void) success; 178 (void) failure; 179 (void) weak; 180 50 181 unsigned ov = *expected; 51 182 unsigned ret; -
uspace/lib/c/generic/async/ports.c
r800d188 r29e7cc7 50 50 #include <as.h> 51 51 #include <abi/mm/as.h> 52 #include "../private/libc.h"53 52 #include "../private/fibril.h" 54 53 … … 115 114 } 116 115 117 static bool interface_key_equal(const void *key, const ht_link_t *item)116 static bool interface_key_equal(const void *key, size_t hash, const ht_link_t *item) 118 117 { 119 118 const iface_t *iface = key; … … 143 142 } 144 143 145 static bool port_key_equal(const void *key, const ht_link_t *item)144 static bool port_key_equal(const void *key, size_t hash, const ht_link_t *item) 146 145 { 147 146 const port_id_t *port_id = key; -
uspace/lib/c/generic/async/server.c
r800d188 r29e7cc7 242 242 } 243 243 244 static bool client_key_equal(const void *key, const ht_link_t *item)244 static bool client_key_equal(const void *key, size_t, const ht_link_t *item) 245 245 { 246 246 const task_id_t *in_task_id = key; … … 502 502 } 503 503 504 static bool notification_key_equal(const void *key, const ht_link_t *item)504 static bool notification_key_equal(const void *key, size_t hash, const ht_link_t *item) 505 505 { 506 506 const sysarg_t *id = key; -
uspace/lib/c/generic/io/asprintf.c
r800d188 r29e7cc7 40 40 #include <str.h> 41 41 #include <printf_core.h> 42 43 static int asprintf_str_write(const char *str, size_t count, void *unused)44 {45 return str_nlength(str, count);46 }47 48 static int asprintf_wstr_write(const char32_t *str, size_t count, void *unused)49 {50 return wstr_nlength(str, count);51 }52 53 int vprintf_length(const char *fmt, va_list args)54 {55 printf_spec_t ps = {56 asprintf_str_write,57 asprintf_wstr_write,58 NULL59 };60 61 return printf_core(fmt, &ps, args);62 }63 64 int printf_length(const char *fmt, ...)65 {66 va_list args;67 va_start(args, fmt);68 int ret = vprintf_length(fmt, args);69 va_end(args);70 71 return ret;72 }73 42 74 43 /** Allocate and print to string. … … 115 84 int ret = vasprintf(strp, fmt, args); 116 85 va_end(args); 117 118 86 return ret; 119 87 } -
uspace/lib/c/generic/io/kio.c
r800d188 r29e7cc7 34 34 */ 35 35 36 #include <abi/syscall.h> 36 37 #include <stddef.h> 37 38 #include <libc.h> … … 112 113 } 113 114 115 size_t kio_read(char *buf, size_t n, size_t at) 116 { 117 return __SYSCALL3(SYS_KIO_READ, (sysarg_t) buf, n, at); 118 } 119 114 120 /** Print formatted text to kio. 115 121 * … … 131 137 } 132 138 133 static int kio_vprintf_str_write(const char *str, size_t size, void *data)139 static errno_t kio_vprintf_str_write(const char *str, size_t size, void *data) 134 140 { 135 size_t wr; 136 137 wr = 0; 138 (void) kio_write(str, size, &wr); 139 return str_nlength(str, wr); 140 } 141 142 static int kio_vprintf_wstr_write(const char32_t *str, size_t size, void *data) 143 { 144 size_t offset = 0; 145 size_t chars = 0; 146 size_t wr; 147 148 while (offset < size) { 149 char buf[STR_BOUNDS(1)]; 150 size_t sz = 0; 151 152 if (chr_encode(str[chars], buf, &sz, STR_BOUNDS(1)) == EOK) 153 kio_write(buf, sz, &wr); 154 155 chars++; 156 offset += sizeof(char32_t); 157 } 158 159 return chars; 141 size_t wr = 0; 142 return kio_write(str, size, &wr); 160 143 } 161 144 … … 172 155 printf_spec_t ps = { 173 156 kio_vprintf_str_write, 174 kio_vprintf_wstr_write,175 157 NULL 176 158 }; -
uspace/lib/c/generic/io/vprintf.c
r800d188 r29e7cc7 42 42 static FIBRIL_MUTEX_INITIALIZE(printf_mutex); 43 43 44 static int vprintf_str_write(const char *str, size_t size, void *stream)44 static errno_t vprintf_str_write(const char *str, size_t size, void *stream) 45 45 { 46 size_t wr = fwrite(str, 1, size, (FILE *) stream); 47 return str_nlength(str, wr); 48 } 46 errno_t old_errno = errno; 49 47 50 static int vprintf_wstr_write(const char32_t *str, size_t size, void *stream) 51 { 52 size_t offset = 0; 53 size_t chars = 0; 48 errno = EOK; 49 size_t written = fwrite(str, 1, size, (FILE *) stream); 54 50 55 while (offset < size) { 56 if (fputuc(str[chars], (FILE *) stream) <= 0) 57 break; 51 if (errno == EOK && written != size) 52 errno = EIO; 58 53 59 chars++; 60 offset += sizeof(char32_t); 61 } 54 if (errno != EOK) 55 return errno; 62 56 63 return chars; 57 errno = old_errno; 58 return EOK; 64 59 } 65 60 … … 77 72 printf_spec_t ps = { 78 73 vprintf_str_write, 79 vprintf_wstr_write,80 74 stream 81 75 }; -
uspace/lib/c/include/io/kio.h
r800d188 r29e7cc7 36 36 #define _LIBC_IO_KIO_H_ 37 37 38 #include <stddef.h>39 #include <stdarg.h>40 #include <io/verify.h>41 38 #include <_bits/errno.h> 42 39 #include <_bits/size_t.h> 40 #include <io/verify.h> 41 #include <stdarg.h> 42 #include <stddef.h> 43 #include <uchar.h> 43 44 44 45 extern void __kio_init(void); … … 50 51 _HELENOS_PRINTF_ATTRIBUTE(1, 2); 51 52 extern int kio_vprintf(const char *, va_list); 53 54 extern size_t kio_read(char *buf, size_t n, size_t at); 52 55 53 56 /* -
uspace/lib/c/include/stdio.h
r800d188 r29e7cc7 209 209 }; 210 210 211 extern int vprintf_length(const char *, va_list);212 extern int printf_length(const char *, ...)213 _HELENOS_PRINTF_ATTRIBUTE(1, 2);214 211 extern FILE *fdopen(int, const char *); 215 212 extern int fileno(FILE *); -
uspace/lib/c/meson.build
r800d188 r29e7cc7 62 62 'common/adt/checksum.c', 63 63 'common/adt/circ_buf.c', 64 'common/adt/hash_table.c', 64 65 'common/adt/list.c', 65 'common/adt/hash_table.c',66 66 'common/adt/odict.c', 67 'common/gsort.c', 67 68 'common/printf/printf_core.c', 69 'common/stdc/bsearch.c', 70 'common/stdc/calloc.c', 68 71 'common/stdc/ctype.c', 69 72 'common/stdc/mem.c', 70 'common/stdc/bsearch.c',71 73 'common/stdc/qsort.c', 72 'common/stdc/calloc.c', 73 'common/gsort.c', 74 'common/stdc/snprintf.c', 75 'common/stdc/uchar.c', 76 'common/stdc/vsnprintf.c', 77 'common/stdc/wchar.c', 74 78 'common/str.c', 75 79 'common/str_error.c', 76 80 'common/strtol.c', 77 81 78 'generic/libc.c',79 82 'generic/adt/prodcons.c', 83 'generic/arg_parse.c', 80 84 'generic/as.c', 81 'generic/ddi.c', 82 'generic/perm.c', 85 'generic/assert.c', 86 'generic/async/client.c', 87 'generic/async/ports.c', 88 'generic/async/server.c', 83 89 'generic/capa.c', 84 90 'generic/config.c', 85 91 'generic/context.c', 86 92 'generic/dbgcon.c', 93 'generic/ddi.c', 87 94 'generic/device/clock_dev.c', 88 95 'generic/device/hw_res.c', … … 91 98 'generic/dirent.c', 92 99 'generic/dlfcn.c', 100 'generic/double_to_str.c', 93 101 'generic/elf/elf.c', 94 102 'generic/elf/elf_load.c', 95 103 'generic/elf/elf_mod.c', 104 'generic/errno.c', 96 105 'generic/event.c', 97 'generic/errno.c', 106 'generic/getopt.c', 107 'generic/ieee_double.c', 108 'generic/imath.c', 98 109 'generic/inttypes.c', 99 'generic/loc.c',100 'generic/string.c',101 'generic/l18n/langs.c',102 'generic/pcb.c',103 'generic/pio_trace.c',104 'generic/smc.c',105 'generic/task.c',106 'generic/imath.c',107 110 'generic/io/asprintf.c', 108 111 'generic/io/io.c', 109 'generic/io/printf.c', 112 'generic/io/kio.c', 113 'generic/io/klog.c', 110 114 'generic/io/log.c', 111 115 'generic/io/logctl.c', 112 'generic/io/kio.c', 113 'generic/io/klog.c', 114 'generic/io/snprintf.c', 116 'generic/io/printf.c', 117 'generic/io/table.c', 115 118 'generic/io/vprintf.c', 116 'generic/io/vsnprintf.c', 117 'generic/io/table.c', 119 'generic/ipc.c', 118 120 'generic/irq.c', 119 'generic/ieee_double.c', 121 'generic/l18n/langs.c', 122 'generic/libc.c', 123 'generic/loader.c', 124 'generic/loc.c', 125 'generic/malloc.c', 126 'generic/ns.c', 127 'generic/pcb.c', 128 'generic/perm.c', 129 'generic/pio_trace.c', 120 130 'generic/power_of_ten.c', 121 'generic/double_to_str.c',122 'generic/malloc.c',123 131 'generic/rndgen.c', 132 'generic/setjmp.c', 124 133 'generic/shutdown.c', 134 'generic/smc.c', 135 'generic/stack.c', 136 'generic/stacktrace.c', 137 'generic/stats.c', 138 'generic/stdio.c', 125 139 'generic/stdio/scanf.c', 126 140 'generic/stdio/sprintf.c', … … 128 142 'generic/stdio/sstream.c', 129 143 'generic/stdio/vsprintf.c', 144 'generic/stdlib.c', 145 'generic/string.c', 146 'generic/sysinfo.c', 147 'generic/task.c', 130 148 'generic/thread/fibril.c', 131 149 'generic/thread/fibril_synch.c', 150 'generic/thread/futex.c', 151 'generic/thread/mpsc.c', 132 152 'generic/thread/thread.c', 133 153 'generic/thread/tls.c', 134 'generic/thread/futex.c',135 'generic/thread/mpsc.c',136 'generic/sysinfo.c',137 'generic/ipc.c',138 'generic/ns.c',139 'generic/async/client.c',140 'generic/async/server.c',141 'generic/async/ports.c',142 'generic/loader.c',143 'generic/getopt.c',144 154 'generic/time.c', 145 155 'generic/tmpfile.c', 146 'generic/stdio.c', 147 'generic/stdlib.c', 156 'generic/ubsan.c', 148 157 'generic/udebug.c', 158 'generic/uuid.c', 149 159 'generic/vfs/canonify.c', 150 160 'generic/vfs/inbox.c', 151 161 'generic/vfs/mtab.c', 152 162 'generic/vfs/vfs.c', 153 'generic/setjmp.c',154 'generic/stack.c',155 'generic/stacktrace.c',156 'generic/arg_parse.c',157 'generic/stats.c',158 'generic/assert.c',159 'generic/ubsan.c',160 'generic/uuid.c',161 163 ) 162 164 163 165 if CONFIG_RTLD 164 166 src += files( 165 'generic/rtld/rtld.c',166 167 'generic/rtld/dynamic.c', 167 168 'generic/rtld/module.c', 169 'generic/rtld/rtld.c', 168 170 'generic/rtld/symbol.c', 169 171 ) … … 190 192 'test/qsort.c', 191 193 'test/sprintf.c', 194 'test/stdio.c', 192 195 'test/stdio/scanf.c', 193 'test/stdio.c',194 196 'test/stdlib.c', 195 197 'test/str.c', 196 198 'test/string.c', 197 199 'test/strtol.c', 200 'test/uchar.c', 198 201 'test/uuid.c', 199 202 ) -
uspace/lib/c/test/adt/odict.c
r800d188 r29e7cc7 233 233 234 234 e->key = v; 235 odict_insert(&e->odict, &odict, &ep->odict);235 odict_insert(&e->odict, &odict, ep ? &ep->odict : NULL); 236 236 PCUT_ASSERT_ERRNO_VAL(EOK, odict_validate(&odict)); 237 237 v = seq_next(v); -
uspace/lib/c/test/main.c
r800d188 r29e7cc7 57 57 PCUT_IMPORT(strtol); 58 58 PCUT_IMPORT(table); 59 PCUT_IMPORT(uchar); 59 60 PCUT_IMPORT(uuid); 60 61 -
uspace/lib/c/test/sprintf.c
r800d188 r29e7cc7 1 1 /* 2 2 * Copyright (c) 2014 Vojtech Horky 3 * Copyright (c) 2025 Jiří Zárevúcky 3 4 * All rights reserved. 4 5 * … … 31 32 #include <pcut/pcut.h> 32 33 34 #pragma GCC diagnostic ignored "-Wformat" 35 33 36 #define BUFFER_SIZE 8192 34 37 #define TEQ(expected, actual) PCUT_ASSERT_STR_EQUALS(expected, actual) … … 36 39 37 40 #define SPRINTF_TEST(test_name, expected_string, actual_format, ...) \ 38 PCUT_TEST( test_name) { \41 PCUT_TEST(printf_##test_name) { \ 39 42 snprintf(buffer, BUFFER_SIZE, actual_format, ##__VA_ARGS__); \ 40 43 PCUT_ASSERT_STR_EQUALS(expected_string, buffer); \ … … 79 82 (long long) -5); 80 83 81 SPRINTF_TEST(int_as_hex, "[0x11] [0x012] [0x013] [0x00014] [0x00015]", 82 "[%#x] [%#5.3x] [%#-5.3x] [%#3.5x] [%#-3.5x]", 83 17, 18, 19, 20, 21); 84 SPRINTF_TEST(int_as_hex, "[1a] [ 02b] [03c ] [ 04d] [05e ] [0006f] [00080]", 85 "[%x] [%5.3x] [%-5.3x] [%7.3x] [%-7.3x] [%3.5x] [%-3.5x]", 86 26, 43, 60, 77, 94, 111, 128); 87 88 SPRINTF_TEST(int_as_hex_alt, "[0x1a] [0x02b] [0x03c] [ 0x04d] [0x05e ] [0x0006f] [0x00080]", 89 "[%#x] [%#5.3x] [%#-5.3x] [%#7.3x] [%#-7.3x] [%#3.5x] [%#-3.5x]", 90 26, 43, 60, 77, 94, 111, 128); 91 92 SPRINTF_TEST(int_as_hex_uc, "[1A] [ 02B] [03C ] [ 04D] [05E ] [0006F] [00080]", 93 "[%X] [%5.3X] [%-5.3X] [%7.3X] [%-7.3X] [%3.5X] [%-3.5X]", 94 26, 43, 60, 77, 94, 111, 128); 95 96 SPRINTF_TEST(int_as_hex_alt_uc, "[0X1A] [0X02B] [0X03C] [ 0X04D] [0X05E ] [0X0006F] [0X00080]", 97 "[%#X] [%#5.3X] [%#-5.3X] [%#7.3X] [%#-7.3X] [%#3.5X] [%#-3.5X]", 98 26, 43, 60, 77, 94, 111, 128); 99 100 SPRINTF_TEST(max_negative, "-9223372036854775808", "%" PRId64, INT64_MIN); 101 102 SPRINTF_TEST(sign1, "[12] [ 12] [+12] [+12] [+12] [+12]", "[%d] [% d] [%+d] [% +d] [%+ d] [%++ ++ + ++++d]", 12, 12, 12, 12, 12, 12); 103 SPRINTF_TEST(sign2, "[-12] [-12] [-12] [-12] [-12] [-12]", "[%d] [% d] [%+d] [% +d] [%+ d] [%++ ++ + ++++d]", -12, -12, -12, -12, -12, -12); 104 105 /* When zero padding and precision and/or left justification are both specified, zero padding is ignored. */ 106 SPRINTF_TEST(zero_left_padding, "[ 0012] [0034 ] [56 ]", "[%08.4d] [%-08.4d] [%-08d]", 12, 34, 56); 107 108 /* Zero padding comes after the sign, but space padding doesn't. */ 109 SPRINTF_TEST(sign_padding, "[00012] [ 12] [ 0012] [ 12] [+0012] [ +12]", "[%05d] [%5d] [%0 5d] [% 5d] [%0+5d] [%+5d]", 12, 12, 12, 12, 12, 12); 110 SPRINTF_TEST(sign_padding2, "[-0012] [ -12] [-0012] [ -12] [-0012] [ -12]", "[%05d] [%5d] [%0 5d] [% 5d] [%0+5d] [%+5d]", -12, -12, -12, -12, -12, -12); 111 112 SPRINTF_TEST(all_zero, "[00000] [0] [0] [0] [0] [0] [0] [0] [0]", "[%05d] [%d] [%x] [%#x] [%o] [%#o] [%b] [%#b] [%u]", 0, 0, 0, 0, 0, 0, 0, 0, 0); 84 113 85 114 PCUT_EXPORT(sprintf); -
uspace/lib/c/test/str.c
r800d188 r29e7cc7 27 27 */ 28 28 29 #include "pcut/asserts.h" 30 #include <assert.h> 31 #include <stdint.h> 29 32 #include <stdio.h> 30 33 #include <str.h> … … 47 50 } 48 51 52 /* Helper to display string contents for debugging */ 53 static void print_string_hex(char *out, const char *s, size_t len) 54 { 55 *out++ = '"'; 56 for (size_t i = 0; i < len && s[i]; i++) { 57 if (s[i] >= 32 && s[i] <= 126) 58 *out++ = s[i]; 59 else 60 out += snprintf(out, 5, "\\x%02x", (uint8_t) s[i]); 61 } 62 *out++ = '"'; 63 *out++ = 0; 64 } 65 49 66 PCUT_TEST(rtrim) 50 67 { … … 115 132 } 116 133 134 PCUT_TEST(str_non_shortest) 135 { 136 /* Overlong zero. */ 137 const char overlong1[] = "\xC0\x80"; 138 const char overlong2[] = "\xE0\x80\x80"; 139 const char overlong3[] = "\xF0\x80\x80\x80"; 140 141 const char overlong4[] = "\xC1\xBF"; 142 const char overlong5[] = "\xE0\x9F\xBF"; 143 const char overlong6[] = "\xF0\x8F\xBF\xBF"; 144 145 size_t offset = 0; 146 PCUT_ASSERT_INT_EQUALS(U_SPECIAL, str_decode(overlong1, &offset, sizeof(overlong1))); 147 offset = 0; 148 PCUT_ASSERT_INT_EQUALS(U_SPECIAL, str_decode(overlong2, &offset, sizeof(overlong2))); 149 offset = 0; 150 PCUT_ASSERT_INT_EQUALS(U_SPECIAL, str_decode(overlong3, &offset, sizeof(overlong3))); 151 offset = 0; 152 PCUT_ASSERT_INT_EQUALS(U_SPECIAL, str_decode(overlong4, &offset, sizeof(overlong4))); 153 offset = 0; 154 PCUT_ASSERT_INT_EQUALS(U_SPECIAL, str_decode(overlong5, &offset, sizeof(overlong5))); 155 offset = 0; 156 PCUT_ASSERT_INT_EQUALS(U_SPECIAL, str_decode(overlong6, &offset, sizeof(overlong6))); 157 } 158 159 struct sanitize_test { 160 const char *input; 161 const char *output; 162 }; 163 164 static const struct sanitize_test sanitize_tests[] = { 165 // Empty string 166 { "", "" }, 167 // ASCII only 168 { "Hello, world!", "Hello, world!" }, 169 // Valid multi-byte sequences 170 { "Aπ你🐱", "Aπ你🐱" }, 171 // U+D7FF is last valid before surrogates 172 { "A\xED\x9F\xBFZ", "A\xED\x9F\xBFZ" }, 173 // 0x10FFFF is the highest legal code point 174 { "A\xF4\x8F\xBF\xBFZ", "A\xF4\x8F\xBF\xBFZ" }, 175 176 // Missing continuation byte 177 { "A\xC2Z", "A?Z" }, 178 // Truncated multi-byte at buffer end 179 { "A\xE2\x82", "A??" }, 180 // Continuation byte without leading byte (0x80-0xBF are never valid first bytes) 181 { "A\x80Y\xBFZ", "A?Y?Z" }, 182 183 // 'A' (U+0041) normally encoded as 0x41 184 // Overlong 2-byte encoding: 0xC1 0x81 185 { "\xC1\x81X", "??X" }, 186 187 // ¢ (U+00A2) normally encoded as 0xC2 0xA2 188 // Overlong 3-byte encoding: 0xE0 0x82 0xA2 189 { "\xE0\x82\xA2X", "???X" }, 190 191 // ¢ (U+00A2) normally encoded as 0xC2 0xA2 192 // Overlong 4-byte encoding: 0xF0 0x80 0x82 0xA2 193 { "\xF0\x80\x82\xA2X", "????X" }, 194 195 // € (U+20AC) normally encoded as 0xE2 0x82 0xAC 196 // Overlong 4-byte encoding: 0xF0 0x82 0x82 0xAC 197 { "\xF0\x82\x82\xACX", "????X" }, 198 199 // Using 0xC0 0x80 as overlong encoding for NUL (which should be just 0x00) 200 { "\xC0\x80X", "??X" }, 201 202 // 0xED 0xA0 0x80 encodes a surrogate half (U+D800), not allowed in UTF-8 203 { "A\xED\xA0\x80Z", "A???Z" }, 204 205 // 0x110000 is not a legal code point 206 { "A\xF4\x90\x80\x80Z", "A????Z" }, 207 208 // Mix of valid and invalid sequences 209 { "A\xC2\xA9\xE2\x28\xA1\xF0\x9F\x98\x81\x80Z", "A©?(?😁?Z" }, 210 }; 211 212 static size_t count_diff(const char *a, const char *b, size_t n) 213 { 214 size_t count = 0; 215 216 for (size_t i = 0; i < n; i++) { 217 if (a[i] != b[i]) 218 count++; 219 } 220 221 return count; 222 } 223 224 PCUT_TEST(str_sanitize) 225 { 226 char replacement = '?'; 227 char buffer2[255]; 228 229 for (size_t i = 0; i < sizeof(sanitize_tests) / sizeof(sanitize_tests[0]); i++) { 230 const char *in = sanitize_tests[i].input; 231 const char *out = sanitize_tests[i].output; 232 size_t n = str_size(in) + 1; 233 assert(str_size(out) + 1 == n); 234 235 memcpy(buffer, in, n); 236 size_t replaced = str_sanitize(buffer, n, replacement); 237 if (memcmp(buffer, out, n) != 0) { 238 print_string_hex(buffer2, buffer, n); 239 print_string_hex(buffer, out, n); 240 PCUT_ASSERTION_FAILED("Expected %s, got %s", buffer, buffer2); 241 } 242 243 size_t expect_replaced = count_diff(buffer, in, n); 244 PCUT_ASSERT_INT_EQUALS(expect_replaced, replaced); 245 } 246 247 // Test with n smaller than string length - truncated valid encoding for € 248 const char *in = "ABC€"; 249 const char *out = "ABC??\xAC"; 250 size_t n = str_size(in) + 1; 251 memcpy(buffer, in, n); 252 size_t replaced = str_sanitize(buffer, 5, replacement); 253 if (memcmp(buffer, out, n) != 0) { 254 print_string_hex(buffer2, buffer, n); 255 print_string_hex(buffer, out, n); 256 PCUT_ASSERTION_FAILED("Expected %s, got %s", buffer, buffer2); 257 } 258 259 PCUT_ASSERT_INT_EQUALS(2, replaced); 260 } 261 117 262 PCUT_EXPORT(str);
Note:
See TracChangeset
for help on using the changeset viewer.
