Branch data Line data Source code
1 : : #include "mem_internal.h"
2 : : #include <string.h>
3 : :
4 : : /**
5 : : * @brief Count visible elements in a raw zero-terminated string
6 : : *
7 : : * This internal helper measures a raw source string without requiring a
8 : : * `memory` descriptor. It supports two scan modes. In bounded mode, it inspects
9 : : * at most @p source_limit_bytes bytes and reports either the first zero-valued
10 : : * element position or the number of whole elements that fit into that byte
11 : : * range. In unbounded mode, it scans until the first zero-valued element
12 : : *
13 : : * A zero-valued element means that every byte in that element is zero. For
14 : : * byte-sized elements the helper delegates to libc `memchr` in bounded mode and
15 : : * `strlen` in unbounded mode. Wider elements are scanned element by element so
16 : : * a zero byte inside a wider element does not accidentally terminate the string
17 : : *
18 : : * @warning Unbounded mode has the same safety contract as `strlen`. The caller
19 : : * must guarantee that @p source_string is non-NULL and truly terminated by a
20 : : * zero-valued element of width @p single_element_size
21 : : *
22 : : * @param source_string Raw source bytes to inspect
23 : : * @param source_limit_bytes Maximum byte range to inspect in bounded mode
24 : : * @param single_element_size Size of one logical string element in bytes
25 : : * @param source_limit_is_active Whether @p source_limit_bytes limits the scan
26 : : * @param length_out Output pointer receiving the visible element count
27 : : * @param terminator_found_out Optional output pointer receiving whether a
28 : : * zero-valued terminator was found
29 : : * @return `SUCCESS` on success; `FAILURE` otherwise
30 : : */
31 : 27184 : Return mem_string_measure_length(
32 : : const void *const source_string,
33 : : const size_t source_limit_bytes,
34 : : const size_t single_element_size,
35 : : const bool source_limit_is_active,
36 : : size_t *const length_out,
37 : : bool *const terminator_found_out)
38 : : {
39 : : /* Status returned by this function through provide()
40 : : Default value assumes successful completion */
41 : 27184 : Return status = SUCCESS;
42 : :
43 : : /* Visible source prefix length measured in elements */
44 : 27184 : size_t measured_length = 0;
45 : :
46 : : /* Becomes true once a zero-valued terminator element is found */
47 : 27184 : bool terminator_found = false;
48 : :
49 [ + - - + ]: 27184 : if(source_string == NULL || length_out == NULL)
50 : : {
51 : 0 : report("Memory management; Invalid arguments for raw string length counter");
52 : 0 : status = FAILURE;
53 : : }
54 : :
55 [ + - - + ]: 27184 : if((TRIUMPH & status) && single_element_size == 0)
56 : : {
57 : 0 : report("Memory management; Raw string element size is zero");
58 : 0 : status = FAILURE;
59 : : }
60 : :
61 [ + - + + ]: 27184 : if((TRIUMPH & status) && single_element_size == sizeof(char))
62 : : {
63 : 27169 : const unsigned char *const source_data_view = (const unsigned char *)source_string;
64 : :
65 [ + + ]: 27169 : if(source_limit_is_active == true)
66 : : {
67 : : /* Address of the first zero byte found by the byte-sized fast path */
68 : 13187 : const void *found_terminator = memchr(source_data_view,0,source_limit_bytes);
69 : :
70 [ + + ]: 13187 : if(found_terminator == NULL)
71 : : {
72 : 7 : measured_length = source_limit_bytes;
73 : : } else {
74 : 13180 : measured_length = (size_t)((const unsigned char *)found_terminator - source_data_view);
75 : 13180 : terminator_found = true;
76 : : }
77 : : } else {
78 : 13982 : measured_length = strlen((const char *)source_string);
79 : 13982 : terminator_found = true;
80 : : }
81 : : }
82 : :
83 [ + - + + ]: 27184 : if((TRIUMPH & status) && single_element_size != sizeof(char))
84 : : {
85 : 15 : const unsigned char *source_data_view = (const unsigned char *)source_string;
86 : :
87 [ + + ]: 15 : if(source_limit_is_active == true)
88 : : {
89 : : /* Byte offset of the current logical element being inspected */
90 : 14 : size_t element_offset = 0;
91 : :
92 [ + + ]: 42 : while(element_offset + single_element_size <= source_limit_bytes)
93 : : {
94 [ + + ]: 40 : if(mem_is_zero_element(source_data_view + element_offset,single_element_size) == true)
95 : : {
96 : 12 : terminator_found = true;
97 : 12 : break;
98 : : }
99 : :
100 : 28 : ++measured_length;
101 : 28 : element_offset += single_element_size;
102 : : }
103 : : } else {
104 [ + + ]: 3 : while(mem_is_zero_element(source_data_view,single_element_size) == false)
105 : : {
106 : 2 : source_data_view += single_element_size;
107 : 2 : ++measured_length;
108 : : }
109 : :
110 : 1 : terminator_found = true;
111 : : }
112 : : }
113 : :
114 [ + - ]: 27184 : if(TRIUMPH & status)
115 : : {
116 : 27184 : *length_out = measured_length;
117 : :
118 [ - + ]: 27184 : if(terminator_found_out != NULL)
119 : : {
120 : 0 : *terminator_found_out = terminator_found;
121 : : }
122 : : }
123 : :
124 : 27184 : provide(status);
125 : : }
|