[SDK] Remove std::regex usage from rocprofiler-sdk library and common library (#421)

* Remove std::regex usage from rocprofiler-sdk and common library

- See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118408
- std::regex usage produces exceptions or segfaults when used when on applications compiled with dual ABI
- Add code restrictions workflow
  - simple workflow ensuring code restrictions (such as std::regex) are not used

* Update CHANGELOG

* Explicitly set permissions for restrictions workflow

* Fix handling of /proc/cpuinfo entries with no info

- e.g. "power_management:" (colon is last character)

---------

Co-authored-by: Jonathan R. Madsen <jonathanrmadsen@gmail.com>
This commit is contained in:
Madsen, Jonathan
2025-05-29 23:11:13 -05:00
committed by GitHub
parent 7f22b66a9b
commit dbb2e52216
12 changed files with 212 additions and 47 deletions
+72 -36
View File
@@ -46,11 +46,12 @@
#include <iomanip>
#include <limits>
#include <random>
#include <regex>
#include <set>
#include <shared_mutex>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <type_traits>
#include <unordered_map>
#include <vector>
@@ -112,6 +113,7 @@ parse_cpu_info()
break;
}
line = sdk::parse::strip(std::move(line), " \t\n\v\f\r");
if(line.empty())
{
if(!current_block.empty()) blocks.emplace_back(std::move(current_block));
@@ -134,46 +136,68 @@ parse_cpu_info()
auto info_v = cpu_info{};
for(const auto& itr : bitr)
{
auto match = std::smatch{};
const std::regex re{".*: (.*)$"};
if(std::regex_match(itr, match, re))
auto match = sdk::parse::tokenize(itr, std::vector<std::string_view>{": "});
if(match.size() == 2)
{
if(match.size() == 2)
{
std::ssub_match value = match[1];
if(itr.find("vendor_id") == 0)
info_v.vendor_id = value.str();
else if(itr.find("model name") == 0)
auto get_stol = [_label = std::string_view{itr}](const auto& _value) -> long {
try
{
info_v.model_name = value.str();
size_t first_colon_pos = match.str().find(':');
// This handles the case where the model name has multiple colons
// Example "model name : AMD EPYC : 100-000000248"
if(first_colon_pos != std::string::npos)
{
// Extract the model name after the first colon
info_v.model_name = match.str().substr(first_colon_pos + 1);
// Remove leading and trailing whitespaces
info_v.model_name = std::regex_replace(
info_v.model_name, std::regex("^\\s+|\\s+$"), "");
}
return std::stol(_value);
} catch(std::exception& e)
{
ROCP_CI_LOG(WARNING) << fmt::format("rocprofiler-sdk agent encountered "
"error while parsing CPU info '{}': {}",
_label,
e.what());
}
return 0;
};
auto value = match.back();
if(itr.find("vendor_id") == 0)
info_v.vendor_id = value;
else if(itr.find("model name") == 0)
{
info_v.model_name = value;
size_t first_colon_pos = value.find(':');
// This handles the case where the model name has multiple colons
// Example "model name : AMD EPYC : 100-000000248"
if(first_colon_pos != std::string::npos)
{
// Extract the model name after the first colon
info_v.model_name = value.substr(first_colon_pos + 1);
// Remove leading and trailing whitespaces
info_v.model_name =
sdk::parse::strip(std::string{info_v.model_name}, " \t\n\v\f\r");
}
else if(itr.find("processor") == 0)
info_v.processor = std::stol(value.str());
else if(itr.find("cpu family") == 0)
info_v.family = std::stol(value.str());
else if(itr.find("model") == 0 && itr.find("model name") != 0)
info_v.model = std::stol(value.str());
else if(itr.find("physical id") == 0)
info_v.physical_id = std::stol(value.str());
else if(itr.find("core id") == 0)
info_v.core_id = std::stol(value.str());
else if(itr.find("apicid") == 0)
info_v.apicid = std::stol(value.str());
}
else if(itr.find("processor") == 0)
info_v.processor = get_stol(value);
else if(itr.find("cpu family") == 0)
info_v.family = get_stol(value);
else if(itr.find("model") == 0 && itr.find("model name") != 0)
info_v.model = get_stol(value);
else if(itr.find("physical id") == 0)
info_v.physical_id = get_stol(value);
else if(itr.find("core id") == 0)
info_v.core_id = get_stol(value);
else if(itr.find("apicid") == 0)
info_v.apicid = get_stol(value);
}
else
{
// Each processor_block is grouped by the presence of an empty line in /proc/cpuinfo
// so no checks for empty lines are performed inside this loop. If an empty line is
// found, that should be considered an error. Entries like "power management:" with
// no info (i.e. where the ":" is the last character on the line) can be ignored
auto last_colon_pos = itr.find_last_of(':');
ROCP_CI_LOG_IF(
INFO, last_colon_pos < itr.length() && (last_colon_pos + 1) != itr.length())
<< fmt::format("Encountered unexpected /proc/cpuinfo line format: '{}'", itr);
}
}
if(info_v.is_valid())
processor_info.emplace_back(info_v);
else
@@ -633,7 +657,19 @@ read_topology()
else
agent_info.model_name = "";
if(!gpu_id_prop.empty()) agent_info.gpu_id = std::stoull(gpu_id_prop.front());
if(!gpu_id_prop.empty())
{
try
{
agent_info.gpu_id = std::stoull(gpu_id_prop.front());
} catch(std::exception& e)
{
ROCP_CI_LOG(WARNING) << fmt::format("rocprofiler-sdk agent encountered error while "
"parsing gpu id property '{}': {}",
gpu_id_prop.front(),
e.what());
}
}
read_property(properties, "cpu_cores_count", agent_info.cpu_cores_count);
read_property(properties, "simd_count", agent_info.simd_count);
@@ -33,7 +33,6 @@
#include <atomic>
#include <cstdint>
#include <cstdlib>
#include <regex>
#include <string_view>
#include <vector>
@@ -33,7 +33,6 @@
#include <atomic>
#include <cstdint>
#include <cstdlib>
#include <regex>
#include <string_view>
#include <vector>
+6 -2
View File
@@ -310,7 +310,9 @@ find_clients()
if(fs::exists(itr) && resolved_exists(itr))
{
auto elfinfo = common::elf_utils::read(itr);
if(!elfinfo.has_symbol(std::regex{"^rocprofiler_configure$"}))
if(!elfinfo.has_symbol([](std::string_view symname) {
return (symname == "rocprofiler_configure");
}))
{
ROCP_CI_LOG(WARNING) << fmt::format(
"[ROCP_TOOL_LIBRARIES] rocprofiler-sdk tool library '{}' did not "
@@ -379,7 +381,9 @@ find_clients()
if(fs::exists(itr) && resolved_exists(itr))
{
auto elfinfo = common::elf_utils::read(itr);
if(!elfinfo.has_symbol(std::regex{"^rocprofiler_configure$"}))
if(!elfinfo.has_symbol([](std::string_view symname) {
return (symname == "rocprofiler_configure");
}))
{
ROCP_INFO << fmt::format(
"Shared library '{}' did not contain the 'rocprofiler_configure' symbol "