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

tudasc / TypeART / 13955121336

19 Mar 2025 07:30PM UTC coverage: 88.842%. First build
13955121336

push

github

web-flow
Merge PR #167 from tudasc/devel

1174 of 1361 new or added lines in 49 files covered. (86.26%)

4212 of 4741 relevant lines covered (88.84%)

261950.04 hits per line

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

93.82
/lib/runtime/TypeResolution.cpp
1
// TypeART library
2
//
3
// Copyright (c) 2017-2025 TypeART Authors
4
// Distributed under the BSD 3-Clause license.
5
// (See accompanying file LICENSE.txt or copy at
6
// https://opensource.org/licenses/BSD-3-Clause)
7
//
8
// Project home: https://github.com/tudasc/TypeART
9
//
10
// SPDX-License-Identifier: BSD-3-Clause
11
//
12

13
#include "TypeResolution.h"
14

15
#include "AllocationTracking.h"
16
#include "Runtime.h"
17
#include "RuntimeData.h"
18
#include "RuntimeInterface.h"
19
#include "TypeInterface.h"
20
#include "support/Logger.h"
21
#include "support/System.h"
22

23
#include "llvm/Support/raw_ostream.h"
24

25
#include <cassert>
26
#include <cstddef>
27
#include <cstdint>
28
#include <utility>
29
#include <vector>
30

