Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
35dc9e5
Fix Coverity CID 1644341: Suppress false positive for bravo lock
PSUdaemon Jan 16, 2026
1839bf8
Fix Coverity CID 1644338: Handle exceptions in Stripe destructor
PSUdaemon Jan 16, 2026
1ffe388
Fix Coverity CID 1644337: Suppress false positive for copy assignment…
PSUdaemon Jan 16, 2026
ef1e2a6
Fix Coverity CID 1644336: Initialize entrylist before scandir
PSUdaemon Jan 16, 2026
d344dcc
Fix Coverity CID 1644335: Make StaticString thread-safe
PSUdaemon Jan 16, 2026
028d2cc
Fix Coverity CID 1644332/1644314: Suppress false positive in State de…
PSUdaemon Jan 16, 2026
843b18a
Fix Coverity CID 1644330: Suppress false positive for visitor pattern
PSUdaemon Jan 16, 2026
8adc433
Fix Coverity CID 1644329: Remove noexcept from UnitParser::operator()
PSUdaemon Jan 16, 2026
3c04cd0
Fix Coverity CID 1644324: Handle exceptions in HttpSM destructor
PSUdaemon Jan 16, 2026
6cd4003
Fix Coverity CID 1644319: Use memcpy instead of strcpy
PSUdaemon Jan 16, 2026
98085b6
Fix Coverity CID 1644318: Add null check before strcmp
PSUdaemon Jan 16, 2026
38b3cff
Fix Coverity CID 1644316: PASS_BY_VALUE in IOBuffer.cc
PSUdaemon Jan 16, 2026
06214c3
Fix Coverity CID 1644312: Suppress false positive RESOURCE_LEAK
PSUdaemon Jan 16, 2026
819f237
Fix Coverity CID 1644310: COPY_INSTEAD_OF_MOVE in regex_remap.cc
PSUdaemon Jan 16, 2026
3e93731
Fix Coverity CID 1644323: CHECKED_RETURN in ts_util.cc
PSUdaemon Jan 16, 2026
985d729
Fix Coverity CID 1644326: OVERRUN in test_HpackIndexingTable.cc
PSUdaemon Jan 16, 2026
70a66a5
Fix Coverity CID 1644325: WRAPPER_ESCAPE in test_RemapPlugin.cc
PSUdaemon Jan 16, 2026
c08dd63
Fix Coverity CID 1644320: UNCAUGHT_EXCEPT in traffic_crashlog.cc
PSUdaemon Jan 16, 2026
d31163e
Fix Coverity CID 1644327: UNCAUGHT_EXCEPT in test_AIO.cc
PSUdaemon Jan 16, 2026
aca4318
Fix inverted condition that could throw std::bad_optional_access
PSUdaemon Jan 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/proxy/http/HttpTransact.h
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,7 @@ class HttpTransact
// memset((void *)&host_db_info, 0, sizeof(host_db_info));
}

// coverity[exn_spec_violation] - destroy() only frees memory and does ref counting
~State() { destroy(); }

void
Expand Down
27 changes: 17 additions & 10 deletions include/tsutil/Metrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -536,11 +536,15 @@ class Metrics

}; // class Counter

