Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 13 additions & 8 deletions include/bout/boutexception.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@ void BoutParallelThrowRhsFail(int status, const char* message);

class BoutException : public std::exception {
public:
BoutException(const BoutException&) = default;
BoutException(BoutException&&) = delete;
BoutException& operator=(const BoutException&) = default;
BoutException& operator=(BoutException&&) = delete;
BoutException(std::string msg);

template <class S, class... Args>
BoutException(const S& format, const Args&... args)
: BoutException(fmt::format(format, args...)) {}
BoutException(S&& format, Args&&... args)
: BoutException(fmt::format(std::forward<S>(format),
std::forward<decltype(args)>(args)...)) {}

~BoutException() override;

Expand All @@ -38,24 +43,24 @@ private:
int trace_size;
char** messages;
#endif

void makeBacktrace();
};

class BoutRhsFail : public BoutException {
public:
BoutRhsFail(std::string message) : BoutException(std::move(message)) {}
template <class S, class... Args>
BoutRhsFail(const S& format, const Args&... args)
: BoutRhsFail(fmt::format(format, args...)) {}
BoutRhsFail(S&& format, Args&&... args)
: BoutRhsFail(fmt::format(std::forward<S>(format),
std::forward<decltype(args)>(args)...)) {}
};

class BoutIterationFail : public BoutException {
public:
BoutIterationFail(std::string message) : BoutException(std::move(message)) {}
template <class S, class... Args>
BoutIterationFail(const S& format, const Args&... args)
: BoutIterationFail(fmt::format(format, args...)) {}
BoutIterationFail(S&& format, Args&&... args)
: BoutIterationFail(fmt::format(std::forward<S>(format),
std::forward<decltype(args)>(args)...)) {}
};

#endif
80 changes: 44 additions & 36 deletions include/bout/output.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ class Output;

#include "bout/multiostream.hxx"
#include <fstream>
#include <functional>
#include <iostream>
#include <string>

#include "bout/assert.hxx"
#include "bout/boutexception.hxx"
#include "bout/sys/gettext.hxx" // for gettext _() macro
#include "bout/sys/gettext.hxx" // IWYU pragma: keep for gettext _() macro
#include "bout/unused.hxx"

#include "fmt/core.h"

#include <utility>

using std::endl;