31
namespace typeart {
32

33
namespace detail {
34

35
template <typename P, typename T>
36
inline const void* add_byte_offset(const P* addr, T offset) {
2,168 ✔
37
  assert(addr != nullptr);
2,168 ✔
38
  return static_cast<const P*>(static_cast<const char*>(addr) + offset);
2,168 ✔
39
}
40

41
template <typename T>
42
inline std::ptrdiff_t substract_pointer(const T* addr_a, const T* addr_b) {
1,580 ✔
43
  assert(addr_a != nullptr);
1,580 ✔
44
  assert(addr_b != nullptr);
1,580 ✔
45
  return static_cast<const char*>(addr_a) - static_cast<const char*>(addr_b);
1,580 ✔
46
}
47

48
inline size_t get_member_index_at(const typeart_struct_layout& structInfo, size_t offset) {
348 ✔
49
  const size_t num_members = structInfo.num_members;
348 ✔
50

51
  if (num_members == 0) {
348 ✔
52
    return 0;
×
53
  }
54

55
  const auto* struct_offsets = structInfo.offsets;
348 ✔
56

57
  if (offset > struct_offsets[num_members - 1]) {
348 ✔
58
    return num_members - 1;
15 ✔
59
  }
60

61
  size_t member_index{0};
333 ✔
62
  while (member_index < (num_members - 1) && offset >= struct_offsets[member_index + 1]) {
720 ✔
63
    ++member_index;
387 ✔
64
  }
65
  return member_index;
333 ✔
66
}
348 ✔
67

68
}  // namespace detail
69

70
TypeResolution::TypeResolution(const TypeDB& type_db, Recorder& recorder)
778 ✔
71
    : type_database{type_db}, runtime_recorder{recorder} {
778 ✔
72
}
778 ✔
73

74
TypeResolution::TypeArtStatus TypeResolution::getSubTypeInfo(const void* baseAddr, size_t offset,
784 ✔
75
                                                             const typeart_struct_layout& containerInfo, int* subType,
76
                                                             const void** subTypeBaseAddr, size_t* subTypeOffset,
77
                                                             size_t* subTypeCount) const {
78
  if (containerInfo.type_id < 0) {
372 ✔
79
    return TYPEART_ERROR;
12 ✔
80
  }
81

82
  if (offset >= containerInfo.extent) {
360 ✔
83
    return TYPEART_BAD_OFFSET;
12 ✔
84
  }
85

86
  // Get index of the struct member at the address
87
  const size_t memberIndex = detail::get_member_index_at(containerInfo, offset);
348 ✔
88
  const int memberType     = containerInfo.member_types[memberIndex];
348 ✔
89
  const size_t baseOffset  = containerInfo.offsets[memberIndex];
348 ✔
90

91
  const size_t internalOffset = offset - baseOffset;
348 ✔
92
  const size_t typeSize       = type_database.getTypeSize(memberType);
348 ✔
93
  if (typeSize == 0) {
348 ✔
NEW
94
    return TYPEART_INVALID_ID;
×
95
  }
96
  const size_t offsetInTypeSize = internalOffset / typeSize;
348 ✔
97
  const size_t newOffset        = internalOffset % typeSize;
348 ✔
98

99
  // If newOffset != 0, the subtype cannot be atomic, i.e. must be a struct
100
  if (newOffset != 0) {
348 ✔
101
    if (type_database.isReservedType(memberType)) {
24 ✔
102
      return TYPEART_BAD_ALIGNMENT;
24 ✔
103
    }
104
  }
×
105

106
  // Ensure that the array index is in bounds
107
  if (offsetInTypeSize >= containerInfo.count[memberIndex]) {
324 ✔
108
    // Address points to padding
109
    return TYPEART_BAD_ALIGNMENT;
60 ✔
110
  }
111

112
  *subType         = memberType;
264 ✔
113
  *subTypeBaseAddr = detail::add_byte_offset(baseAddr, baseOffset);
264 ✔
114
  *subTypeOffset   = newOffset;
264 ✔
115
  *subTypeCount    = containerInfo.count[memberIndex] - offsetInTypeSize;
264 ✔
116

117
  return TYPEART_OK;
264 ✔
118
}
372 ✔
119

120
TypeResolution::TypeArtStatus TypeResolution::getTypeInfoInternal(const void* baseAddr, size_t offset,
324 ✔
121
                                                                  const StructTypeInfo& containerInfo, int* type,
122
                                                                  size_t* count) const {
123
  assert(offset < containerInfo.extent && "Something went wrong with the base address computation");
648 ✔
124

125
  int subType{-1};
324 ✔
126
  const void* subTypeBaseAddr;
324 ✔
127
  size_t subTypeOffset{0};
324 ✔
128
  size_t subTypeCount{0};
324 ✔
129

130
  const StructTypeInfo* structInfo = &containerInfo;
324 ✔
131

132
  const auto to_struct_layout_info = [](const auto& struct_type_info) {
648 ✔
133
    typeart_struct_layout struct_layout;
324 ✔
134
    struct_layout.type_id      = struct_type_info.type_id;
324 ✔
135
    struct_layout.name         = struct_type_info.name.c_str();
324 ✔
136
    struct_layout.num_members  = struct_type_info.num_members;
324 ✔
137
    struct_layout.extent       = struct_type_info.extent;
324 ✔
138
    struct_layout.offsets      = &struct_type_info.offsets[0];
324 ✔
139
    struct_layout.member_types = &struct_type_info.member_types[0];
324 ✔
140
    struct_layout.count        = &struct_type_info.array_sizes[0];
324 ✔
141
    return struct_layout;
324 ✔
142
  };
324 ✔
143

144
  // Resolve type recursively, until the address matches exactly
145
  bool resolve{true};
324 ✔
146
  while (resolve) {
576 ✔
147
    const auto status_subtype_info = getSubTypeInfo(baseAddr, offset, to_struct_layout_info(*structInfo), &subType,
324 ✔
148
                                                    &subTypeBaseAddr, &subTypeOffset, &subTypeCount);
149

150
    if (status_subtype_info != TYPEART_OK) {
324 ✔
151
      return status_subtype_info;
72 ✔
152
    }
153

154
    baseAddr = subTypeBaseAddr;
252 ✔
155
    offset   = subTypeOffset;
252 ✔
156

157
    // Continue as long as there is a byte offset
158
    resolve = offset != 0;
252 ✔
159

160
    // Get layout of the nested struct
161
    if (resolve) {
252 ✔
162
      const auto status_struct_info = getStructInfo(subType, &structInfo);
×
163
      if (status_struct_info != TYPEART_OK) {
×
164
        return status_struct_info;
×
165
      }
166
    }
×
167
  }
324 ✔
168
  *type  = subType;
252 ✔
169
  *count = subTypeCount;
252 ✔
170
  return TYPEART_OK;
252 ✔
171
}
324 ✔
172

173
TypeResolution::TypeArtStatus TypeResolution::getTypeInfo(const void* addr, const void* basePtr,
7,527 ✔
174
                                                          const PointerInfo& ptrInfo, int* type, size_t* count) const {
175
  const int containing_type = ptrInfo.typeId;
7,527 ✔
176
  size_t containing_type_count{0};
7,527 ✔
177
  size_t internal_byte_offset{0};
7,527 ✔
178

179
  // First, retrieve the containing type
180
  TypeArtStatus status = getContainingTypeInfo(addr, basePtr, ptrInfo, &containing_type_count, &internal_byte_offset);
7,527 ✔
181
  if (status != TYPEART_OK) {
7,527 ✔
182
    if (status == TYPEART_UNKNOWN_ADDRESS) {
578 ✔
183
      runtime_recorder.incAddrMissing(addr);
578 ✔
184
    }
578 ✔
185
    return status;
578 ✔
186
  }
187

188
  // Check for exact address match
189
  if (internal_byte_offset == 0) {
6,949 ✔
190
    *type  = containing_type;
6,385 ✔
191
    *count = containing_type_count;
6,385 ✔
192
    return TYPEART_OK;
6,385 ✔
193
  }
194

195
  if (type_database.isBuiltinType(containing_type)) {
564 ✔
196
    // Address points to the middle of a builtin type
197
    return TYPEART_BAD_ALIGNMENT;
240 ✔
198
  }
199

200
  // Resolve struct recursively
201
  const auto* structInfo = type_database.getStructInfo(containing_type);
324 ✔
202
  if (structInfo != nullptr) {
324 ✔
203
    const void* containingTypeAddr = detail::add_byte_offset(addr, -std::ptrdiff_t(internal_byte_offset));
324 ✔
204
    return getTypeInfoInternal(containingTypeAddr, internal_byte_offset, *structInfo, type, count);
324 ✔
205
  }
324 ✔
206

207
  return TYPEART_INVALID_ID;
×
208
}
7,527 ✔
209

210
TypeResolution::TypeArtStatus TypeResolution::getContainingTypeInfo(const void* addr, const void* basePtr,
7,581 ✔
211
                                                                    const PointerInfo& ptrInfo, size_t* count,
212
                                                                    size_t* offset) const {
213
  const auto& basePtrInfo = ptrInfo;
7,581 ✔
214
  size_t typeSize         = type_database.getTypeSize(basePtrInfo.typeId);
7,581 ✔
215
  if (basePtrInfo.typeId == TYPEART_VOID || basePtrInfo.typeId == TYPEART_POINTER) {
7,581 ✔
216
    // typeSize = 1;
217
  }
108 ✔
218

219
  // Check for exact match -> no further checks and offsets calculations needed
220
  if (basePtr == addr) {
7,581 ✔
221
    *count  = ptrInfo.count;
6,001 ✔
222
    *offset = 0;
6,001 ✔
223
    return TYPEART_OK;
6,001 ✔
224
  }
225

226
  if (typeSize == 0) {
1,580 ✔
NEW
227
    return TYPEART_ERROR;
×
228
  }
229

230
  // The address points inside a known array
231
  const void* blockEnd = detail::add_byte_offset(basePtr, basePtrInfo.count * typeSize);
1,580 ✔
232

233
  // Ensure that the given address is in bounds and points to the start of an element
234
  if (addr >= blockEnd) {
1,580 ✔
235
    const std::ptrdiff_t byte_offset_to_base = detail::substract_pointer(addr, basePtr);
578 ✔
236

237
    const auto elements  = byte_offset_to_base / typeSize;
578 ✔
238
    const auto oob_index = elements - basePtrInfo.count + 1;
578 ✔
239
    LOG_WARNING("Out of bounds for the lookup: (" << debug::toString(addr, basePtrInfo)
578 ✔
240
                                                  << ") #Elements too far: " << oob_index);
241
    return TYPEART_UNKNOWN_ADDRESS;
578 ✔
242
  }
578 ✔
243

244
  assert(addr >= basePtr && "Error in base address computation");
2,004 ✔
245

246
  const std::ptrdiff_t addrDif = detail::substract_pointer(addr, basePtr);
1,002 ✔
247

248
  // Offset of the pointer w.r.t. the start of the containing type
249
  const size_t internalOffset = addrDif % typeSize;
1,002 ✔
250

251
  // Array index
252
  const size_t typeOffset = addrDif / typeSize;
1,002 ✔
253
  const size_t typeCount  = basePtrInfo.count - typeOffset;
1,002 ✔
254

255
  // Retrieve and return type information
256
  *count  = typeCount;
1,002 ✔
257
  *offset = internalOffset;
1,002 ✔
258
  return TYPEART_OK;
1,002 ✔
259
}
7,581 ✔
260

261
TypeResolution::TypeArtStatus TypeResolution::getStructInfo(int type_id, const StructTypeInfo** structInfo) const {
276 ✔
262
  // Requested ID must correspond to a struct
263
  if (!type_database.isStructType(type_id)) {
276 ✔
264
    return TYPEART_WRONG_KIND;
×
265
  }
266

267
  const auto* result = type_database.getStructInfo(type_id);
276 ✔
268

269
  if (result != nullptr) {
276 ✔
270
    *structInfo = result;
252 ✔
271
    return TYPEART_OK;
252 ✔
272
  }
273
  return TYPEART_INVALID_ID;
24 ✔
274
}
276 ✔
275

276
const TypeDB& TypeResolution::db() const {
888,605 ✔
277
  return type_database;
888,605 ✔
278
}
279

280
namespace detail {
281
inline typeart_status query_type(const void* addr, int* type, size_t* count) {
282
  auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr);
283
  typeart::RuntimeSystem::get().recorder.incUsedInRequest(addr);
284
  if (alloc) {
285
    return typeart::RuntimeSystem::get().typeResolution.getTypeInfo(addr, alloc->first, alloc->second, type, count);
286
  }
287
  return TYPEART_UNKNOWN_ADDRESS;
288
}
289

290
inline typeart_status query_type(const void* addr, typeart_type_info& info) {
7,711 ✔
291
  auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr);
7,711 ✔
292
  typeart::RuntimeSystem::get().recorder.incUsedInRequest(addr);
7,711 ✔
293
  if (alloc) {
7,711 ✔
294
    typeart_base_type_info base;
7,526 ✔
295
    base.address        = alloc->first;
7,526 ✔
296
    base.type_id        = alloc->second.typeId;
7,526 ✔
297
    base.count          = alloc->second.count;
7,526 ✔
298
    info.base_type_info = base;
7,526 ✔
299
    info.address        = addr;
7,526 ✔
300
    const auto result   = typeart::RuntimeSystem::get().typeResolution.getTypeInfo(addr, alloc->first, alloc->second,
7,526 ✔
301
                                                                                   &info.type_id, &info.count);
7,526 ✔
302
    return result;
7,526 ✔
303
  }
7,526 ✔
304
  return TYPEART_UNKNOWN_ADDRESS;
185 ✔
305
}
7,711 ✔
306

