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

nasa / trick / 22883160149

10 Mar 2026 01:42AM UTC coverage: 55.807%. First build
22883160149

Pull #1965

github

web-flow
Merge e3e10af72 into 282376682
Pull Request #1965: 1964 methods return size one pointers

146 of 177 new or added lines in 3 files covered. (82.49%)

12624 of 22621 relevant lines covered (55.81%)

308509.85 hits per line

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

92.31
/trick_source/sim_services/MemoryManager/AttributesUtils.cpp
1
#include "trick/AttributesUtils.hh"
2

3
// Compute the byte size occupied by a member - references, arrays, and pointers
4
size_t Trick::AttributesUtils::compute_member_byte_size(const ATTRIBUTES &member)
4,783✔
5
{
6
    // if mod bit 0 is set, member is a reference. Width of reference is stored
7
    // in bits 3-8 of mods. We could use size(void*), but that is implementation
8
    // specific and not required by C++ standard.
9
    if ((member.mods & 1) == 1)
4,783✔
10
    {
11
        return ((member.mods >> 3) & 0x3F);
5✔
12
    }
13

14
    // if array
15
    if (member.num_index != 0)
4,778✔
16
    {
17
        // if size of last valid index is 0, then we are looking at a pointer
18
        if (member.index[member.num_index - 1].size == 0)
415✔
19
        {
20
            return sizeof(void *);
349✔
21
        }
22
        size_t total = member.size;
66✔
23
        // multiply by sizes of fixed dimensions
24
        for (int i = 0; i < member.num_index; ++i)
134✔
25
        {
26
            if (member.index[i].size != 0)
68✔
27
            {
28
                total *= member.index[i].size;
68✔
29
            }
30
            else
31
            {
NEW
32
                break;
×
33
            }
34
        }
35
        return total;
66✔
36
    }
37

38
    // just return member.size otherwise
39
    return member.size;
4,363✔
40
}
41

42
// Return the ATTRIBUTES entry that contains the given offset within the struct/class.
43
// Example: for a struct with members like this:
44
//   struct MyStruct {
45
//     int a;          // offset 0, size 4 (padding 4-7)
46
//     double b;       // offset 8, size 8
47
//     char c[10];     // offset 16, size 10
48
//   }
49
// Then:
50
//   find_member_by_offset(structAttr, 2) would return the ATTRIBUTES for 'a' because offset 2 is within 'a' (0-3).
51
//   find_member_by_offset(structAttr, 10) would return the ATTRIBUTES for 'b' because offset 10 is within 'b' (8-15).
52
//   find_member_by_offset(structAttr, 20) would return the ATTRIBUTES for 'c' because offset 20 is within 'c' (16-25).
53
ATTRIBUTES *Trick::AttributesUtils::find_member_by_offset(ATTRIBUTES *structAttr, size_t addrOffsetFromStruct)
762✔
54
{
55
    int ii = 0;
762✔
56
    size_t temp_size;
57
    // Find the member which contains the address pointed to by addr and offset
58
    while (structAttr[ii].name[0] != '\0')
5,371✔
59
    {
60
        temp_size = compute_member_byte_size(structAttr[ii]);
4,783✔
61
        if (addrOffsetFromStruct < structAttr[ii].offset ||
4,783✔
62
            addrOffsetFromStruct >= structAttr[ii].offset + temp_size)
1,103✔
63
        {
64
            ++ii;
4,609✔
65
        }
66
        else
67
        {
68
            break;
69
        }
70
    }
71
    return &(structAttr[ii]);
762✔
72
}
73

74
// Count the number of fixed dimensions on an ATTRIBUTES entry.
75
int Trick::AttributesUtils::count_fixed_dims(const ATTRIBUTES &member)
3✔
76
{
77
    int num_fixed_dims = 0;
3✔
78
    for (int i = 0; i < member.num_index; ++i)
8✔
79
    {
80
        if (member.index[i].size > 0)
5✔
81
        {
82
            ++num_fixed_dims;
5✔
83
        }
84
        else
85
        {
NEW
86
            break;
×
87
        }
88
    }
89
    return num_fixed_dims;
3✔
90
}
91

