/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2026 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#if defined(__CYGWIN__)
#define _BSD_SOURCE // required to have getloadavg()
#endif
#include "processexecutor.h"
#ifdef HAS_THREADING_MODEL_FORK
#include "cppcheck.h"
#include "errorlogger.h"
#include "errortypes.h"
#include "filesettings.h"
#include "settings.h"
#include "suppressions.h"
#include "timer.h"
#include "utils.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef __SVR4 // Solaris
#include
#endif
#if defined(__linux__)
#include
#endif
enum class Color : std::uint8_t;
// NOLINTNEXTLINE(misc-unused-using-decls) - required for FD_ZERO
using std::memset;
ProcessExecutor::ProcessExecutor(const std::list &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, TimerResults* timerResults, CppCheck::ExecuteCmdFn executeCommand)
: Executor(files, fileSettings, settings, suppressions, errorLogger, timerResults)
, mExecuteCommand(std::move(executeCommand))
{
assert(mSettings.jobs > 1);
}
namespace {
class PipeWriter : public ErrorLogger {
public:
enum PipeSignal : std::uint8_t {REPORT_OUT='1',REPORT_ERROR='2',REPORT_SUPPR_INLINE='3',REPORT_SUPPR='4',CHILD_END='5',REPORT_METRIC='6',REPORT_TIMER='7'};
explicit PipeWriter(int pipe, bool debug) : mWpipe(pipe), mDebug(debug) {}
void reportOut(const std::string &outmsg, Color c) override {
writeToPipe(REPORT_OUT, static_cast(c) + outmsg);
}
void reportErr(const ErrorMessage &msg) override {
writeToPipe(REPORT_ERROR, msg.serialize());
}
void writeSuppr(const SuppressionList &supprs) const {
for (const auto& suppr : supprs.getSuppressions())
{
if (suppr.isInline)
writeToPipe(REPORT_SUPPR_INLINE, suppressionToString(suppr));
else if (suppr.checked)
writeToPipe(REPORT_SUPPR, suppressionToString(suppr));
}
}
void reportMetric(const std::string &metric) override {
writeToPipe(REPORT_METRIC, metric);
}
void writeTimer(const TimerResults* timerResults) const {
if (!timerResults)
return;
for (const auto& entry : timerResults->getResults())
{
for (const auto& d : entry.second) {
writeToPipe(REPORT_TIMER, entry.first + ";" + std::to_string(d.count()));
}
}
}
void writeEnd(const std::string& str) const {
writeToPipe(CHILD_END, str);
}
private:
static std::string suppressionToString(const SuppressionList::Suppression &suppr)
{
std::string suppr_str = suppr.toString();
suppr_str += ";";
suppr_str += std::to_string(suppr.column);
suppr_str += ";";
suppr_str += suppr.checked ? "1" : "0";
suppr_str += ";";
suppr_str += suppr.matched ? "1" : "0";
suppr_str += ";";
suppr_str += suppr.extraComment;
return suppr_str;
}
// TODO: how to log file name in error?
void writeToPipeInternal(PipeSignal type, const void* data, std::size_t to_write) const
{
const ssize_t bytes_written = write(mWpipe, data, to_write);
if (bytes_written