307
inline typeart_status query_struct_layout(int type_id, typeart_struct_layout* struct_layout) {
276 ✔
308
  const typeart::StructTypeInfo* struct_info;
276 ✔
309
  typeart_status status = typeart::RuntimeSystem::get().typeResolution.getStructInfo(type_id, &struct_info);
276 ✔
310
  if (status == TYPEART_OK) {
276 ✔
311
    struct_layout->type_id      = struct_info->type_id;
252 ✔
312
    struct_layout->name         = struct_info->name.c_str();
252 ✔
313
    struct_layout->num_members  = struct_info->num_members;
252 ✔
314
    struct_layout->extent       = struct_info->extent;
252 ✔
315
    struct_layout->offsets      = (struct_info->offsets).data();
252 ✔
316
    struct_layout->member_types = (struct_info->member_types).data();
252 ✔
317
    struct_layout->count        = (struct_info->array_sizes).data();
252 ✔
318
  } else {
252 ✔
319
    struct_layout->type_id      = std::numeric_limits<decltype(typeart_struct_layout::type_id)>::min();
24 ✔
320
    struct_layout->name         = "";
24 ✔
321
    struct_layout->num_members  = 0;
24 ✔
322
    struct_layout->extent       = 0;
24 ✔
323
    struct_layout->offsets      = nullptr;
24 ✔
324
    struct_layout->member_types = nullptr;
24 ✔
325
    struct_layout->count        = nullptr;
24 ✔
326
  }
327
  return status;
276 ✔
328
}
276 ✔
329