92
// Resolve a byte offset within a structured object to the matching member and array context.
93
// This call resolves one strucural level at a time. The caller is responsible for stepping
94
// through nested structures by calling this function recursively with the found member's ATTRIBUTES
95
// and the offset within that member.
96
//
97
// Example 1: for a struct with members like this:
98
//   struct MyStruct {
99
//     int a;        // offset 0, size 4
100
//     int b[3];     // offset 4, size 4 each
101
//   }
102
// Entries would be:
103
//   myStructAttr[0] = { name="a", offset=0, size=4, num_index=0, ... }
104
//   myStructAttr[1] = { name="b", offset=4, size=4, num_index=1, index[0].size=3, ... }
105
//   myStructAttr[2] = { name="", ... } // Sentinel
106
// So member b occupies these bytes:
107
//   b[0] at offset 4-7
108
//   b[1] at offset 8-11
109
//   b[2] at offset 12-15
110
// Then call:
111
//   TraversalResult result;
112
//   traverse_for_offset(10, myStructAttr, result);
113
// Basically asking given the member layout of MyStruct, what member contains byte offset 10
114
//   The function would resolve offset 10 to member 'b' and compute the array index as 1
115
//   because b[1] occupies bytes 8-11 which contains byte 10. So result would be:
116
//     result.found_attr = b (pointer to myStructAttr[1] (the ATTRIBUTES for 'b'))
117
//     result.offset_from_found_attr = 10 - 4 = 6 (offset within member 'b')
118
//     result.array_indices = [1] (index for the first dimension of 'b')
119
//     result.num_computed_indices = 1 (because 'b' is a 1D array)
120
//     result.is_in_anonymous_member = false (because a member with a name that contains the offset was found)
121
//
122
// Example 2: for a struct with a structured array member like this:
123
//   struct Inner {
124
//     double q;   // offset 0, size 8
125
//     int r;      // offset 8, size 4
126
//   };
127
//
128
//   struct Outer {
129
//     int a;          // offset 0
130
//     Inner items[4]; // offset 8, each element size 16
131
//   };
132
//
133
// Array layout of items would be:
134
//   items[0].q at offset 8-15
135
//   items[0].r at offset 16-19
136
//   items[1].q at offset 24-31
137
//   items[1].r at offset 32-35
138
//   items[2].q at offset 40-47
139
//   items[2].r at offset 48-51
140
//   items[3].q at offset 56-63
141
//   items[3].r at offset 64-67
142
//
143
// If called with reference_offset = 44, the function would resolve it to the
144
// named member 'items', because offset 44 lies within the items member.
145
// The result would be:
146
//   result.found_attr = items (pointer to ATTRIBUTES for 'items')
147
//   result.offset_from_found_attr = 32
148
//     (initially 44 - 8 = 36, then adjusted to the base offset of items[2],
149
//      which is 2 * 16 = 32 bytes into the items array)
150
//   result.array_indices = [2]
151
//   result.num_computed_indices = 1
152
//   result.is_in_anonymous_member = false
153
//
154
// The call resolves the address to the named member 'items' and computes array
155
// index 2 because items[2] contains byte offset 44. It does not resolve to the
156
// inner members 'q' or 'r' yet; that happens after the caller recurses into
157
// items[2]. On that recursive call, the inner offset is 44 - 40 = 4, so the
158
// found_attr would be 'q' because q occupies offsets 0-7 within Inner.
159
// That is how ClassicCheckPointerAgent builds names, and how MemoryManager_get_attributes_for_address
160
// walks into nested members.
161
int Trick::AttributesUtils::traverse_for_offset(
762✔
162
    size_t reference_offset,
163
    ATTRIBUTES *struct_attr,
164
    TraversalResult &result)
