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

tudasc / TypeART / 24397737785

14 Apr 2026 12:00PM UTC coverage: 90.264% (+1.3%) from 88.924%
24397737785

Pull #187

github

web-flow
Merge 278119205 into de3bc148a
Pull Request #187: Release v2.2

880 of 935 new or added lines in 31 files covered. (94.12%)

17 existing lines in 3 files now uncovered.

4886 of 5413 relevant lines covered (90.26%)

38873.79 hits per line

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

82.05
/lib/support/System.cpp
1
// TypeART library
2
//
3
// Copyright (c) 2017-2026 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 "System.h"
14

15
#include <cstdio>
16
#include <dlfcn.h>
17
#include <filesystem>
18
#include <link.h>  // For link_map, see SourceLocation::create
19
#include <memory>
20
#include <sstream>
21
#include <sys/resource.h>
22

23
namespace typeart {
24
namespace system {
25

26
Process::Process() {
21✔
27
  self_exe = std::filesystem::canonical("/proc/self/exe");
21✔
28
}
21✔
29

30
const std::string& Process::exe() const {
21✔
31
  return self_exe;
21✔
32
}
33

34
const Process& Process::get() {
21✔
35
  static Process self;
21✔
36
  return self;
21✔
37
}
×
38

UNCOV
39
long Process::getMaxRSS() {
×
UNCOV
40
  rusage proc;
×
UNCOV
41
  getrusage(RUSAGE_SELF, &proc);
×
42

UNCOV
43
  return proc.ru_maxrss;
×
UNCOV
44
}
×
45

46
class CommandPipe {
63✔
47
  using UniqueFile = std::unique_ptr<FILE, int (*)(FILE*)>;
48
  UniqueFile command_;
49

50
  explicit CommandPipe(UniqueFile command);
51

52
 public:
53
  static std::optional<CommandPipe> create(std::string_view command);
54

55
  [[nodiscard]] std::string nextLine() const;
56
};
57

58
CommandPipe::CommandPipe(CommandPipe::UniqueFile command) : command_(std::move(command)) {
21✔
59
}
21✔
60

61
std::optional<CommandPipe> CommandPipe::create(std::string_view command) {
21✔
62
  UniqueFile comm(popen(command.data(), "r"), &pclose);
21✔
63

64
  if (!comm) {
21✔
65
    return {};
×
66
  }
67

68
  return CommandPipe{std::move(comm)};
21✔
69
}
21✔
70

71
std::string CommandPipe::nextLine() const {
42✔
72
  char* buffer{nullptr};
42✔
73
  size_t buffer_length{0};
42✔
74
  std::string result;
42✔
75

76
  if (getline(&buffer, &buffer_length, command_.get()) != -1) {
42✔
77
    result = buffer;
42✔
78
  }
42✔
79

80
  if (buffer != nullptr) {
42✔
81
    free(buffer);
42✔
82
  }
42✔
83

84
  if (!result.empty()) {
42✔
85
    result.resize(result.size() - 1);  // remove \n
42✔
86
  }
42✔
87

88
  return result;
42✔
89
}
42✔
90

91
bool test_command(std::string_view command, std::string_view test_arg) {
42✔
92
  const auto available = [](const std::string_view command_to_try) -> bool {
84✔
93
    constexpr int command_not_found{127};
42✔
94
    auto* proc        = popen(command_to_try.data(), "r");
42✔
95
    const int ret_val = pclose(proc);
42✔
96
    return WEXITSTATUS(ret_val) != command_not_found;
42✔
97
  };
42✔
98

99
  std::ostringstream os;
42✔
100
  os << command << " " << test_arg;
42✔
101

102
  const bool avail = available(os.str());
42✔
103
  return avail;
42✔
104
}
42✔
105

106
class SourceLocHelper {
107
  bool has_addr2line{false};
21✔
108
  bool has_llvmsymbolizer{false};
21✔
109

110
  SourceLocHelper() {
21✔
111
    has_addr2line      = test_command("addr2line");
21✔
112
    has_llvmsymbolizer = test_command("llvm-symbolizer");
21✔
113
  }
21✔
114

115
 public:
116
  static const SourceLocHelper& get() {
21✔
117
    static SourceLocHelper helper;
21✔
118
    return helper;
21✔
119
  }
×
120

121
  [[nodiscard]] bool hasAddr2line() const {
21✔
122
    return has_addr2line;
21✔
123
  }
124

125
  [[nodiscard]] bool hasLLVMSymbolizer() const {
21✔
126
    return has_llvmsymbolizer;
21✔
127
  }
128
};
129

130
struct RemoveEnvInScope {
131
  explicit RemoveEnvInScope(std::string_view var_name) : var_name_(var_name) {
21✔
132
    old_val_ = [](std::string_view env_var_name) {
63✔
133
      const auto* env_data = getenv(env_var_name.data());
21✔
134
      if (env_data) {
21✔
135
        return env_data;
×
136
      }
137
      return "";
21✔
138
    }(var_name);
42✔
139

140
    if (!old_val_.empty()) {
21✔
141
      setenv(var_name.data(), "", true);
×
142
    }
×
143
  }
21✔
144

145
  ~RemoveEnvInScope() {
21✔
146
    if (!old_val_.empty()) {
21✔
147
      setenv(var_name_.data(), old_val_.data(), true);
×
148
    }
×
149
  }
21✔
150

151
 private:
152
  std::string_view var_name_;
153
  std::string_view old_val_;
154
};
155

156
}  // namespace system
157

158
std::optional<SourceLocation> SourceLocation::create(const void* raw_address, intptr_t offset_ptr) {
21✔
159
  // Preload might cause infinite recursion, hence temp. remove this flag in this scope only:
160
  system::RemoveEnvInScope rm_preload_var{"LD_PRELOAD"};
21✔
161

162
  const auto pipe = [](const void* paddr, intptr_t offset_ptr_value) -> std::optional<system::CommandPipe> {
63✔
163
    const auto& sloc_helper = system::SourceLocHelper::get();
21✔
164
    const auto& proc        = system::Process::get();
21✔
165

166
    // FIXME: Inst Pointer points one past what we need with __built_in_return_addr(0), hacky way to fix:
167
    const auto addr = [](const auto address_to_offset) {  //  reinterpret_cast<intptr_t>(paddr) - offset_ptr;
42✔
168
      // Transform addr to VMA Addr:
169
      Dl_info info;
21✔
170
      link_map* link_map;
21✔
171
      dladdr1((void*)address_to_offset, &info, (void**)&link_map, RTLD_DL_LINKMAP);
21✔
172
      return address_to_offset - link_map->l_addr;
21✔
173
    }(reinterpret_cast<intptr_t>(paddr) - offset_ptr_value);
42✔
174

175
    if (sloc_helper.hasLLVMSymbolizer()) {
21✔
176
      std::ostringstream command;
×
177
      command << "llvm-symbolizer --demangle --output-style=GNU -f -e " << proc.exe() << " " << addr;
×
178
      auto llvm_symbolizer = system::CommandPipe::create(command.str());
×
179
      if (llvm_symbolizer) {
×
180
        return llvm_symbolizer;
×
181
      }
182
    }
×
183

184
    if (sloc_helper.hasAddr2line()) {
21✔
185
      std::ostringstream command;
21✔
186
      command << "addr2line --demangle=auto -f -e " << proc.exe() << " " << std::hex << addr;
21✔
187
      auto addr2line = system::CommandPipe::create(command.str());
21✔
188
      if (addr2line) {
21✔
189
        return addr2line;
21✔
190
      }
191
    }
21✔
192

193
    return {};
×
194
  }(raw_address, offset_ptr);
42✔
195

196
  if (!pipe) {
21✔
197
    return {};
×
198
  }
199

200
  SourceLocation loc;
21✔
201

202
  loc.function             = pipe->nextLine();
21✔
203
  const auto file_and_line = pipe->nextLine();
21✔
204
  const auto delimiter     = file_and_line.find(':');
21✔
205
  loc.line                 = file_and_line.substr(delimiter + 1);
21✔
206
  loc.file                 = file_and_line.substr(0, delimiter);
21✔
207

208
  return loc;
21✔
209
}
21✔
210

211
}  // namespace typeart
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