Enable proper full C++ exception handling on MSVC
[openal-soft.git] / al / error.cpp
blob24cc51dca332febfcd0c4bd8995529d6b8b4c4f6
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.
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.
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
21 #include "config.h"
23 #include "error.h"
25 #ifdef _WIN32
26 #define WIN32_LEAN_AND_MEAN
27 #include <windows.h>
28 #endif
30 #include <atomic>
31 #include <csignal>
32 #include <cstdarg>
33 #include <cstdio>
34 #include <cstdlib>
35 #include <cstring>
36 #include <limits>
37 #include <optional>
38 #include <string>
39 #include <utility>
40 #include <vector>
42 #include "AL/al.h"
43 #include "AL/alc.h"
45 #include "al/debug.h"
46 #include "alc/alconfig.h"
47 #include "alc/context.h"
48 #include "alc/inprogext.h"
49 #include "core/logging.h"
50 #include "opthelpers.h"
51 #include "strutils.h"
54 namespace al {
55 context_error::context_error(ALenum code, const char *msg, ...) : mErrorCode{code}
57 /* NOLINTBEGIN(*-array-to-pointer-decay) */
58 std::va_list args;
59 va_start(args, msg);
60 setMessage(msg, args);
61 va_end(args);
62 /* NOLINTEND(*-array-to-pointer-decay) */
64 context_error::~context_error() = default;
65 } /* namespace al */
67 void ALCcontext::setError(ALenum errorCode, const char *msg, ...)
69 auto message = std::vector<char>(256);
71 /* NOLINTBEGIN(*-array-to-pointer-decay) */
72 std::va_list args, args2;
73 va_start(args, msg);
74 va_copy(args2, args);
75 int msglen{std::vsnprintf(message.data(), message.size(), msg, args)};
76 if(msglen >= 0 && static_cast<size_t>(msglen) >= message.size())
78 message.resize(static_cast<size_t>(msglen) + 1u);
79 msglen = std::vsnprintf(message.data(), message.size(), msg, args2);
81 va_end(args2);
82 va_end(args);
83 /* NOLINTEND(*-array-to-pointer-decay) */
85 if(msglen >= 0)
86 msg = message.data();
87 else
89 msg = "<internal error constructing message>";
90 msglen = static_cast<int>(strlen(msg));
93 WARN("Error generated on context %p, code 0x%04x, \"%s\"\n",
94 decltype(std::declval<void*>()){this}, errorCode, msg);
95 if(TrapALError)
97 #ifdef _WIN32
98 /* DebugBreak will cause an exception if there is no debugger */
99 if(IsDebuggerPresent())
100 DebugBreak();
101 #elif defined(SIGTRAP)
102 raise(SIGTRAP);
103 #endif
106 if(mLastThreadError.get() == AL_NO_ERROR)
107 mLastThreadError.set(errorCode);
109 debugMessage(DebugSource::API, DebugType::Error, 0, DebugSeverity::High,
110 {msg, static_cast<uint>(msglen)});
113 /* Special-case alGetError since it (potentially) raises a debug signal and
114 * returns a non-default value for a null context.
116 AL_API auto AL_APIENTRY alGetError() noexcept -> ALenum
118 if(auto context = GetContextRef()) LIKELY
119 return alGetErrorDirect(context.get());
121 auto get_value = [](const char *envname, const char *optname) -> ALenum
123 auto optstr = al::getenv(envname);
124 if(!optstr)
125 optstr = ConfigValueStr({}, "game_compat", optname);
126 if(optstr)
128 char *end{};
129 auto value = std::strtoul(optstr->c_str(), &end, 0);
130 if(end && *end == '\0' && value <= std::numeric_limits<ALenum>::max())
131 return static_cast<ALenum>(value);
132 ERR("Invalid default error value: \"%s\"", optstr->c_str());
134 return AL_INVALID_OPERATION;
136 static const ALenum deferror{get_value("__ALSOFT_DEFAULT_ERROR", "default-error")};
138 WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror);
139 if(TrapALError)
141 #ifdef _WIN32
142 if(IsDebuggerPresent())
143 DebugBreak();
144 #elif defined(SIGTRAP)
145 raise(SIGTRAP);
146 #endif
148 return deferror;
151 FORCE_ALIGN ALenum AL_APIENTRY alGetErrorDirect(ALCcontext *context) noexcept
153 ALenum ret{context->mLastThreadError.get()};
154 if(ret != AL_NO_ERROR) UNLIKELY
155 context->mLastThreadError.set(AL_NO_ERROR);
156 return ret;