[Openmp-commits] [llvm] [openmp] [Offload] Implement double free (and other allocation error) reporting (PR #100261)
Shilei Tian via Openmp-commits
openmp-commits at lists.llvm.org
Wed Jul 24 17:33:50 PDT 2024
================
@@ -0,0 +1,234 @@
+//===- ErrorReporting.h - Helper to provide nice error messages ----- c++ -===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OFFLOAD_PLUGINS_NEXTGEN_COMMON_ERROR_REPORTING_H
+#define OFFLOAD_PLUGINS_NEXTGEN_COMMON_ERROR_REPORTING_H
+
+#include "PluginInterface.h"
+#include "Shared/EnvironmentVar.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <functional>
+#include <optional>
+#include <string>
+#include <unistd.h>
+
+namespace llvm {
+namespace omp {
+namespace target {
+namespace plugin {
+
+class ErrorReporter {
+
+ enum ColorTy {
+ Yellow = int(HighlightColor::Address),
+ Green = int(HighlightColor::String),
+ DarkBlue = int(HighlightColor::Tag),
+ Cyan = int(HighlightColor::Attribute),
+ DarkPurple = int(HighlightColor::Enumerator),
+ DarkRed = int(HighlightColor::Macro),
+ BoldRed = int(HighlightColor::Error),
+ BoldLightPurple = int(HighlightColor::Warning),
+ BoldDarkGrey = int(HighlightColor::Note),
+ BoldLightBlue = int(HighlightColor::Remark),
+ };
+
+ /// The banner printed at the beginning of an error report.
+ static constexpr auto ErrorBanner = "OFFLOAD ERROR: ";
+
+ /// The size of the getBuffer() buffer.
+ static constexpr unsigned BufferSize = 1024;
+
+ /// Return a buffer of size BufferSize that can be used for formatting.
+ static char *getBuffer() {
+ static char *Buffer = nullptr;
+ if (!Buffer)
+ Buffer = reinterpret_cast<char *>(malloc(BufferSize));
+ return Buffer;
+ }
+
+ /// Return the device id as string, or n/a if not available.
+ static std::string getDeviceIdStr(GenericDeviceTy *Device) {
+ return Device ? std::to_string(Device->getDeviceId()) : "n/a";
+ }
+
+ /// Return a nice name for an TargetAllocTy.
+ static std::string getAllocTyName(TargetAllocTy Kind) {
+ switch (Kind) {
+ case TARGET_ALLOC_DEVICE_NON_BLOCKING:
+ case TARGET_ALLOC_DEFAULT:
+ case TARGET_ALLOC_DEVICE:
+ return "device memory";
+ case TARGET_ALLOC_HOST:
+ return "pinned host memory";
+ case TARGET_ALLOC_SHARED:
+ return "managed memory";
+ break;
+ }
+ llvm_unreachable("Unknown target alloc kind");
+ }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgcc-compat"
+#pragma clang diagnostic ignored "-Wformat-security"
+ /// Print \p Format, instantiated with \p Args to stderr.
+ /// TODO: Allow redirection into a file stream.
+ template <typename... ArgsTy>
+ [[gnu::format(__printf__, 1, 2)]] static void print(const char *Format,
+ ArgsTy &&...Args) {
+ raw_fd_ostream OS(STDERR_FILENO, false);
+ OS << llvm::format(Format, Args...);
+ }
+
+ /// Print \p Format, instantiated with \p Args to stderr, but colored.
+ /// TODO: Allow redirection into a file stream.
+ template <typename... ArgsTy>
+ [[gnu::format(__printf__, 2, 3)]] static void
+ print(ColorTy Color, const char *Format, ArgsTy &&...Args) {
+ raw_fd_ostream OS(STDERR_FILENO, false);
+ WithColor(OS, HighlightColor(Color)) << llvm::format(Format, Args...);
+ }
+
+ /// Print \p Format, instantiated with \p Args to stderr, but colored and with
+ /// a banner.
+ /// TODO: Allow redirection into a file stream.
+ template <typename... ArgsTy>
+ [[gnu::format(__printf__, 1, 2)]] static void reportError(const char *Format,
+ ArgsTy &&...Args) {
+ raw_fd_ostream OS(STDERR_FILENO, false);
+ WithColor(OS, HighlightColor::Error)
+ << ErrorBanner << llvm::format(Format, Args...) << "\n";
+ }
+#pragma clang diagnostic pop
+
+ static void reportError(const char *Str) { reportError("%s", Str); }
+ static void print(const char *Str) { print("%s", Str); }
+ static void print(StringRef Str) { print("%s", Str.str().c_str()); }
+ static void print(ColorTy Color, const char *Str) { print(Color, "%s", Str); }
+ static void print(ColorTy Color, StringRef Str) {
+ print(Color, "%s", Str.str().c_str());
+ }
+
+ /// Pretty print a stack trace.
+ static void reportStackTrace(StringRef StackTrace) {
+ if (StackTrace.empty())
+ return;
+
+ SmallVector<StringRef> Lines, Parts;
+ StackTrace.split(Lines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ int Start = Lines.empty() || !Lines[0].contains("PrintStackTrace") ? 0 : 1;
+ unsigned NumDigits =
+ (int)(floor(log10(Lines.size() - Start - /*0*/ 1)) + 1);
+ for (int I = Start, E = Lines.size(); I < E; ++I) {
+ auto Line = Lines[I];
+ Parts.clear();
+ Line = Line.drop_while([](char C) { return std::isspace(C); });
+ Line.split(Parts, " ", /*MaxSplit=*/2);
+ if (Parts.size() != 3 || Parts[0].size() < 2 || Parts[0][0] != '#') {
+ print("%s\n", Line.str().c_str());
+ continue;
+ }
+ unsigned FrameIdx = std::stoi(Parts[0].drop_front(1).str());
+ if (Start)
+ FrameIdx -= 1;
+ print(DarkPurple, " %s", Parts[0].take_front().str().c_str());
+ print(Green, "%*u", NumDigits, FrameIdx);
+ print(BoldLightBlue, " %s", Parts[1].str().c_str());
+ print(" %s\n", Parts[2].str().c_str());
+ }
+ print("\n");
+ }
+
+ /// Report information about an allocation associated with \p ATI.
+ static void reportAllocationInfo(AllocationTraceInfoTy *ATI) {
+ if (!ATI)
+ return;
+
+ if (!ATI->DeallocationTrace.empty()) {
+ print(BoldLightPurple, "Last deallocation:\n");
+ reportStackTrace(ATI->DeallocationTrace);
+ }
+
+ if (ATI->HostPtr)
+ print(BoldLightPurple,
+ "Last allocation of size %lu for host pointer %p:\n", ATI->Size,
+ ATI->HostPtr);
+ else
+ print(BoldLightPurple, "Last allocation of size %lu:\n", ATI->Size);
+ reportStackTrace(ATI->AllocationTrace);
+ if (!ATI->LastAllocationInfo)
+ return;
+
+ unsigned I = 0;
+ print(BoldLightPurple, "Prior allocations with the same base pointer:");
+ while (ATI->LastAllocationInfo) {
+ print("\n");
+ ATI = ATI->LastAllocationInfo;
+ print(BoldLightPurple, " #%u Prior deallocation of size %lu:\n", I,
+ ATI->Size);
+ reportStackTrace(ATI->DeallocationTrace);
+ if (ATI->HostPtr)
+ print(BoldLightPurple, " #%u Prior allocation for host pointer %p:\n",
+ I, ATI->HostPtr);
+ else
+ print(BoldLightPurple, " #%u Prior allocation:\n", I);
+ reportStackTrace(ATI->AllocationTrace);
+ ++I;
+ }
+ }
+
+public:
+ /// Check if the deallocation of \p DevicePtr is valid given \p ATI. Stores \p
+ /// StackTrace to \p ATI->DeallocationTrace if there was no error.
+ static void checkDeallocation(GenericDeviceTy *Device, void *DevicePtr,
----------------
shiltian wrote:
IMHO the responsibilities of this `ErrorReporter` is too wide. I'd prefer to use something else to do the check and then report the error using `ErrorReporter`, instead of making it a static member function of `ErrorReporter`.
https://github.com/llvm/llvm-project/pull/100261
More information about the Openmp-commits
mailing list