330
char* string2char(std::string_view src) {
36 ✔
331
  const void* ret_addr       = __builtin_return_address(0);
36 ✔
332
  const size_t source_length = src.size() + 1;  // +1 for '\0'
36 ✔
333
  char* string_copy          = (char*)malloc(sizeof(char) * source_length);
36 ✔
334

335
  if (string_copy == nullptr) {
36 ✔
336
    return nullptr;
×
337
  }
338

339
  typeart::RuntimeSystem::get().allocTracker.onAlloc(string_copy, TYPEART_CHAR_8, source_length, ret_addr);
36 ✔
340

341
  memcpy(string_copy, src.data(), source_length);
36 ✔
342

343
  return string_copy;
36 ✔
344
}
36 ✔
345

346
}  // namespace detail
347
}  // namespace typeart
348

349
/**
350
 * Runtime interface implementation
351
 *
352
 */
353

354
typeart_status typeart_get_type(const void* addr, typeart_type_info* base_type) {
7,712 ✔
355
  typeart::RTGuard guard;
7,712 ✔
356
  return typeart::detail::query_type(addr, *base_type);
7,712 ✔
357
}
7,712 ✔
358

359
typeart_status typeart_get_containing_type(typeart_type_info type, typeart_base_type_info* containing_type,
54 ✔
360
                                           size_t* byte_offset) {
361
  typeart::RTGuard guard;
54 ✔
362
  containing_type->type_id = type.base_type_info.type_id;
54 ✔
363
  containing_type->count   = type.base_type_info.count;
54 ✔
364
  containing_type->address = type.base_type_info.address;
54 ✔
365
  const typeart::PointerInfo info{type.base_type_info.type_id, type.base_type_info.count};
54 ✔
366
  const auto result = typeart::RuntimeSystem::get().typeResolution.getContainingTypeInfo(
60 ✔
367
      type.address, containing_type->address, info, &containing_type->count, byte_offset);
30 ✔
368

369
  return result;
30 ✔
370
}
30 ✔
371

