1/*
2 * Copyright (C) 2016 Igalia S.L
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "XErrorTrapper.h"
28
29#if PLATFORM(X11)
30#include <sys/types.h>
31#include <unistd.h>
32#include <wtf/HashMap.h>
33#include <wtf/NeverDestroyed.h>
34
35namespace WebCore {
36
37static HashMap<Display*, Vector<XErrorTrapper*>>& xErrorTrappersMap()
38{
39 static NeverDestroyed<HashMap<Display*, Vector<XErrorTrapper*>>> trappersMap;
40 return trappersMap;
41}
42
43XErrorTrapper::XErrorTrapper(Display* display, Policy policy, Vector<unsigned char>&& expectedErrors)
44 : m_display(display)
45 , m_policy(policy)
46 , m_expectedErrors(WTFMove(expectedErrors))
47{
48 xErrorTrappersMap().add(m_display, Vector<XErrorTrapper*>()).iterator->value.append(this);
49 m_previousErrorHandler = XSetErrorHandler([](Display* display, XErrorEvent* event) -> int {
50 auto iterator = xErrorTrappersMap().find(display);
51 if (iterator == xErrorTrappersMap().end())
52 return 0;
53
54 ASSERT(!iterator->value.isEmpty());
55 iterator->value.last()->errorEvent(event);
56 return 0;
57 });
58}
59
60XErrorTrapper::~XErrorTrapper()
61{
62 XSync(m_display, False);
63 auto iterator = xErrorTrappersMap().find(m_display);
64 ASSERT(iterator != xErrorTrappersMap().end());
65 auto* trapper = iterator->value.takeLast();
66 ASSERT_UNUSED(trapper, trapper == this);
67 if (iterator->value.isEmpty())
68 xErrorTrappersMap().remove(iterator);
69
70 XSetErrorHandler(m_previousErrorHandler);
71}
72
73unsigned char XErrorTrapper::errorCode() const
74{
75 XSync(m_display, False);
76 return m_errorCode;
77}
78
79void XErrorTrapper::errorEvent(XErrorEvent* event)
80{
81 m_errorCode = event->error_code;
82 if (m_policy == Policy::Ignore)
83 return;
84
85 if (m_expectedErrors.contains(m_errorCode))
86 return;
87
88 static const char errorFormatString[] = "The program with pid %d received an X Window System error.\n"
89 "The error was '%s'.\n"
90 " (Details: serial %ld error_code %d request_code %d minor_code %d)\n";
91 char errorMessage[64];
92 XGetErrorText(m_display, m_errorCode, errorMessage, 63);
93 WTFLogAlways(errorFormatString, getpid(), errorMessage, event->serial, event->error_code, event->request_code, event->minor_code);
94
95 if (m_policy == Policy::Crash)
96 CRASH();
97}
98
99} // namespace WebCore
100
101#endif // PLATFORM(X11)
102