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

tudasc / TypeART / 12974719593

26 Jan 2025 12:40PM UTC coverage: 87.511%. First build
12974719593

Pull #153

github

web-flow
Merge 467600c61 into 9a5045231
Pull Request #153: Silence warnings

148 of 153 new or added lines in 15 files covered. (96.73%)

3959 of 4524 relevant lines covered (87.51%)

111873.46 hits per line

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

95.26
/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) {
1,057✔
37
  assert(addr != nullptr);
1,057✔
38
  return static_cast<const P*>(static_cast<const char*>(addr) + offset);
1,057✔
39
}
40

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

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

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

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

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

61
  size_t member_index{0};
156✔
62
  while (member_index < (num_members - 1) && offset >= struct_offsets[member_index + 1]) {
339✔
63
    ++member_index;
183✔
64
  }
65
  return member_index;
156✔
66
}
162✔
67

68
}  // namespace detail
69

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

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

81
  if (offset >= containerInfo.extent) {
168✔
82
    return TYPEART_BAD_OFFSET;
6✔
83
  }
84

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

90
  const size_t internalOffset   = offset - baseOffset;
162✔
91
  const size_t typeSize         = type_database.getTypeSize(memberType);
162✔
92
  const size_t offsetInTypeSize = internalOffset / typeSize;
162✔
93
  const size_t newOffset        = internalOffset % typeSize;
162✔
94

95
  // If newOffset != 0, the subtype cannot be atomic, i.e. must be a struct
96
  if (newOffset != 0) {
162✔
97
    if (type_database.isReservedType(memberType)) {
12✔
98
      return TYPEART_BAD_ALIGNMENT;
12✔
99
    }
100
  }
×
101

102
  // Ensure that the array index is in bounds
103
  if (offsetInTypeSize >= containerInfo.count[memberIndex]) {
150✔
104
    // Address points to padding
105
    return TYPEART_BAD_ALIGNMENT;
24✔
106
  }
107

108
  *subType         = memberType;
126✔
109
  *subTypeBaseAddr = detail::add_byte_offset(baseAddr, baseOffset);
126✔
110
  *subTypeOffset   = newOffset;
126✔
111
  *subTypeCount    = containerInfo.count[memberIndex] - offsetInTypeSize;
126✔
112

113
  return TYPEART_OK;
126✔
114
}
174✔
115

116
TypeResolution::TypeArtStatus TypeResolution::getTypeInfoInternal(const void* baseAddr, size_t offset,
150✔
117
                                                                  const StructTypeInfo& containerInfo, int* type,
118
                                                                  size_t* count) const {
119
  assert(offset < containerInfo.extent && "Something went wrong with the base address computation");
300✔
120

121
  int subType{-1};
150✔
122
  const void* subTypeBaseAddr;
150✔
123
  size_t subTypeOffset{0};
150✔
124
  size_t subTypeCount{0};
150✔
125

126
  const StructTypeInfo* structInfo = &containerInfo;
150✔
127

128
  const auto to_struct_layout_info = [](const auto& struct_type_info) {
300✔
129
    typeart_struct_layout struct_layout;
150✔
130
    struct_layout.type_id      = struct_type_info.type_id;
150✔
131
    struct_layout.name         = struct_type_info.name.c_str();
150✔
132
    struct_layout.num_members  = struct_type_info.num_members;
150✔
133
    struct_layout.extent       = struct_type_info.extent;
150✔
134
    struct_layout.offsets      = &struct_type_info.offsets[0];
150✔
135
    struct_layout.member_types = &struct_type_info.member_types[0];
150✔
136
    struct_layout.count        = &struct_type_info.array_sizes[0];
150✔
137
    return struct_layout;
150✔
138
  };
150✔
139

140
  // Resolve type recursively, until the address matches exactly
141
  bool resolve{true};
150✔
142
  while (resolve) {
270✔
143
    const auto status_subtype_info = getSubTypeInfo(baseAddr, offset, to_struct_layout_info(*structInfo), &subType,
150✔
144
                                                    &subTypeBaseAddr, &subTypeOffset, &subTypeCount);
145

146
    if (status_subtype_info != TYPEART_OK) {
150✔
147
      return status_subtype_info;
30✔
148
    }
149

150
    baseAddr = subTypeBaseAddr;
120✔
151
    offset   = subTypeOffset;
120✔
152

153
    // Continue as long as there is a byte offset
154
    resolve = offset != 0;
120✔
155

156
    // Get layout of the nested struct
157
    if (resolve) {
120✔
158
      const auto status_struct_info = getStructInfo(subType, &structInfo);
×
159
      if (status_struct_info != TYPEART_OK) {
×
160
        return status_struct_info;
×
161
      }
162
    }
×
163
  }
150✔
164
  *type  = subType;
120✔
165
  *count = subTypeCount;
120✔
166
  return TYPEART_OK;
120✔
167
}
150✔
168