372
typeart_status typeart_get_subtype(const typeart_struct_layout* container_layout, const void* base_addr, size_t offset,
48 ✔
373
                                   typeart_base_type_info* subtype_info, size_t* subtype_byte_offset) {
374
  typeart::RTGuard guard;
48 ✔
375
  auto status = typeart::RuntimeSystem::get().typeResolution.getSubTypeInfo(
96 ✔
376
      base_addr, offset, *container_layout, &subtype_info->type_id, &subtype_info->address, subtype_byte_offset,
48 ✔
377
      &subtype_info->count);
48 ✔
378
  return status;
48 ✔
379
}
48 ✔
380

381
typeart_status typeart_resolve_type_id(int type_id, typeart_struct_layout* struct_layout) {
276 ✔
382
  typeart::RTGuard guard;
276 ✔
383
  return typeart::detail::query_struct_layout(type_id, struct_layout);
276 ✔
384
}
276 ✔
385

386
typeart_status typeart_get_return_address(const void* addr, const void** return_addr) {
60 ✔
387
  typeart::RTGuard guard;
60 ✔
388
  auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr);
60 ✔
389

390
  if (alloc) {
60 ✔
391
    *return_addr = alloc.value().second.debug;
48 ✔
392
    return TYPEART_OK;
48 ✔
393
  }
