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

tudasc / TypeART / 15070187546

16 May 2025 01:57PM UTC coverage: 88.896% (+0.009%) from 88.887%
15070187546

push

github

web-flow
Refactor source location interface (#170)

17 of 18 new or added lines in 1 file covered. (94.44%)

4235 of 4764 relevant lines covered (88.9%)

260823.36 hits per line

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

93.77
/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 <charconv>
27
#include <cstddef>
28
#include <cstdint>
29
#include <utility>
30
#include <vector>
31

32
namespace typeart {
33

34
namespace detail {
35

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

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

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

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

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

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

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

69
}  // namespace detail
70

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

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

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

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

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

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

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

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

118
  return TYPEART_OK;
264✔
119
}
372✔
120

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

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

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

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

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

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

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

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

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

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

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

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

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

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

208
  return TYPEART_INVALID_ID;
×
209
}
7,543✔
210

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

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

227
  if (typeSize == 0) {
1,585✔
228
    return TYPEART_ERROR;
×
229
  }
230

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

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

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

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

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

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

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

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

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

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

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

277
const TypeDB& TypeResolution::db() const {
883,490✔
278
  return type_database;
883,490✔
279
}
280

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

291
inline typeart_status query_type(const void* addr, typeart_type_info& info) {
7,690✔
292
  auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr);
7,690✔
293
  typeart::RuntimeSystem::get().recorder.incUsedInRequest(addr);
7,690✔
294
  if (alloc) {
7,690✔
295
    typeart_base_type_info base;
7,545✔
296
    base.address        = alloc->first;
7,545✔
297
    base.type_id        = alloc->second.typeId;
7,545✔
298
    base.count          = alloc->second.count;
7,545✔
299
    info.base_type_info = base;
7,545✔
300
    info.address        = addr;
7,545✔
301

302
    typeart::RuntimeSystem::get().recorder.incTypeQuery(base.type_id);
7,545✔
303

304
    const auto result = typeart::RuntimeSystem::get().typeResolution.getTypeInfo(addr, alloc->first, alloc->second,
7,545✔
305
                                                                                 &info.type_id, &info.count);
7,545✔
306
    return result;
7,545✔
307
  }
7,545✔
308
  return TYPEART_UNKNOWN_ADDRESS;
145✔
309
}
7,690✔
310

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

334
char* string2char(std::string_view src) {
24✔
335
  // const void* ret_addr       = __builtin_return_address(0);
336
  const size_t source_length = src.size() + 1;  // +1 for '\0'
24✔
337
  char* string_copy          = (char*)malloc(sizeof(char) * source_length);
24✔
338

339
  if (string_copy == nullptr) {
24✔
340
    return nullptr;
×
341
  }
342

343
  // typeart::RuntimeSystem::get().allocTracker.onAlloc(string_copy, TYPEART_CHAR_8, source_length, ret_addr);
344

345
  memcpy(string_copy, src.data(), source_length);
24✔
346

347
  return string_copy;
24✔
348
}
24✔
349

350
}  // namespace detail
351
}  // namespace typeart
352

353
/**
354
 * Runtime interface implementation
355
 *
356
 */
357

358
typeart_status typeart_get_type(const void* addr, typeart_type_info* base_type) {
7,690✔
359
  typeart::RTGuard guard;
7,690✔
360
  return typeart::detail::query_type(addr, *base_type);
7,690✔
361
}
7,690✔
362

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

373
  return result;
30✔
374
}
30✔
375

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

385
typeart_status typeart_resolve_type_id(int type_id, typeart_struct_layout* struct_layout) {
276✔
386
  typeart::RTGuard guard;
276✔
387
  return typeart::detail::query_struct_layout(type_id, struct_layout);
276✔
388
}
276✔
389

390
typeart_status typeart_get_return_address(const void* addr, const void** return_addr) {
24✔
391
  typeart::RTGuard guard;
24✔
392
  auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr);
24✔
393

394
  if (alloc) {
24✔
395
    *return_addr = alloc.value().second.debug;
12✔
396
    return TYPEART_OK;
12✔
397
  }
398
  *return_addr = nullptr;
12✔
399
  return TYPEART_UNKNOWN_ADDRESS;
12✔
400
}
24✔
401

402
// typeart_status_t typeart_get_source_location(const void* addr, char** file, char** function, char** line) {
403
//   using namespace typeart::detail;
404
//   typeart::RTGuard guard;
405

406
//   auto source_loc = typeart::SourceLocation::create(addr);
407

408
//   if (source_loc) {
409
//     *file     = string2char(source_loc->file);
410
//     *function = string2char(source_loc->function);
411
//     *line     = string2char(source_loc->line);
412

413
//     if (*file == nullptr || *function == nullptr || *line == nullptr) {
414
//       return TYPEART_ERROR;
415
//     }
416

417
//     return TYPEART_OK;
418
//   }
419

420
//   return TYPEART_UNKNOWN_ADDRESS;
421
// }
422

423
typeart_status_t typeart_get_source_location(const void* addr, typeart_source_location* source_location) {
12✔
424
  using namespace typeart::detail;
425
  typeart::RTGuard guard;
12✔
426

427
  auto source_loc = typeart::SourceLocation::create(addr);
12✔
428

429
  if (source_loc) {
12✔
430
    source_location->file     = string2char(source_loc->file);
12✔
431
    source_location->function = string2char(source_loc->function);
12✔
432
    source_location->line     = 0;
12✔
433
    const auto& line          = source_loc->line;
12✔
434
    auto [ptr, ec]            = std::from_chars(line.data(), line.data() + line.size(), source_location->line);
24✔
435

436
    if (source_location->file == nullptr || source_location->function == nullptr || ec != std::errc{}) {
12✔
437
      return TYPEART_ERROR;
×
438
    }
439

440
    return TYPEART_OK;
12✔
441
  }
12✔
442

443
  return TYPEART_UNKNOWN_ADDRESS;
×
444
}
12✔
445

446
typeart_status_t typeart_free_source_location(typeart_source_location* source_location) {
12✔
447
  using namespace typeart::detail;
448
  typeart::RTGuard guard;
12✔
449

450
  if (source_location == nullptr) {
12✔
NEW
451
    return TYPEART_ERROR;
×
452
  }
453

454
  free(source_location->file);
12✔
455
  free(source_location->function);
12✔
456

457
  source_location->file     = nullptr;
12✔
458
  source_location->function = nullptr;
12✔
459
  source_location->line     = 0;
12✔
460

461
  return TYPEART_OK;
12✔
462
}
12✔
463

464
const char* typeart_get_type_name(int type_id) {
6,095✔
465
  typeart::RTGuard guard;
6,095✔
466
  return typeart::RuntimeSystem::get().typeResolution.db().getTypeName(type_id).c_str();
6,095✔
467
}
6,095✔
468

469
bool typeart_is_vector_type(int type_id) {
24✔
470
  typeart::RTGuard guard;
24✔
471
  return typeart::RuntimeSystem::get().typeResolution.db().isVectorType(type_id);
24✔
472
}
24✔
473

474
bool typeart_is_valid_type(int type_id) {
24✔
475
  typeart::RTGuard guard;
24✔
476
  return typeart::RuntimeSystem::get().typeResolution.db().isValid(type_id);
24✔
477
}
24✔
478

479
bool typeart_is_reserved_type(int type_id) {
24✔
480
  typeart::RTGuard guard;
24✔
481
  return typeart::RuntimeSystem::get().typeResolution.db().isReservedType(type_id);
24✔
482
}
24✔
483

484
bool typeart_is_builtin_type(int type_id) {
24✔
485
  typeart::RTGuard guard;
24✔
486
  return typeart::RuntimeSystem::get().typeResolution.db().isBuiltinType(type_id);
24✔
487
}
24✔
488

489
bool typeart_is_struct_type(int type_id) {
24✔
490
  typeart::RTGuard guard;
24✔
491
  return typeart::RuntimeSystem::get().typeResolution.db().isStructType(type_id);
24✔
492
}
24✔
493

494
bool typeart_is_userdefined_type(int type_id) {
24✔
495
  typeart::RTGuard guard;
24✔
496
  return typeart::RuntimeSystem::get().typeResolution.db().isUserDefinedType(type_id);
24✔
497
}
24✔
498

499
bool typeart_is_union(int type_id) {
×
500
  typeart::RTGuard guard;
×
501
  return typeart::RuntimeSystem::get().typeResolution.db().isUnion(type_id);
×
502
}
×
503

504
size_t typeart_get_type_size(int type_id) {
24✔
505
  typeart::RTGuard guard;
24✔
506
  return typeart::RuntimeSystem::get().typeResolution.db().getTypeSize(type_id);
24✔
507
}
24✔
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