169
TypeResolution::TypeArtStatus TypeResolution::getTypeInfo(const void* addr, const void* basePtr,
3,797✔
170
                                                          const PointerInfo& ptrInfo, int* type, size_t* count) const {
171
  const int containing_type = ptrInfo.typeId;
3,797✔
172
  size_t containing_type_count{0};
3,797✔
173
  size_t internal_byte_offset{0};
3,797✔
174

175
  // First, retrieve the containing type
176
  TypeArtStatus status = getContainingTypeInfo(addr, basePtr, ptrInfo, &containing_type_count, &internal_byte_offset);
3,797✔
177
  if (status != TYPEART_OK) {
3,797✔
178
    if (status == TYPEART_UNKNOWN_ADDRESS) {
289✔
179
      runtime_recorder.incAddrMissing(addr);
289✔
180
    }
289✔
181
    return status;
289✔
182
  }
183

184
  // Check for exact address match
185
  if (internal_byte_offset == 0) {
3,508✔
186
    *type  = containing_type;
3,238✔
187
    *count = containing_type_count;
3,238✔
188
    return TYPEART_OK;
3,238✔
189
  }
190

191
  if (type_database.isBuiltinType(containing_type)) {
270✔
192
    // Address points to the middle of a builtin type
193
    return TYPEART_BAD_ALIGNMENT;
120✔
194
  }
195

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

203
  return TYPEART_INVALID_ID;
×
204
}
3,797✔
205

206
TypeResolution::TypeArtStatus TypeResolution::getContainingTypeInfo(const void* addr, const void* basePtr,
3,833✔
207
                                                                    const PointerInfo& ptrInfo, size_t* count,
208
                                                                    size_t* offset) const {
209
  const auto& basePtrInfo = ptrInfo;
3,833✔
210
  size_t typeSize         = type_database.getTypeSize(basePtrInfo.typeId);
3,833✔
211

212
  // Check for exact match -> no further checks and offsets calculations needed
213
  if (basePtr == addr) {
3,833✔
214
    *count  = ptrInfo.count;
3,052✔
215
    *offset = 0;
3,052✔
216
    return TYPEART_OK;
3,052✔
217
  }
218

219
  // The address points inside a known array
220
  const void* blockEnd = detail::add_byte_offset(basePtr, basePtrInfo.count * typeSize);
781✔
221

222
  // Ensure that the given address is in bounds and points to the start of an element
223
  if (addr >= blockEnd) {
781✔
224
    const std::ptrdiff_t byte_offset_to_base = detail::substract_pointer(addr, basePtr);
289✔
225

226
    const auto elements  = byte_offset_to_base / typeSize;
289✔
227
    const auto oob_index = elements - basePtrInfo.count + 1;
289✔
228
    LOG_WARNING("Out of bounds for the lookup: (" << debug::toString(addr, basePtrInfo)
289✔
229
                                                  << ") #Elements too far: " << oob_index);
230
    return TYPEART_UNKNOWN_ADDRESS;
289✔
231
  }
289✔
232

233
  assert(addr >= basePtr && "Error in base address computation");
984✔
234

235
  const std::ptrdiff_t addrDif = detail::substract_pointer(addr, basePtr);
492✔
236

237
  // Offset of the pointer w.r.t. the start of the containing type
238
  const size_t internalOffset = addrDif % typeSize;
492✔
239

240
  // Array index
241
  const size_t typeOffset = addrDif / typeSize;
492✔
242
  const size_t typeCount  = basePtrInfo.count - typeOffset;
492✔
243

244
  // Retrieve and return type information
245
  *count  = typeCount;
492✔
246
  *offset = internalOffset;
492✔
247
  return TYPEART_OK;
492✔
248
}
3,833✔
249

250
TypeResolution::TypeArtStatus TypeResolution::getStructInfo(int type_id, const StructTypeInfo** structInfo) const {
144✔
251
  // Requested ID must correspond to a struct
252
  if (!type_database.isStructType(type_id)) {
144✔
NEW
253
    return TYPEART_WRONG_KIND;
×
254
  }
255

256
  const auto* result = type_database.getStructInfo(type_id);
144✔
257

258
  if (result != nullptr) {
144✔
259
    *structInfo = result;
132✔
260
    return TYPEART_OK;
132✔
261
  }
262
  return TYPEART_INVALID_ID;
12✔
263
}
144✔
264

265
const TypeDB& TypeResolution::db() const {
445,002✔
266
  return type_database;
445,002✔
267
}
268

269
namespace detail {
270
inline typeart_status query_type(const void* addr, int* type, size_t* count) {
3,852✔
271
  auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr);
3,852✔
272
  typeart::RuntimeSystem::get().recorder.incUsedInRequest(addr);
3,852✔
273
  if (alloc) {
3,852✔
274
    return typeart::RuntimeSystem::get().typeResolution.getTypeInfo(addr, alloc->first, alloc->second, type, count);
3,797✔
275
  }
276
  return TYPEART_UNKNOWN_ADDRESS;
55✔
277
}
3,852✔
278

279
inline typeart_status query_struct_layout(int type_id, typeart_struct_layout* struct_layout) {
144✔
280
  const typeart::StructTypeInfo* struct_info;
144✔
281
  typeart_status status = typeart::RuntimeSystem::get().typeResolution.getStructInfo(type_id, &struct_info);
144✔
282
  if (status == TYPEART_OK) {
144✔
283
    struct_layout->type_id      = struct_info->type_id;
132✔
284
    struct_layout->name         = struct_info->name.c_str();
132✔
285
    struct_layout->num_members  = struct_info->num_members;
132✔
286
    struct_layout->extent       = struct_info->extent;
132✔
287
    struct_layout->offsets      = &struct_info->offsets[0];
132✔
288
    struct_layout->member_types = &struct_info->member_types[0];
132✔
289
    struct_layout->count        = &struct_info->array_sizes[0];
132✔
290
  } else {
132✔
291
    struct_layout->type_id      = std::numeric_limits<decltype(typeart_struct_layout::type_id)>::min();
12✔
292
    struct_layout->name         = "";
12✔
293
    struct_layout->num_members  = 0;
12✔
294
    struct_layout->extent       = 0;
12✔
295
    struct_layout->offsets      = nullptr;
12✔
296
    struct_layout->member_types = nullptr;
12✔
297
    struct_layout->count        = nullptr;
12✔
298
  }
299
  return status;
144✔
300
}
144✔
301

302
char* string2char(std::string_view src) {
18✔
303
  const void* ret_addr       = __builtin_return_address(0);
18✔
304
  const size_t source_length = src.size() + 1;  // +1 for '\0'
18✔
305
  char* string_copy          = (char*)malloc(sizeof(char) * source_length);
18✔
306

307
  if (string_copy == nullptr) {
18✔
308
    return nullptr;
×
309
  }
310

311
  typeart::RuntimeSystem::get().allocTracker.onAlloc(string_copy, TYPEART_CHAR_8, source_length, ret_addr);
18✔
312

313
  memcpy(string_copy, src.data(), source_length);
18✔
314

315
  return string_copy;
18✔
316
}
18✔
317

318
}  // namespace detail
319
}  // namespace typeart
320

321
/**
322
 * Runtime interface implementation
323
 *
324
 */
325

326
typeart_status typeart_get_type(const void* addr, int* type_id, size_t* count) {
3,804✔
327
  typeart::RTGuard guard;
3,804✔
328
  return typeart::detail::query_type(addr, type_id, count);
3,804✔
329
}
3,804✔
330

331
typeart_status typeart_get_type_length(const void* addr, size_t* count) {
6✔
332
  typeart::RTGuard guard;
6✔
333
  int type{0};
6✔
334
  return typeart::detail::query_type(addr, &type, count);
6✔
335
}
6✔
336

337
typeart_status typeart_get_type_id(const void* addr, int* type_id) {
36✔
338
  typeart::RTGuard guard;
36✔
339
  size_t count{0};
36✔
340
  return typeart::detail::query_type(addr, type_id, &count);
36✔
341
}
36✔
342

343
typeart_status typeart_get_containing_type(const void* addr, int* type_id, size_t* count, const void** base_address,
36✔
344
                                           size_t* byte_offset) {
345
  typeart::RTGuard guard;
36✔
346
  auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr);
36✔
347
  if (alloc) {
36✔
348
    //    auto& allocVal = alloc.value();
349
    *type_id      = alloc->second.typeId;
36✔
350
    *base_address = alloc->first;
36✔
351
    return typeart::RuntimeSystem::get().typeResolution.getContainingTypeInfo(addr, alloc->first, alloc->second, count,
36✔
352
                                                                              byte_offset);
36✔
353
  }
354
  return TYPEART_UNKNOWN_ADDRESS;
×
355
}
36✔
356

357
typeart_status typeart_get_subtype(const void* base_addr, size_t offset, const typeart_struct_layout* container_layout,
24✔
358
                                   int* subtype_id, const void** subtype_base_addr, size_t* subtype_byte_offset,
359
                                   size_t* subtype_count) {
360
  typeart::RTGuard guard;
24✔
361
  auto status = typeart::RuntimeSystem::get().typeResolution.getSubTypeInfo(
24✔
362
      base_addr, offset, *container_layout, subtype_id, subtype_base_addr, subtype_byte_offset, subtype_count);
24✔
363
  return status;
24✔
364
}
24✔
365

366
typeart_status typeart_resolve_type_addr(const void* addr, typeart_struct_layout* struct_layout) {
6✔
367
  typeart::RTGuard guard;
6✔
368
  int type_id{0};
6✔
369
  size_t size{0};
6✔
370
  auto status = typeart::detail::query_type(addr, &type_id, &size);
6✔
371
  if (status != TYPEART_OK) {
6✔
372
    return status;
×
373
  }
374
  return typeart::detail::query_struct_layout(type_id, struct_layout);
6✔
375
}
6✔
376

377
typeart_status typeart_resolve_type_id(int type_id, typeart_struct_layout* struct_layout) {
138✔
378
  typeart::RTGuard guard;
138✔
379
  return typeart::detail::query_struct_layout(type_id, struct_layout);
138✔
380
}
138✔
381

382
typeart_status typeart_get_return_address(const void* addr, const void** return_addr) {
30✔
383
  typeart::RTGuard guard;
30✔
384
  auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr);
30✔
385

386
  if (alloc) {
30✔
387
    *return_addr = alloc.value().second.debug;
24✔
388
    return TYPEART_OK;
24✔
389
  }
390
  *return_addr = nullptr;
6✔
391
  return TYPEART_UNKNOWN_ADDRESS;
6✔
392
}
30✔
393

394
typeart_status_t typeart_get_source_location(const void* addr, char** file, char** function, char** line) {
6✔
395
  using namespace typeart::detail;
396
  typeart::RTGuard guard;
6✔
397

398
  auto source_loc = typeart::SourceLocation::create(addr);
6✔
399

400
  if (source_loc) {
6✔
401
    *file     = string2char(source_loc->file);
6✔
402
    *function = string2char(source_loc->function);
6✔
403
    *line     = string2char(source_loc->line);
6✔
404

405
    if (*file == nullptr || *function == nullptr || *line == nullptr) {
6✔
406
      return TYPEART_ERROR;
×
407
    }
408

409
    return TYPEART_OK;
6✔
410
  }
411

412
  return TYPEART_UNKNOWN_ADDRESS;
×
413
}
6✔
414

415
const char* typeart_get_type_name(int type_id) {
2,748✔
416
  typeart::RTGuard guard;
2,748✔
417
  return typeart::RuntimeSystem::get().typeResolution.db().getTypeName(type_id).c_str();
2,748✔
418
}
2,748✔
419

420
bool typeart_is_vector_type(int type_id) {
12✔
421
  typeart::RTGuard guard;
12✔
422
  return typeart::RuntimeSystem::get().typeResolution.db().isVectorType(type_id);
12✔
423
}
12✔
424

425
bool typeart_is_valid_type(int type_id) {
12✔
426
  typeart::RTGuard guard;
12✔
427
  return typeart::RuntimeSystem::get().typeResolution.db().isValid(type_id);
12✔
428
}
12✔
429

430
bool typeart_is_reserved_type(int type_id) {
12✔
431
  typeart::RTGuard guard;
12✔
432
  return typeart::RuntimeSystem::get().typeResolution.db().isReservedType(type_id);
12✔
433
}
12✔
434

435
bool typeart_is_builtin_type(int type_id) {
12✔
436
  typeart::RTGuard guard;
12✔
437
  return typeart::RuntimeSystem::get().typeResolution.db().isBuiltinType(type_id);
12✔
438
}
12✔
439

440
bool typeart_is_struct_type(int type_id) {
12✔
441
  typeart::RTGuard guard;
12✔
442
  return typeart::RuntimeSystem::get().typeResolution.db().isStructType(type_id);
12✔
443
}
12✔
444

445
bool typeart_is_userdefined_type(int type_id) {
12✔
446
  typeart::RTGuard guard;
12✔
447
  return typeart::RuntimeSystem::get().typeResolution.db().isUserDefinedType(type_id);
12✔
448
}
12✔
449

450
size_t typeart_get_type_size(int type_id) {
12✔
451
  typeart::RTGuard guard;
12✔
452
  return typeart::RuntimeSystem::get().typeResolution.db().getTypeSize(type_id);
12✔
453
}
12✔
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