394
  *return_addr = nullptr;
12 ✔
395
  return TYPEART_UNKNOWN_ADDRESS;
12 ✔
396
}
60 ✔
397

398
typeart_status_t typeart_get_source_location(const void* addr, char** file, char** function, char** line) {
12 ✔
399
  using namespace typeart::detail;
400
  typeart::RTGuard guard;
12 ✔
401

402
  auto source_loc = typeart::SourceLocation::create(addr);
12 ✔
403

404
  if (source_loc) {
12 ✔
405
    *file     = string2char(source_loc->file);
12 ✔
406
    *function = string2char(source_loc->function);
12 ✔
407
    *line     = string2char(source_loc->line);
12 ✔
408

409
    if (*file == nullptr || *function == nullptr || *line == nullptr) {
12 ✔
410
      return TYPEART_ERROR;
×
411
    }
412

413
    return TYPEART_OK;
12 ✔
414
  }
415

416
  return TYPEART_UNKNOWN_ADDRESS;
×
417
}
12 ✔
418

419
const char* typeart_get_type_name(int type_id) {
5,700 ✔
420
  typeart::RTGuard guard;
5,700 ✔
421
  return typeart::RuntimeSystem::get().typeResolution.db().getTypeName(type_id).c_str();
5,700 ✔
422
}
5,700 ✔
423

424
bool typeart_is_vector_type(int type_id) {
24 ✔
425
  typeart::RTGuard guard;
24 ✔
426
  return typeart::RuntimeSystem::get().typeResolution.db().isVectorType(type_id);
24 ✔
427
}
24 ✔
428

429
bool typeart_is_valid_type(int type_id) {
24 ✔
430
  typeart::RTGuard guard;
24 ✔
431
  return typeart::RuntimeSystem::get().typeResolution.db().isValid(type_id);
24 ✔
432
}
24 ✔
433

434
bool typeart_is_reserved_type(int type_id) {
24 ✔
435
  typeart::RTGuard guard;
24 ✔
436
  return typeart::RuntimeSystem::get().typeResolution.db().isReservedType(type_id);
24 ✔
437
}
24 ✔
438

439
bool typeart_is_builtin_type(int type_id) {
24 ✔
440
  typeart::RTGuard guard;
24 ✔
441
  return typeart::RuntimeSystem::get().typeResolution.db().isBuiltinType(type_id);
24 ✔
442
}
24 ✔
443

444
bool typeart_is_struct_type(int type_id) {
24 ✔
445
  typeart::RTGuard guard;
24 ✔
446
  return typeart::RuntimeSystem::get().typeResolution.db().isStructType(type_id);
24 ✔
447
}
24 ✔
448

449
bool typeart_is_userdefined_type(int type_id) {
24 ✔
450
  typeart::RTGuard guard;
24 ✔
451
  return typeart::RuntimeSystem::get().typeResolution.db().isUserDefinedType(type_id);
24 ✔
452
}
24 ✔
453

NEW
454
bool typeart_is_union(int type_id) {
×
NEW
455
  typeart::RTGuard guard;
×
NEW
456
  return typeart::RuntimeSystem::get().typeResolution.db().isUnion(type_id);
×
NEW
457
}
×
458

459
size_t typeart_get_type_size(int type_id) {
24 ✔
460
  typeart::RTGuard guard;
24 ✔
461
  return typeart::RuntimeSystem::get().typeResolution.db().getTypeSize(type_id);
24 ✔
462
}
24 ✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc