error.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2000 by authors.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include "error.h"
  22. #ifdef _WIN32
  23. #define WIN32_LEAN_AND_MEAN
  24. #include <windows.h>
  25. #endif
  26. #include <atomic>
  27. #include <csignal>
  28. #include <cstdarg>
  29. #include <cstdio>
  30. #include <cstdlib>
  31. #include <cstring>
  32. #include <limits>
  33. #include <optional>
  34. #include <string>
  35. #include <utility>
  36. #include <vector>
  37. #include "AL/al.h"
  38. #include "AL/alc.h"
  39. #include "al/debug.h"
  40. #include "alc/alconfig.h"
  41. #include "alc/context.h"
  42. #include "alc/inprogext.h"
  43. #include "core/logging.h"
  44. #include "opthelpers.h"
  45. #include "strutils.h"
  46. namespace al {
  47. context_error::context_error(ALenum code, const char *msg, ...) : mErrorCode{code}
  48. {
  49. /* NOLINTBEGIN(*-array-to-pointer-decay) */
  50. std::va_list args;
  51. va_start(args, msg);
  52. setMessage(msg, args);
  53. va_end(args);
  54. /* NOLINTEND(*-array-to-pointer-decay) */
  55. }
  56. context_error::~context_error() = default;
  57. } /* namespace al */
  58. void ALCcontext::setError(ALenum errorCode, const char *msg, ...)
  59. {
  60. auto message = std::vector<char>(256);
  61. /* NOLINTBEGIN(*-array-to-pointer-decay) */
  62. std::va_list args, args2;
  63. va_start(args, msg);
  64. va_copy(args2, args);
  65. int msglen{std::vsnprintf(message.data(), message.size(), msg, args)};
  66. if(msglen >= 0 && static_cast<size_t>(msglen) >= message.size())
  67. {
  68. message.resize(static_cast<size_t>(msglen) + 1u);
  69. msglen = std::vsnprintf(message.data(), message.size(), msg, args2);
  70. }
  71. va_end(args2);
  72. va_end(args);
  73. /* NOLINTEND(*-array-to-pointer-decay) */
  74. if(msglen >= 0)
  75. msg = message.data();
  76. else
  77. {
  78. msg = "<internal error constructing message>";
  79. msglen = static_cast<int>(strlen(msg));
  80. }
  81. WARN("Error generated on context %p, code 0x%04x, \"%s\"\n",
  82. decltype(std::declval<void*>()){this}, errorCode, msg);
  83. if(TrapALError)
  84. {
  85. #ifdef _WIN32
  86. /* DebugBreak will cause an exception if there is no debugger */
  87. if(IsDebuggerPresent())
  88. DebugBreak();
  89. #elif defined(SIGTRAP)
  90. raise(SIGTRAP);
  91. #endif
  92. }
  93. if(mLastThreadError.get() == AL_NO_ERROR)
  94. mLastThreadError.set(errorCode);
  95. debugMessage(DebugSource::API, DebugType::Error, 0, DebugSeverity::High,
  96. {msg, static_cast<uint>(msglen)});
  97. }
  98. /* Special-case alGetError since it (potentially) raises a debug signal and
  99. * returns a non-default value for a null context.
  100. */
  101. AL_API auto AL_APIENTRY alGetError() noexcept -> ALenum
  102. {
  103. if(auto context = GetContextRef()) LIKELY
  104. return alGetErrorDirect(context.get());
  105. auto get_value = [](const char *envname, const char *optname) -> ALenum
  106. {
  107. auto optstr = al::getenv(envname);
  108. if(!optstr)
  109. optstr = ConfigValueStr({}, "game_compat", optname);
  110. if(optstr)
  111. {
  112. char *end{};
  113. auto value = std::strtoul(optstr->c_str(), &end, 0);
  114. if(end && *end == '\0' && value <= std::numeric_limits<ALenum>::max())
  115. return static_cast<ALenum>(value);
  116. ERR("Invalid default error value: \"%s\"", optstr->c_str());
  117. }
  118. return AL_INVALID_OPERATION;
  119. };
  120. static const ALenum deferror{get_value("__ALSOFT_DEFAULT_ERROR", "default-error")};
  121. WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror);
  122. if(TrapALError)
  123. {
  124. #ifdef _WIN32
  125. if(IsDebuggerPresent())
  126. DebugBreak();
  127. #elif defined(SIGTRAP)
  128. raise(SIGTRAP);
  129. #endif
  130. }
  131. return deferror;
  132. }
  133. FORCE_ALIGN ALenum AL_APIENTRY alGetErrorDirect(ALCcontext *context) noexcept
  134. {
  135. ALenum ret{context->mLastThreadError.get()};
  136. if(ret != AL_NO_ERROR) UNLIKELY
  137. context->mLastThreadError.set(AL_NO_ERROR);
  138. return ret;
  139. }