165
{
166
    // Initialize result
167
    result = TraversalResult{};
762✔
168

169
    // Find the structure member that corresponds to the reference offset
170
    ATTRIBUTES *ret_attr = find_member_by_offset(struct_attr, reference_offset);
762✔
171

172
    // Check if we failed to find a member (anonymous/**'d out member)
173
    if (ret_attr->name[0] == '\0')
762✔
174
    {
175
        result.is_in_anonymous_member = true;
588✔
176
        result.offset_from_found_attr = reference_offset;
588✔
177
        return 0;
588✔
178
    }
179

180
    result.found_attr = ret_attr;
174✔
181
    result.offset_from_found_attr = reference_offset - ret_attr->offset;
174✔
182

183
    // Handle non-structured (primitive) types
184
    if (ret_attr->type != TRICK_STRUCTURED)
174✔
185
    {
186
        // Check if it's a scalar or unconstrained pointer
187
        if (ret_attr->num_index == 0 || ret_attr->index[0].size == 0)
19✔
188
        {
189
            return 0;
17✔
190
        }
191

192
        // It's an array - compute indices
193
        size_t offset_in_array = result.offset_from_found_attr;
2✔
194
        bool ok = compute_fixed_indices_for_linear_offset(*ret_attr, offset_in_array, result.array_indices, result.num_computed_indices);
2✔
195

196
        if (!ok)
2✔
197
        {
NEW
198
            return 1;
×
199
        }
200

201
        return 0;
2✔
202
    }
203

204
    // Handle TRICK_STRUCTURED types
205

206
    // If it's a reference (&), we're done
207
    if ((ret_attr->mods & 1) == 1)
155✔
208
    {
209
        return 0;
1✔
210
    }
211

212
    // If it's an unarrayed struct, caller should recurse into it
213
    if (ret_attr->num_index == 0)
154✔
214
    {
215
        // Signal to caller that recursion is needed
216
        // The found_attr and offset info are already set
217
        return 0;
151✔
218
    }
219

220
    // If it's a pointer (unconstrained array), we're done
221
    if (ret_attr->index[0].size == 0)
3✔
222
    {
223
        return 0;
2✔
224
    }
225

226
    // It's an arrayed struct - compute indices
227
    size_t offset_in_array = result.offset_from_found_attr;
1✔
228
    bool ok = compute_fixed_indices_for_linear_offset(*ret_attr, offset_in_array, result.array_indices, result.num_computed_indices);
1✔
229

230
    if (!ok)
1✔
231
    {
NEW
232
        return 1;
×
233
    }
234

235
    // Calculate the linear offset within the array element
236
    size_t element_offset = 0;
1✔
237
    for (int j = 0; j < ret_attr->num_index; j++)
3✔
238
    {
239
        int m = result.array_indices[j];
2✔
240
        for (int k = j + 1; m && (k < ret_attr->num_index); k++)
3✔
241
        {
242
            m *= ret_attr->index[k].size;
1✔
243
        }
244
        element_offset += m * ret_attr->size;
2✔
245
    }
246

247
    result.offset_from_found_attr = element_offset;
1✔
248

249
    return 0;
1✔
250
}
251

252
// Convert a byte offset within fixed array into concrete array indices.
253
// Example: For an array int a[3][4], assuming:
254
//   member.size = 4 (size of int in bytes)
255
//   dimensions are 3 and 4 (member.index[0].size = 3, member.index[1].size = 4)
256
//   offset_within_member_bytes = 28
257
//     Byte 28 means the 8th int overall, so the expected indices would be [1][3] 
258
//     because a[1][3] is the 8th int (0-based indexing).
259
//   So, out_indices would be set to [1, 3] and out_num_fixed_dims would be set to 2.
260
bool Trick::AttributesUtils::compute_fixed_indices_for_linear_offset(
3✔
261
    const ATTRIBUTES &member,
262
    long offset_within_member_bytes,
263
    int out_indices[TRICK_MAX_INDEX],
264
    int &out_num_fixed_dims)
265
{
266
    out_num_fixed_dims = count_fixed_dims(member);
3✔
267
    if (out_num_fixed_dims == 0)
3✔
268
    {
NEW
269
        return true;
×
270
    }
271

272
    long size = member.size;
3✔
273
    int last_size = member.size;
3✔
274
    long remaining = offset_within_member_bytes;
3✔
275

276
    for (int i = out_num_fixed_dims - 1; i >= 0; --i)
8✔
277
    {
278
        size *= member.index[i].size;
5✔
279
        if (size == 0 || last_size == 0)
5✔
280
        {
NEW
281
            return false;
×
282
        }
283
        out_indices[i] = static_cast<int>((remaining % size) / last_size);
5✔
284
        remaining -= last_size * out_indices[i];
5✔
285
        last_size = size;
5✔
286
    }
287
    return true;
3✔
288
}
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