/// Class for text output to stdout and/or log file
Expand All @@ -61,22 +61,28 @@ using std::endl;
class Output : private multioutbuf_init<char, std::char_traits<char>>,
public std::basic_ostream<char, std::char_traits<char>> {

using _Tr = std::char_traits<char>;
using multioutbuf_init = ::multioutbuf_init<char, _Tr>;
using Tr = std::char_traits<char>;
using multioutbuf_init = ::multioutbuf_init<char, Tr>;

public:
Output() : multioutbuf_init(), std::basic_ostream<char, _Tr>(multioutbuf_init::buf()) {
Output() : multioutbuf_init(), std::basic_ostream<char, Tr>(multioutbuf_init::buf()) {
Output::enable();
}

Output(const Output&) = delete;
Output(Output&&) = delete;
Output& operator=(const Output&) = delete;
Output& operator=(Output&&) = delete;

/// Specify a log file to open
Output(const std::string& filename) {
Output::enable();
open(filename);
}

template <class S, class... Args>
Output(const S& format, const Args&... args) : Output(fmt::format(format, args...)) {}
Output(const S& format, Args&&... args)
: Output(fmt::format(format, std::forward<decltype(args)>(args)...)) {}

~Output() override { close(); }

Expand All @@ -87,8 +93,8 @@ public:
int open(const std::string& filename);

template <class S, class... Args>
int open(const S& format, const Args&... args) {
return open(fmt::format(format, args...));
int open(const S& format, Args&&... args) {
return open(fmt::format(format, std::forward<decltype(args)>(args)...));
}

/// Close the log file
Expand All @@ -98,24 +104,22 @@ public:
virtual void write(const std::string& message);

template <class S, class... Args>
void write(const S& format, const Args&... args) {
write(fmt::format(format, args...));
void write(const S& format, Args&&... args) {
write(fmt::format(format, std::forward<decltype(args)>(args)...));
}
/// Same as write, but only to screen
virtual void print(const std::string& message);

template <class S, class... Args>
void print(const S& format, const Args&... args) {
print(fmt::format(format, args...));
void print(const S& format, Args&&... args) {
print(fmt::format(format, std::forward<decltype(args)>(args)...));
}

/// Add an output stream. All output will be sent to all streams
void add(std::basic_ostream<char, _Tr>& str) { multioutbuf_init::buf()->add(str); }
void add(std::basic_ostream<char, Tr>& str) { multioutbuf_init::buf()->add(str); }

/// Remove an output stream
void remove(std::basic_ostream<char, _Tr>& str) {
multioutbuf_init::buf()->remove(str);
}
void remove(std::basic_ostream<char, Tr>& str) { multioutbuf_init::buf()->remove(str); }

static Output* getInstance(); ///< Return pointer to instance

Expand All @@ -126,7 +130,7 @@ protected:

private:
std::ofstream file; ///< Log file stream
bool enabled; ///< Whether output to stdout is enabled
bool enabled{}; ///< Whether output to stdout is enabled
};

/// Class which behaves like Output, but has no effect.
Expand All @@ -136,14 +140,14 @@ private:
class DummyOutput : public Output {
public:
template <class S, class... Args>
void write([[maybe_unused]] const S& format, [[maybe_unused]] const Args&... args){};
void write([[maybe_unused]] const S& format, [[maybe_unused]] Args&&... args) {};
template <class S, class... Args>
void print([[maybe_unused]] const S& format, [[maybe_unused]] const Args&... args){};
void write([[maybe_unused]] const std::string& message) override{};
void print([[maybe_unused]] const std::string& message) override{};
void enable() override{};
void disable() override{};
void enable([[maybe_unused]] bool enable){};
void print([[maybe_unused]] const S& format, [[maybe_unused]] Args&&... args) {};
void write([[maybe_unused]] const std::string& message) override {};
void print([[maybe_unused]] const std::string& message) override {};
void enable() override {};
void disable() override {};
void enable([[maybe_unused]] bool enable) {};
bool isEnabled() override { return false; }
};

Expand All @@ -170,10 +174,10 @@ public:
void write(const std::string& message) override;

template <class S, class... Args>
void write(const S& format, const Args&... args) {
void write(const S& format, Args&&... args) {
if (enabled) {
ASSERT1(base != nullptr);
base->write(fmt::format(format, args...));
base->write(fmt::format(format, std::forward<decltype(args)>(args)...));
}
}

Expand All @@ -182,10 +186,10 @@ public:
void print(const std::string& message) override;

template <class S, class... Args>
void print(const S& format, const Args&... args) {
void print(const S& format, Args&&... args) {
if (enabled) {
ASSERT1(base != nullptr);
base->print(fmt::format(format, args...));
base->print(fmt::format(format, std::forward<decltype(args)>(args)...));
}
}

Expand Down Expand Up @@ -216,8 +220,6 @@ private:
/// The lower-level Output to send output to
Output* base;

protected:
friend class WithQuietOutput;
/// Does this instance output anything?
bool enabled;
};
Expand Down Expand Up @@ -276,18 +278,23 @@ ConditionalOutput& operator<<(ConditionalOutput& out, const T* t) {
/// // output now enabled
class WithQuietOutput {
public:
explicit WithQuietOutput(ConditionalOutput& output_in) : output(output_in) {
state = output.enabled;
output.disable();
WithQuietOutput(const WithQuietOutput&) = delete;
WithQuietOutput(WithQuietOutput&&) = delete;
WithQuietOutput& operator=(const WithQuietOutput&) = delete;
WithQuietOutput& operator=(WithQuietOutput&&) = delete;
explicit WithQuietOutput(ConditionalOutput& output_in)
: output(&output_in), state(output->isEnabled()) {
output->disable();
}

~WithQuietOutput() { output.enable(state); }
~WithQuietOutput() { output->enable(state); }

private:
ConditionalOutput& output;
ConditionalOutput* output;
bool state;
};

// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
/// To allow statements like "output.write(...)" or "output << ..."
/// Output for debugging
#ifdef BOUT_USE_OUTPUT_DEBUG
Expand All @@ -303,5 +310,6 @@ extern ConditionalOutput output_verbose; ///< less interesting messages

/// Generic output, given the same level as output_progress
extern ConditionalOutput output;
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)

#endif // BOUT_OUTPUT_H
42 changes: 23 additions & 19 deletions src/sys/boutexception.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@
#include <bout/boutexception.hxx>
#include <bout/msg_stack.hxx>
#include <bout/utils.hxx>

#include <mpi.h>

#if BOUT_USE_BACKTRACE
#include <dlfcn.h>
#include <execinfo.h>
#include <stdio.h>
#endif

#include <array>
#include <cstdlib>
#include <string>
#include <utility>

#include <fmt/format.h>

Expand All @@ -22,18 +25,24 @@ const std::string header{"====== Exception thrown ======\n"};
}

void BoutParallelThrowRhsFail(int status, const char* message) {
int allstatus;
int allstatus = 0;
MPI_Allreduce(&status, &allstatus, 1, MPI_INT, MPI_LOR, BoutComm::get());

if (allstatus) {
if (allstatus != 0) {
throw BoutRhsFail(message);
}
}

BoutException::BoutException(std::string msg) : message(std::move(msg)) {
makeBacktrace();
BoutException::BoutException(std::string msg)
: message(std::move(msg))
#if BOUT_USE_BACKTRACE
,
trace_size(backtrace(trace.data(), TRACE_MAX)),
messages(backtrace_symbols(trace.data(), trace_size))
#endif
{
if (std::getenv("BOUT_SHOW_BACKTRACE") != nullptr) {
message = getBacktrace() + "\n" + message;
message = fmt::format("{}\n{}", getBacktrace(), message);
}
}

Expand All @@ -54,7 +63,8 @@ std::string BoutException::getBacktrace() const {
backtrace_message = "====== Exception path ======\n";
// skip first stack frame (points here)
for (int i = trace_size - 1; i > 1; --i) {
backtrace_message += fmt::format(FMT_STRING("[bt] #{:d} {:s}\n"), i - 1, messages[i]);
backtrace_message = fmt::format(FMT_STRING("{}[bt] #{:d} {:s}\n"), backtrace_message,
i - 1, messages[i]);
// find first occurence of '(' or ' ' in message[i] and assume
// everything before that is the file name. (Don't go beyond 0 though
// (string terminator)
Expand All @@ -65,11 +75,11 @@ std::string BoutException::getBacktrace() const {

// If we are compiled as PIE, need to get base pointer of .so and substract
Dl_info info;
void* ptr = trace[i];
if (dladdr(trace[i], &info)) {
const void* ptr = trace[i];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use array subscript when the index is not an integer constant expression [cppcoreguidelines-pro-bounds-constant-array-index]

    const void* ptr = trace[i];
                      ^

if (dladdr(ptr, &info) != 0) {
// Additionally, check whether this is the default offset for an executable
if (info.dli_fbase != reinterpret_cast<void*>(0x400000)) {
ptr = reinterpret_cast<void*>(reinterpret_cast<size_t>(trace[i])
ptr = reinterpret_cast<void*>(reinterpret_cast<size_t>(ptr)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]

        ptr = reinterpret_cast<void*>(reinterpret_cast<size_t>(ptr)
                                      ^

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]

        ptr = reinterpret_cast<void*>(reinterpret_cast<size_t>(ptr)
              ^

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: integer to pointer cast pessimizes optimization opportunities [performance-no-int-to-ptr]

        ptr = reinterpret_cast<void*>(reinterpret_cast<size_t>(ptr)
              ^

- reinterpret_cast<size_t>(info.dli_fbase));
}
}
Expand All @@ -82,27 +92,21 @@ std::string BoutException::getBacktrace() const {
FILE* file = popen(syscom.c_str(), "r");
if (file != nullptr) {
std::array<char, 1024> out{};
char* retstr = nullptr;
const char* retstr = nullptr;
std::string buf;
while ((retstr = fgets(out.data(), out.size() - 1, file)) != nullptr) {
buf += retstr;
}
int const status = pclose(file);
if (status == 0) {
backtrace_message += buf;
backtrace_message = fmt::format("{}{}", backtrace_message, buf);
}
}
}
#else
backtrace_message = "Stacktrace not enabled.\n";
#endif

return backtrace_message + msg_stack.getDump() + "\n" + header + message + "\n";
}

void BoutException::makeBacktrace() {
Comment thread
ZedThree marked this conversation as resolved.
#if BOUT_USE_BACKTRACE
trace_size = backtrace(trace.data(), TRACE_MAX);
messages = backtrace_symbols(trace.data(), trace_size);
#endif
return fmt::format("{}{}\n{}{}\n", backtrace_message, msg_stack.getDump(), header,
message);
}
14 changes: 9 additions & 5 deletions src/sys/output.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
*
**************************************************************************/

#include <bout/assert.hxx>
#include <bout/output.hxx>
#include <bout/utils.hxx>
#include <cstdarg>
#include <cstdio>
#include <cstring>

#include <fmt/base.h>

#include <iostream>
#include <string>

void Output::enable() {
add(std::cout);
Expand Down Expand Up @@ -68,7 +70,7 @@ void Output::close() {
}

void Output::write(const std::string& message) {
multioutbuf_init::buf()->sputn(message.c_str(), message.length());
multioutbuf_init::buf()->sputn(message.c_str(), static_cast<long>(message.length()));
}

void Output::print(const std::string& message) {
Expand Down Expand Up @@ -98,6 +100,7 @@ void ConditionalOutput::print(const std::string& message) {
}
}

// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
#ifdef BOUT_USE_OUTPUT_DEBUG
ConditionalOutput output_debug(Output::getInstance());
#else
Expand All @@ -109,3 +112,4 @@ ConditionalOutput output_progress(Output::getInstance());
ConditionalOutput output_error(Output::getInstance());
ConditionalOutput output_verbose(Output::getInstance(), false);
ConditionalOutput output(Output::getInstance());
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
Loading