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

nasa / trick / 24056498786

06 Apr 2026 11:34PM UTC coverage: 55.988% (+0.2%) from 55.798%
24056498786

Pull #1965

github

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

173 of 205 new or added lines in 5 files covered. (84.39%)

73 existing lines in 2 files now uncovered.

12679 of 22646 relevant lines covered (55.99%)

305418.97 hits per line

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

94.94
/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)
50,163✔
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)
50,163✔
10
    {
11
        return ((member.mods >> 3) & 0x3F);
5✔
12
    }
13

14
    // if array
15
    if (member.num_index != 0)
50,158✔
16
    {
17
        // if size of last valid index is 0, then we are looking at a pointer
18
        size_t total = 0;
32,909✔
19
        if (member.index[member.num_index - 1].size == 0)
32,909✔
20
        {
21
            total = sizeof(void *);
18,070✔
22
        } else { 
23
            total = member.size;
14,839✔
24
        }
25
        // multiply by sizes of fixed dimensions
26
        for (int i = 0; i < member.num_index; ++i)
65,974✔
27
        {
28
            if (member.index[i].size != 0)
51,135✔
29
            {
30
                total *= member.index[i].size;
33,065✔
31
            }
32
            else
33
            {
34
                break;
18,070✔
35
            }
36
        }
37
        return total;
32,909✔
38
    }
39

40
    // just return member.size otherwise
41
    return member.size;
17,249✔
42
}
43

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

76
// Count the number of fixed dimensions on an ATTRIBUTES entry.
77
int Trick::AttributesUtils::count_fixed_dims(const ATTRIBUTES &member)
1,235✔
78
{
79
    int num_fixed_dims = 0;
1,235✔
80
    for (int i = 0; i < member.num_index; ++i)
3,237✔
81
    {
82
        if (member.index[i].size > 0)
2,229✔
83
        {
84
            ++num_fixed_dims;
2,002✔
85
        }
86
        else
87
        {
88
            break;
227✔
89
        }
90
    }
91
    return num_fixed_dims;
1,235✔
92
}
93

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

171
    // Find the structure member that corresponds to the reference offset
172
    ATTRIBUTES *ret_attr = find_member_by_offset(struct_attr, reference_offset);
2,952✔
173

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

182
    result.found_attr = ret_attr;
2,364✔
183
    result.offset_from_found_attr = reference_offset - ret_attr->offset;
2,364✔
184

185
    // Handle non-structured (primitive) types
186
    if (ret_attr->type != TRICK_STRUCTURED)
2,364✔
187
    {
188
        // Check if it's a scalar or unconstrained pointer
189
        if (ret_attr->num_index == 0 || ret_attr->index[0].size == 0)
1,259✔
190
        {
191
            return 0;
25✔
192
        }
193

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

198
        if (!ok)
1,234✔
199
        {
NEW
200
            return 1;
×
201
        }
202

203
        return 0;
1,234✔
204
    }
205

206
    // Handle TRICK_STRUCTURED types
207

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

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

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

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

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

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

249
    result.offset_from_found_attr = element_offset;
1✔
250

251
    return 0;
1✔
252
}
253

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

274
    long size = member.size;
1,235✔
275
    int last_size = member.size;
1,235✔
276
    long remaining = offset_within_member_bytes;
1,235✔
277

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