Branch data Line data Source code
1 : : #include "mem.h"
2 : : #include "mem_internal.h"
3 : : #include <string.h>
4 : :
5 : : /**
6 : : * @brief Convert a data descriptor into string mode and cache the visible length
7 : : *
8 : : * Use this helper when a descriptor currently holds raw data, but from now on
9 : : * should behave like a string. The function scans the current logical range
10 : : * until it finds the first zero-valued element and treats that position as the
11 : : * end of the visible string. A zero-valued element means that every byte in
12 : : * that element is zero
13 : : *
14 : : * If the descriptor is not empty and there is not enough logical room for one
15 : : * trailing terminator, the helper grows it and writes that terminator for you.
16 : : * Empty descriptors are promoted to string mode without allocating storage.
17 : : * Descriptors that are already in string mode are accepted as a no-op only
18 : : * when their cached string metadata is internally consistent
19 : : *
20 : : * The helper rejects inconsistent descriptors instead of guessing what the user
21 : : * meant. Examples include `length > 0` with `data == NULL`, `single_element_size == 0`,
22 : : * or stale `string_length` while the descriptor is still in data mode
23 : : *
24 : : * Small example:
25 : : * @code
26 : : * m_create(char,buffer);
27 : : * if((TRIUMPH & mem_copy_buffer(buffer,sizeof("abc"),"abc")) == 0) { return FAILURE; }
28 : : * if((TRIUMPH & mem_convert_data_to_string(buffer)) == 0) { return FAILURE; }
29 : : * // buffer->length == 4, buffer->string_length == 3, buffer->is_string == true
30 : : * @endcode
31 : : *
32 : : * @param memory_structure Mutable descriptor that should start behaving like a string
33 : : * @return `SUCCESS` on success; `FAILURE` if the descriptor is inconsistent or cannot be resized
34 : : */
35 : 248 : Return mem_convert_data_to_string(memory *memory_structure)
36 : : {
37 : : /* This function was reviewed line by line by a human and is not AI-generated
38 : : Any change to this function requires separate explicit approval */
39 : :
40 : : /* Status returned by this function through provide()
41 : : Default value assumes successful completion */
42 : 248 : Return status = SUCCESS;
43 : :
44 : : /* Visible prefix length used to update string_length and place the terminator */
45 : 248 : size_t measured_length = 0;
46 : :
47 [ - + ]: 248 : if(memory_structure == NULL)
48 : : {
49 : 0 : report("Memory management; Invalid arguments for string conversion");
50 : 0 : provide(FAILURE);
51 : : }
52 : :
53 [ + + + + ]: 248 : if(memory_structure->length > 0 && memory_structure->data == NULL)
54 : : {
55 : 1 : report("Memory management; Descriptor has non-zero length with NULL data pointer");
56 : 1 : provide(FAILURE);
57 : : }
58 : :
59 [ + + ]: 247 : if(memory_structure->is_string == false &&
60 [ + + ]: 39 : memory_structure->string_length != 0)
61 : : {
62 : 1 : report("Memory management; Data descriptor has non-zero string_length during string conversion");
63 : 1 : provide(FAILURE);
64 : : }
65 : :
66 [ + + ]: 246 : if(memory_structure->single_element_size == 0)
67 : : {
68 : 1 : report("Memory management; Descriptor element size is zero during string conversion");
69 : 1 : provide(FAILURE);
70 : : }
71 : :
72 [ + + ]: 245 : if(memory_structure->is_string == true &&
73 [ + + ]: 207 : memory_structure->length == 0 &&
74 [ + + ]: 2 : memory_structure->string_length != 0)
75 : : {
76 : 1 : report("Memory management; String descriptor has non-zero string_length with zero length during string conversion");
77 : 1 : provide(FAILURE);
78 : : }
79 : :
80 [ + + ]: 244 : if(memory_structure->is_string == true &&
81 [ + + ]: 206 : memory_structure->length > 0 &&
82 [ + + ]: 205 : memory_structure->string_length >= memory_structure->length)
83 : : {
84 : 1 : report("Memory management; String descriptor cache is inconsistent during string conversion");
85 : 1 : provide(FAILURE);
86 : : }
87 : :
88 [ + + ]: 243 : if(memory_structure->is_string == true)
89 : : {
90 : 205 : provide(status);
91 : : }
92 : :
93 [ + + ]: 38 : if(memory_structure->length == 0)
94 : : {
95 : 22 : memory_structure->string_length = 0;
96 : 22 : memory_structure->is_string = true;
97 : : }
98 : :
99 [ + + ]: 38 : if(memory_structure->length > 0)
100 : : {
101 : : /* Reserve room for exactly one trailing string terminator.
102 : : This block first measures how much payload is currently visible before the first zero-valued element.
103 : : It then computes payload plus one terminator slot and grows the descriptor only when the current logical length is too small */
104 : 16 : size_t required_elements = 0;
105 : :
106 : 16 : run(mem_find_zero_terminator(memory_structure,&measured_length));
107 : 16 : run(mem_guarded_add(measured_length,1,&required_elements));
108 : :
109 [ - + ]: 16 : if(CRITICAL & status)
110 : : {
111 : 0 : report("Memory management; Not enough room for string terminator");
112 : : }
113 : :
114 : : /* Grow only when the current logical length cannot hold both the visible payload and one final zero-valued terminator.
115 : : If enough logical space already exists, conversion keeps the current descriptor size and reuses it as is */
116 [ + - + + ]: 16 : if((TRIUMPH & status) && memory_structure->length < required_elements)
117 : : {
118 : 5 : run(m_resize(memory_structure,required_elements));
119 : : }
120 : : }
121 : :
122 [ + - + + ]: 38 : if((TRIUMPH & status) && memory_structure->length > 0)
123 : : {
124 : : /* Materialize a well-formed string view in the current buffer.
125 : : This block writes the final zero-valued terminator at the measured boundary,
126 : : then stores the visible payload length in string_length and marks the descriptor as a string */
127 : 16 : unsigned char *memory_structure_data_rewritable = (unsigned char *)memory_structure->data;
128 : :
129 [ - + ]: 16 : if(memory_structure_data_rewritable == NULL)
130 : : {
131 : 0 : report("Memory management; Data pointer is NULL while converting data to string");
132 : 0 : status = FAILURE;
133 : : } else {
134 : : /* Finalize the descriptor as a usable string.
135 : : This writes the terminating zero element at the measured boundary,
136 : : caches how many payload elements stay visible before that terminator,
137 : : and switches the descriptor into string mode for future string-aware helpers */
138 : 16 : run(mem_write_zero_terminator(memory_structure,measured_length));
139 : 16 : memory_structure->string_length = measured_length;
140 : 16 : memory_structure->is_string = true;
141 : : }
142 : : }
143 : :
144 [ + - ]: 38 : if(TRIUMPH & status)
145 : : {
146 : 38 : telemetry_data_to_string_conversions();
147 : : }
148 : :
149 : 38 : provide(status);
150 : : }
|