/**
* Static string metrics storage.
*
* All methods are thread-safe.
*/
class StaticString
{
public:
using StringStorage = std::unordered_map<std::string, std::string>;
using iterator = StringStorage::iterator;

static void
createString(const std::string &name, const std::string_view value)
Expand All @@ -551,18 +555,21 @@ class Metrics

static StaticString &instance();

iterator
begin()
/**
* Thread-safe iteration over all string metrics.
* The callback is invoked for each metric while holding the mutex.
*/
template <typename Func>
void
for_each(Func &&func) const
{
return _strings.begin();
std::lock_guard lock(_mutex);
for (const auto &[name, value] : _strings) {
func(name, value);
}
}
iterator
end()
{
return _strings.end();
};

std::optional<std::string_view> lookup(const std::string &name);
std::optional<std::string_view> lookup(const std::string &name) const;

private:
void _createString(const std::string &name, const std::string_view value);
Expand Down
2 changes: 1 addition & 1 deletion include/tsutil/ts_unit_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class UnitParser
* @param src Input string.
* @return The computed value if the input is valid, or an error report.
*/
Rv<value_type> operator()(swoc::TextView const &src) const noexcept;
Rv<value_type> operator()(swoc::TextView const &src) const;

protected:
bool _unit_required_p = true; ///< Whether unitless values are allowed.
Expand Down
1 change: 1 addition & 0 deletions plugins/experimental/txn_box/plugin/src/Comparison.cc
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,7 @@ Cmp_Rxp::expr_visitor::operator()(std::monostate)
Rv<Comparison::Handle>
Cmp_Rxp::expr_visitor::operator()(Expr::Direct &d)
{
// coverity[use_after_move] - intentional: visitor consumes the variant alternative
return Handle(new Cmp_RxpSingle(Expr{std::move(d)}, _rxp_opt));
}

Expand Down
4 changes: 3 additions & 1 deletion plugins/experimental/txn_box/plugin/src/ts_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,9 @@ ts::HttpTxn::outbound_remote_addr() const
Errata
ts::HttpTxn::cache_key_assign(TextView const &key)
{
TSCacheUrlSet(_txn, key.data(), key.size());
if (TS_ERROR == TSCacheUrlSet(_txn, key.data(), key.size())) {
return Errata(S_ERROR, R"(Failed to set cache key to "{}".)", key);
}
return {};
}

Expand Down
2 changes: 1 addition & 1 deletion plugins/regex_remap/regex_remap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ RemapRegex::initialize(const std::string &reg, const std::string &sub, const std
_lowercase_substitutions = true;
} else if (opt.compare(start, 8, "strategy") == 0) {
_has_strategy = true;
_strategy = opt_val;
_strategy = std::move(opt_val);
} else if (opt_val.size() <= 0) {
// All other options have a required value
TSError("[%s] Malformed options: %s", PLUGIN_NAME, opt.c_str());
Expand Down
1 change: 1 addition & 0 deletions src/iocore/aio/test_AIO.cc
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ class IOUringLoopTailHandler : public EThread::LoopTailHandler
int
main(int argc, char *argv[])
{
// coverity[fun_call_w_exception] - called functions may throw but this is a test program
int i;

// Read the configuration file
Expand Down
1 change: 1 addition & 0 deletions src/iocore/cache/Stripe.cc
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ Stripe::_init_directory(std::size_t directory_size, int header_size, int footer_
Stripe::~Stripe()
{
if (this->directory.raw_dir != nullptr) {
// coverity[fun_call_w_exception] - ink_assert aborts (doesn't throw), Dbg is exception-safe
// Debug logging to track cleanup - helps correlate with crash location
Dbg(dbg_ctl_cache_free, "Stripe %s: freeing raw_dir=%p size=%zu huge=%s", hash_text.get() ? hash_text.get() : "(null)",
this->directory.raw_dir, this->directory.raw_dir_size, this->directory.raw_dir_huge ? "true" : "false");
Expand Down
39 changes: 20 additions & 19 deletions src/iocore/eventsystem/IOBuffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1046,25 +1046,26 @@ auto
make_buffer_size_parser()
{
using L = swoc::Lexicon<int>;
return [l = L{
L::with_multi{{0, {"128"}},
{1, {"256"}},
{2, {"512"}},
{3, {"1k", "1024"}},
{4, {"2k", "2048"}},
{5, {"4k", "4096"}},
{6, {"8k", "8192"}},
{7, {"16k"}},
{8, {"32k"}},
{9, {"64k"}},
{10, {"128k"}},
{11, {"256k"}},
{12, {"512k"}},
{13, {"1M", "1024k"}},
{14, {"2M", "2048k"}}},
-1
}](swoc::TextView esize) -> std::optional<int> {
int result = l[esize];
static const L lexicon{
L::with_multi{{0, {"128"}},
{1, {"256"}},
{2, {"512"}},
{3, {"1k", "1024"}},
{4, {"2k", "2048"}},
{5, {"4k", "4096"}},
{6, {"8k", "8192"}},
{7, {"16k"}},
{8, {"32k"}},
{9, {"64k"}},
{10, {"128k"}},
{11, {"256k"}},
{12, {"512k"}},
{13, {"1M", "1024k"}},
{14, {"2M", "2048k"}}},
-1
};
return [](swoc::TextView esize) -> std::optional<int> {
int result = lexicon[esize];
if (result == -1) {
return std::nullopt;
}
Expand Down
3 changes: 2 additions & 1 deletion src/iocore/net/SSLSessionCache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ SSLSessionBucket::insertSession(const SSLSessionID &id, SSL_SESSION *sess, SSL *
} else {
std::string_view group_name = SSLGetGroupName(ssl);
ink_release_assert(group_name.size() < sizeof(exdata->group_name));
strcpy(exdata->group_name, group_name.data());
memcpy(exdata->group_name, group_name.data(), group_name.size());
exdata->group_name[group_name.size()] = '\0';
}

std::unique_ptr<SSLSession> ssl_session(new SSLSession(id, buf, len, buf_exdata));
Expand Down
1 change: 1 addition & 0 deletions src/iocore/net/unit_tests/test_ProxyProtocol.cc
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,7 @@ TEST_CASE("ProxyProtocol Rule of 5", "[ProxyProtocol]")
std::string_view copy_tlv_data("\x02\x00\x04copy", 7);
copy.set_additional_data(copy_tlv_data);

// coverity[copy_instead_of_move] - intentionally testing copy assignment
copy = original;

// After assignment, copy should have original's data
Expand Down
2 changes: 1 addition & 1 deletion src/proxy/Plugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ plugin_expand(char *arg)
}
case RECD_COUNTER: {
auto count_val{RecGetRecordCounter(arg)};
if (count_val) {
if (!count_val) {
goto not_found;
}
str = static_cast<char *>(ats_malloc(128));
Expand Down
2 changes: 2 additions & 0 deletions src/proxy/hdrs/unit_tests/test_HeaderValidator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ TEST_CASE("testIsHeaderValid", "[proxy][hdrtest]")
{
HTTPHdr hdr;
// extra to prevent proxy allocation.
// coverity[resource_leak] - heap is freed via hdr.destroy() which calls
// HdrHeapSDKHandle::destroy() -> m_heap->destroy()
HdrHeap *heap = new_HdrHeap(HdrHeap::DEFAULT_SIZE + 64);

SECTION("Test (valid) request with 4 required pseudo headers")
Expand Down
3 changes: 2 additions & 1 deletion src/proxy/http/HttpConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,8 @@ ParsedConfigCache::lookup_impl(TSOverridableConfigKey key, std::string_view valu
// Fast path: check cache under read lock.
{
ts::bravo::shared_lock lock(_mutex);
auto it = _cache.find(cache_key);
// coverity[missing_lock] - ts::bravo::shared_lock properly holds the mutex
auto it = _cache.find(cache_key);
if (it != _cache.end()) {
return it->second;
}
Expand Down
11 changes: 10 additions & 1 deletion src/proxy/http/HttpSM.cc
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,17 @@ HttpSM::~HttpSM()
{
http_parser_clear(&http_parser);

// coverity[exn_spec_violation] - release() only does ref counting and delete on POD types
HttpConfig::release(t_state.http_config_param);
m_remap->release();

// m_remap->release() can allocate (new_Deleter), so catch potential bad_alloc
try {
m_remap->release();
} catch (...) {
Error("Exception in ~HttpSM during m_remap->release");
}

// coverity[exn_spec_violation] - cancel_pending_action() only sets boolean flags
cache_sm.cancel_pending_action();

mutex.clear();
Expand All @@ -293,6 +301,7 @@ HttpSM::~HttpSM()
debug_on = false;

if (_prewarm_sm) {
// coverity[exn_spec_violation] - destroy() only frees memory and resets shared_ptrs
_prewarm_sm->destroy();
THREAD_FREE(_prewarm_sm, preWarmSMAllocator, this_ethread());
_prewarm_sm = nullptr;
Expand Down
2 changes: 1 addition & 1 deletion src/proxy/http/remap/RemapConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ parse_include_directive(const char *directive, BUILD_TABLE_INFO *bti, char *errb
path = RecConfigReadConfigPath(nullptr, bti->paramv[i]);

if (ink_file_is_directory(path)) {
struct dirent **entrylist;
struct dirent **entrylist = nullptr;
int n_entries;

n_entries = scandir(path, &entrylist, nullptr, alphasort);
Expand Down
2 changes: 2 additions & 0 deletions src/proxy/http/remap/unit-tests/test_NextHopRoundRobin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ SCENARIO("Testing NextHopRoundRobin class, using policy 'rr-ip'", "[NextHopRound
build_request(10017, &sm, &sa2, "rabbit.net", nullptr);
result->reset();
strategy->findNextHop(txnp);
REQUIRE(result->hostname != nullptr);
CHECK(strcmp(result->hostname, "p3.foo.com") == 0);

// call and test parentExists(), this call should not affect
Expand All @@ -297,6 +298,7 @@ SCENARIO("Testing NextHopRoundRobin class, using policy 'rr-ip'", "[NextHopRound
build_request(10018, &sm, &sa2, "rabbit.net", nullptr);
result->reset();
strategy->findNextHop(txnp);
REQUIRE(result->hostname != nullptr);
CHECK(strcmp(result->hostname, "p3.foo.com") == 0);

// call and test parentExists(), this call should not affect
Expand Down
1 change: 1 addition & 0 deletions src/proxy/http/remap/unit-tests/test_RemapPlugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ SCENARIO("unloading the plugin", "[plugin][core]")
{
debugObject->clear();

// coverity[wrapper_escape] - plugin pointer temporarily escapes to thread context but is reset before return
plugin->doneInstance(INSTANCE_HANDLER);

THEN("expect it to run and receive the right instance handler")
Expand Down
1 change: 1 addition & 0 deletions src/proxy/http2/unit_tests/test_HpackIndexingTable.cc
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ TEST_CASE("HPACK low level APIs", "[hpack]")

REQUIRE(len > 0);
REQUIRE(len == literal_test_case[i].encoded_field_len);
// coverity[overrun-buffer-arg] - len is validated positive above
REQUIRE(memcmp(buf, literal_test_case[i].encoded_field, len) == 0);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/records/RecCore.cc
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ RecLookupMatchingRecords(unsigned rec_type, const char *match, void (*callback)(
}
}
// Finally check string metrics
for (auto &&[name, value] : ts::Metrics::StaticString::instance()) {
ts::Metrics::StaticString::instance().for_each([&](const std::string &name, const std::string &value) {
if (regex.exec(name)) {
RecRecord tmp;

Expand All @@ -608,7 +608,7 @@ RecLookupMatchingRecords(unsigned rec_type, const char *match, void (*callback)(
tmp.data.rec_string = const_cast<char *>(value.c_str());
callback(&tmp, data);
}
}
});
}

int num_records = g_num_records;
Expand Down
1 change: 1 addition & 0 deletions src/traffic_crashlog/traffic_crashlog.cc
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ main(int /* argc ATS_UNUSED */, const char **argv)
if (syslog_mode) {
int facility = -1;
if (auto name{RecGetRecordStringAlloc("proxy.config.syslog_facility")}; name) {
// coverity[fun_call_w_exception] - guarded by if(name) check above
facility = facility_string_to_int(ats_as_c_str(name));
}

Expand Down
7 changes: 3 additions & 4 deletions src/tsutil/Metrics.cc
Original file line number Diff line number Diff line change
Expand Up @@ -303,15 +303,14 @@ Metrics::StaticString::instance()
void
Metrics::StaticString::_createString(const std::string &name, const std::string_view value)
{
std::lock_guard l(_mutex);

std::lock_guard lock(_mutex);
_strings[name] = value;
}

std::optional<std::string_view>
Metrics::StaticString::lookup(const std::string &name)
Metrics::StaticString::lookup(const std::string &name) const
{
std::lock_guard l(_mutex);
std::lock_guard lock(_mutex);
auto it = _strings.find(name);
std::optional<std::string_view> result{};

Expand Down
2 changes: 1 addition & 1 deletion src/tsutil/ts_unit_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace ts
{

auto
UnitParser::operator()(swoc::TextView const &src) const noexcept -> Rv<value_type>
UnitParser::operator()(swoc::TextView const &src) const -> Rv<value_type>
{
value_type zret = 0;
TextView text = src; // Keep @a src around to report error offsets.
Expand Down