File: | var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/UniquePtr.h |
Warning: | line 472, column 5 Memory allocated by malloc() should be deallocated by free(), not 'delete[]' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |||
2 | /* vim:expandtab:shiftwidth=2:tabstop=2: | |||
3 | */ | |||
4 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
7 | ||||
8 | #include "nsGNOMEShellSearchProvider.h" | |||
9 | ||||
10 | #include "nsToolkitCompsCID.h" | |||
11 | #include "nsIFaviconService.h" | |||
12 | #include "base/message_loop.h" // for MessageLoop | |||
13 | #include "base/task.h" // for NewRunnableMethod, etc | |||
14 | #include "mozilla/gfx/2D.h" | |||
15 | #include "nsComponentManagerUtils.h" | |||
16 | #include "nsIIOService.h" | |||
17 | #include "nsIURI.h" | |||
18 | #include "nsNetCID.h" | |||
19 | #include "nsPrintfCString.h" | |||
20 | #include "nsServiceManagerUtils.h" | |||
21 | #include "mozilla/GUniquePtr.h" | |||
22 | #include "mozilla/UniquePtrExtensions.h" | |||
23 | ||||
24 | #include "imgIContainer.h" | |||
25 | #include "imgITools.h" | |||
26 | ||||
27 | using namespace mozilla; | |||
28 | using namespace mozilla::gfx; | |||
29 | ||||
30 | // Mozilla has old GIO version in build roots | |||
31 | #define G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUEGBusNameOwnerFlags(1 << 2) GBusNameOwnerFlags(1 << 2) | |||
32 | ||||
33 | static const char* introspect_template = | |||
34 | "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection " | |||
35 | "1.0//EN\"\n" | |||
36 | "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" | |||
37 | "<node>\n" | |||
38 | " <interface name=\"org.gnome.Shell.SearchProvider2\">\n" | |||
39 | " <method name=\"GetInitialResultSet\">\n" | |||
40 | " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" | |||
41 | " <arg type=\"as\" name=\"results\" direction=\"out\" />\n" | |||
42 | " </method>\n" | |||
43 | " <method name=\"GetSubsearchResultSet\">\n" | |||
44 | " <arg type=\"as\" name=\"previous_results\" direction=\"in\" />\n" | |||
45 | " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" | |||
46 | " <arg type=\"as\" name=\"results\" direction=\"out\" />\n" | |||
47 | " </method>\n" | |||
48 | " <method name=\"GetResultMetas\">\n" | |||
49 | " <arg type=\"as\" name=\"identifiers\" direction=\"in\" />\n" | |||
50 | " <arg type=\"aa{sv}\" name=\"metas\" direction=\"out\" />\n" | |||
51 | " </method>\n" | |||
52 | " <method name=\"ActivateResult\">\n" | |||
53 | " <arg type=\"s\" name=\"identifier\" direction=\"in\" />\n" | |||
54 | " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" | |||
55 | " <arg type=\"u\" name=\"timestamp\" direction=\"in\" />\n" | |||
56 | " </method>\n" | |||
57 | " <method name=\"LaunchSearch\">\n" | |||
58 | " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" | |||
59 | " <arg type=\"u\" name=\"timestamp\" direction=\"in\" />\n" | |||
60 | " </method>\n" | |||
61 | "</interface>\n" | |||
62 | "</node>\n"; | |||
63 | ||||
64 | class AsyncFaviconDataReady final : public nsIFaviconDataCallback { | |||
65 | public: | |||
66 | NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID , void** aInstancePtr) override; virtual MozExternalRefCountType AddRef(void) override; virtual MozExternalRefCountType Release (void) override; using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: | |||
67 | NS_DECL_NSIFAVICONDATACALLBACKvirtual nsresult OnComplete(nsIURI *aFaviconURI, uint32_t aDataLen , const uint8_t *aData, const nsACString& aMimeType, uint16_t aWidth) override; | |||
68 | ||||
69 | AsyncFaviconDataReady(RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult, | |||
70 | int aIconIndex, int aTimeStamp) | |||
71 | : mSearchResult(std::move(aSearchResult)), | |||
72 | mIconIndex(aIconIndex), | |||
73 | mTimeStamp(aTimeStamp) {}; | |||
74 | ||||
75 | private: | |||
76 | ~AsyncFaviconDataReady() {} | |||
77 | ||||
78 | RefPtr<nsGNOMEShellHistorySearchResult> mSearchResult; | |||
79 | int mIconIndex; | |||
80 | int mTimeStamp; | |||
81 | }; | |||
82 | ||||
83 | NS_IMPL_ISUPPORTS(AsyncFaviconDataReady, nsIFaviconDataCallback)MozExternalRefCountType AsyncFaviconDataReady::AddRef(void) { static_assert(!std::is_destructible_v<AsyncFaviconDataReady >, "Reference-counted class " "AsyncFaviconDataReady" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 83; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("AsyncFaviconDataReady" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("AsyncFaviconDataReady" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"AsyncFaviconDataReady\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"AsyncFaviconDataReady\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 83; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership ("AsyncFaviconDataReady" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("AsyncFaviconDataReady" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType AsyncFaviconDataReady::Release(void) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 83 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("AsyncFaviconDataReady" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("AsyncFaviconDataReady" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"AsyncFaviconDataReady\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"AsyncFaviconDataReady\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 83; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership ("AsyncFaviconDataReady" " not thread-safe"); const char* const nametmp = "AsyncFaviconDataReady"; nsrefcnt count = --mRefCnt ; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult AsyncFaviconDataReady::QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak (NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<AsyncFaviconDataReady, nsIFaviconDataCallback >, int32_t( reinterpret_cast<char*>(static_cast<nsIFaviconDataCallback *>((AsyncFaviconDataReady*)0x1000)) - reinterpret_cast< char*>((AsyncFaviconDataReady*)0x1000))}, {&mozilla::detail ::kImplementedIID<AsyncFaviconDataReady, nsISupports>, int32_t (reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIFaviconDataCallback*>((AsyncFaviconDataReady *)0x1000))) - reinterpret_cast<char*>((AsyncFaviconDataReady *)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) / sizeof(table[0])) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID, aInstancePtr , table); return rv; } | |||
84 | ||||
85 | // Inspired by SurfaceToPackedBGRA | |||
86 | static UniquePtr<uint8_t[]> SurfaceToPackedRGBA(DataSourceSurface* aSurface) { | |||
87 | IntSize size = aSurface->GetSize(); | |||
88 | CheckedInt<size_t> bufferSize = | |||
89 | CheckedInt<size_t>(size.width * 4) * CheckedInt<size_t>(size.height); | |||
90 | if (!bufferSize.isValid()) { | |||
| ||||
91 | return nullptr; | |||
92 | } | |||
93 | UniquePtr<uint8_t[]> imageBuffer(new (std::nothrow) | |||
94 | uint8_t[bufferSize.value()]); | |||
95 | if (!imageBuffer) { | |||
96 | return nullptr; | |||
97 | } | |||
98 | ||||
99 | DataSourceSurface::MappedSurface map; | |||
100 | if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) { | |||
101 | return nullptr; | |||
102 | } | |||
103 | ||||
104 | // Convert BGRA to RGBA | |||
105 | uint32_t* aSrc = (uint32_t*)map.mData; | |||
106 | uint32_t* aDst = (uint32_t*)imageBuffer.get(); | |||
107 | for (int i = 0; i < size.width * size.height; i++, aDst++, aSrc++) { | |||
108 | *aDst = *aSrc & 0xff00ff00; | |||
109 | *aDst |= (*aSrc & 0xff) << 16; | |||
110 | *aDst |= (*aSrc & 0xff0000) >> 16; | |||
111 | } | |||
112 | ||||
113 | aSurface->Unmap(); | |||
114 | ||||
115 | return imageBuffer; | |||
116 | } | |||
117 | ||||
118 | NS_IMETHODIMPnsresult | |||
119 | AsyncFaviconDataReady::OnComplete(nsIURI* aFaviconURI, uint32_t aDataLen, | |||
120 | const uint8_t* aData, | |||
121 | const nsACString& aMimeType, | |||
122 | uint16_t aWidth) { | |||
123 | // This is a callback from some previous search so we don't want it | |||
124 | if (mTimeStamp != mSearchResult->GetTimeStamp() || !aData || !aDataLen) { | |||
125 | return NS_ERROR_FAILURE; | |||
126 | } | |||
127 | ||||
128 | // Decode the image from the format it was returned to us in (probably PNG) | |||
129 | nsCOMPtr<imgIContainer> container; | |||
130 | nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1"); | |||
131 | nsresult rv = imgtool->DecodeImageFromBuffer( | |||
132 | reinterpret_cast<const char*>(aData), aDataLen, aMimeType, | |||
133 | getter_AddRefs(container)); | |||
134 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 134); return rv; } } while (false); | |||
135 | ||||
136 | RefPtr<SourceSurface> surface = container->GetFrame( | |||
137 | imgIContainer::FRAME_FIRST, | |||
138 | imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY); | |||
139 | ||||
140 | if (!surface || surface->GetFormat() != SurfaceFormat::B8G8R8A8) { | |||
141 | return NS_ERROR_FAILURE; | |||
142 | } | |||
143 | ||||
144 | // Allocate a new buffer that we own. | |||
145 | RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface(); | |||
146 | UniquePtr<uint8_t[]> data = SurfaceToPackedRGBA(dataSurface); | |||
147 | if (!data) { | |||
148 | return NS_ERROR_OUT_OF_MEMORY; | |||
149 | } | |||
150 | ||||
151 | mSearchResult->SetHistoryIcon(mTimeStamp, std::move(data), | |||
152 | surface->GetSize().width, | |||
153 | surface->GetSize().height, mIconIndex); | |||
154 | return NS_OK; | |||
155 | } | |||
156 | ||||
157 | void nsGNOMEShellSearchProvider::HandleSearchResultSet( | |||
158 | GVariant* aParameters, GDBusMethodInvocation* aInvocation, | |||
159 | bool aInitialSearch) { | |||
160 | // Discard any existing search results. | |||
161 | mSearchResult = nullptr; | |||
162 | ||||
163 | RefPtr<nsGNOMEShellHistorySearchResult> newSearch = | |||
164 | new nsGNOMEShellHistorySearchResult(this, mConnection, | |||
165 | mSearchResultTimeStamp); | |||
166 | mSearchResultTimeStamp++; | |||
167 | newSearch->SetTimeStamp(mSearchResultTimeStamp); | |||
168 | ||||
169 | // Send the search request over DBus. We'll get reply over DBus it will be | |||
170 | // set to mSearchResult by nsGNOMEShellSearchProvider::SetSearchResult(). | |||
171 | DBusHandleResultSet(newSearch.forget(), aParameters, aInitialSearch, | |||
172 | aInvocation); | |||
173 | } | |||
174 | ||||
175 | void nsGNOMEShellSearchProvider::HandleResultMetas( | |||
176 | GVariant* aParameters, GDBusMethodInvocation* aInvocation) { | |||
177 | if (mSearchResult) { | |||
178 | DBusHandleResultMetas(mSearchResult, aParameters, aInvocation); | |||
179 | } | |||
180 | } | |||
181 | ||||
182 | void nsGNOMEShellSearchProvider::ActivateResult( | |||
183 | GVariant* aParameters, GDBusMethodInvocation* aInvocation) { | |||
184 | if (mSearchResult) { | |||
185 | DBusActivateResult(mSearchResult, aParameters, aInvocation); | |||
186 | } | |||
187 | } | |||
188 | ||||
189 | void nsGNOMEShellSearchProvider::LaunchSearch( | |||
190 | GVariant* aParameters, GDBusMethodInvocation* aInvocation) { | |||
191 | if (mSearchResult) { | |||
192 | DBusLaunchSearch(mSearchResult, aParameters, aInvocation); | |||
193 | } | |||
194 | } | |||
195 | ||||
196 | static void HandleMethodCall(GDBusConnection* aConnection, const gchar* aSender, | |||
197 | const gchar* aObjectPath, | |||
198 | const gchar* aInterfaceName, | |||
199 | const gchar* aMethodName, GVariant* aParameters, | |||
200 | GDBusMethodInvocation* aInvocation, | |||
201 | gpointer aUserData) { | |||
202 | MOZ_ASSERT(aUserData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aUserData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aUserData))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aUserData", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 202); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aUserData" ")" ); do { *((volatile int*)__null) = 202; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
203 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 203); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 203; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
204 | ||||
205 | if (strcmp("org.gnome.Shell.SearchProvider2", aInterfaceName) == 0) { | |||
206 | if (strcmp("GetInitialResultSet", aMethodName) == 0) { | |||
207 | static_cast<nsGNOMEShellSearchProvider*>(aUserData) | |||
208 | ->HandleSearchResultSet(aParameters, aInvocation, | |||
209 | /* aInitialSearch */ true); | |||
210 | } else if (strcmp("GetSubsearchResultSet", aMethodName) == 0) { | |||
211 | static_cast<nsGNOMEShellSearchProvider*>(aUserData) | |||
212 | ->HandleSearchResultSet(aParameters, aInvocation, | |||
213 | /* aInitialSearch */ false); | |||
214 | } else if (strcmp("GetResultMetas", aMethodName) == 0) { | |||
215 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->HandleResultMetas( | |||
216 | aParameters, aInvocation); | |||
217 | } else if (strcmp("ActivateResult", aMethodName) == 0) { | |||
218 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->ActivateResult( | |||
219 | aParameters, aInvocation); | |||
220 | } else if (strcmp("LaunchSearch", aMethodName) == 0) { | |||
221 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->LaunchSearch( | |||
222 | aParameters, aInvocation); | |||
223 | } else { | |||
224 | g_warning( | |||
225 | "nsGNOMEShellSearchProvider: HandleMethodCall() wrong method %s", | |||
226 | aMethodName); | |||
227 | } | |||
228 | } | |||
229 | } | |||
230 | ||||
231 | static GVariant* HandleGetProperty(GDBusConnection* aConnection, | |||
232 | const gchar* aSender, | |||
233 | const gchar* aObjectPath, | |||
234 | const gchar* aInterfaceName, | |||
235 | const gchar* aPropertyName, GError** aError, | |||
236 | gpointer aUserData) { | |||
237 | MOZ_ASSERT(aUserData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aUserData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aUserData))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aUserData", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aUserData" ")" ); do { *((volatile int*)__null) = 237; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
238 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 238); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 238; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
239 | g_set_error(aError, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_FAILED, | |||
240 | "%s:%s setting is not supported", aInterfaceName, aPropertyName); | |||
241 | return nullptr; | |||
242 | } | |||
243 | ||||
244 | static gboolean HandleSetProperty(GDBusConnection* aConnection, | |||
245 | const gchar* aSender, | |||
246 | const gchar* aObjectPath, | |||
247 | const gchar* aInterfaceName, | |||
248 | const gchar* aPropertyName, GVariant* aValue, | |||
249 | GError** aError, gpointer aUserData) { | |||
250 | MOZ_ASSERT(aUserData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aUserData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aUserData))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aUserData", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aUserData" ")" ); do { *((volatile int*)__null) = 250; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
251 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 251); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 251; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
252 | g_set_error(aError, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_FAILED, | |||
253 | "%s:%s setting is not supported", aInterfaceName, aPropertyName); | |||
254 | return false; | |||
255 | } | |||
256 | ||||
257 | static const GDBusInterfaceVTable gInterfaceVTable = { | |||
258 | HandleMethodCall, HandleGetProperty, HandleSetProperty}; | |||
259 | ||||
260 | void nsGNOMEShellSearchProvider::OnBusAcquired(GDBusConnection* aConnection) { | |||
261 | GUniquePtr<GError> error; | |||
262 | mIntrospectionData = dont_AddRef(g_dbus_node_info_new_for_xml( | |||
263 | introspect_template, getter_Transfers(error))); | |||
264 | if (!mIntrospectionData) { | |||
265 | g_warning( | |||
266 | "nsGNOMEShellSearchProvider: g_dbus_node_info_new_for_xml() failed! %s", | |||
267 | error->message); | |||
268 | return; | |||
269 | } | |||
270 | ||||
271 | mRegistrationId = g_dbus_connection_register_object( | |||
272 | aConnection, GetDBusObjectPath(), mIntrospectionData->interfaces[0], | |||
273 | &gInterfaceVTable, this, /* user_data */ | |||
274 | nullptr, /* user_data_free_func */ | |||
275 | getter_Transfers(error)); /* GError** */ | |||
276 | ||||
277 | if (mRegistrationId == 0) { | |||
278 | g_warning( | |||
279 | "nsGNOMEShellSearchProvider: g_dbus_connection_register_object() " | |||
280 | "failed! %s", | |||
281 | error->message); | |||
282 | return; | |||
283 | } | |||
284 | } | |||
285 | ||||
286 | void nsGNOMEShellSearchProvider::OnNameAcquired(GDBusConnection* aConnection) { | |||
287 | mConnection = aConnection; | |||
288 | } | |||
289 | ||||
290 | void nsGNOMEShellSearchProvider::OnNameLost(GDBusConnection* aConnection) { | |||
291 | mConnection = nullptr; | |||
292 | if (!mRegistrationId) { | |||
293 | return; | |||
294 | } | |||
295 | if (g_dbus_connection_unregister_object(aConnection, mRegistrationId)) { | |||
296 | mRegistrationId = 0; | |||
297 | } | |||
298 | } | |||
299 | ||||
300 | nsresult nsGNOMEShellSearchProvider::Startup() { | |||
301 | if (mDBusID) { | |||
302 | // We're already connected so we don't need to reconnect | |||
303 | return NS_ERROR_ALREADY_INITIALIZED; | |||
304 | } | |||
305 | ||||
306 | mDBusID = g_bus_own_name( | |||
307 | G_BUS_TYPE_SESSION, GetDBusBusName(), G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUEGBusNameOwnerFlags(1 << 2), | |||
308 | [](GDBusConnection* aConnection, const gchar*, | |||
309 | gpointer aUserData) -> void { | |||
310 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->OnBusAcquired( | |||
311 | aConnection); | |||
312 | }, | |||
313 | [](GDBusConnection* aConnection, const gchar*, | |||
314 | gpointer aUserData) -> void { | |||
315 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->OnNameAcquired( | |||
316 | aConnection); | |||
317 | }, | |||
318 | [](GDBusConnection* aConnection, const gchar*, | |||
319 | gpointer aUserData) -> void { | |||
320 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->OnNameLost( | |||
321 | aConnection); | |||
322 | }, | |||
323 | this, nullptr); | |||
324 | ||||
325 | if (!mDBusID) { | |||
326 | g_warning("nsGNOMEShellSearchProvider: g_bus_own_name() failed!"); | |||
327 | return NS_ERROR_FAILURE; | |||
328 | } | |||
329 | ||||
330 | mSearchResultTimeStamp = 0; | |||
331 | return NS_OK; | |||
332 | } | |||
333 | ||||
334 | void nsGNOMEShellSearchProvider::Shutdown() { | |||
335 | OnNameLost(mConnection); | |||
336 | if (mDBusID) { | |||
337 | g_bus_unown_name(mDBusID); | |||
338 | mDBusID = 0; | |||
339 | } | |||
340 | mIntrospectionData = nullptr; | |||
341 | } | |||
342 | ||||
343 | bool nsGNOMEShellSearchProvider::SetSearchResult( | |||
344 | RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult) { | |||
345 | MOZ_ASSERT(!mSearchResult)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!mSearchResult)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!mSearchResult))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mSearchResult" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 345); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mSearchResult" ")"); do { *((volatile int*)__null) = 345; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
346 | ||||
347 | if (mSearchResultTimeStamp != aSearchResult->GetTimeStamp()) { | |||
348 | NS_WARNING("Time stamp mismatch.")NS_DebugBreak(NS_DEBUG_WARNING, "Time stamp mismatch.", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 348); | |||
349 | return false; | |||
350 | } | |||
351 | mSearchResult = aSearchResult; | |||
352 | return true; | |||
353 | } | |||
354 | ||||
355 | static void DispatchSearchResults( | |||
356 | RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult, | |||
357 | nsCOMPtr<nsINavHistoryContainerResultNode> aHistResultContainer) { | |||
358 | aSearchResult->ReceiveSearchResultContainer(aHistResultContainer); | |||
359 | } | |||
360 | ||||
361 | nsresult nsGNOMEShellHistoryService::QueryHistory( | |||
362 | RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult) { | |||
363 | if (!mHistoryService) { | |||
364 | mHistoryService = do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID"@mozilla.org/browser/nav-history-service;1"); | |||
365 | if (!mHistoryService) { | |||
366 | return NS_ERROR_FAILURE; | |||
367 | } | |||
368 | } | |||
369 | ||||
370 | nsresult rv; | |||
371 | nsCOMPtr<nsINavHistoryQuery> histQuery; | |||
372 | rv = mHistoryService->GetNewQuery(getter_AddRefs(histQuery)); | |||
373 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 373); return rv; } } while (false); | |||
374 | ||||
375 | rv = histQuery->SetSearchTerms( | |||
376 | NS_ConvertUTF8toUTF16(aSearchResult->GetSearchTerm())); | |||
377 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 377); return rv; } } while (false); | |||
378 | ||||
379 | nsCOMPtr<nsINavHistoryQueryOptions> histQueryOpts; | |||
380 | rv = mHistoryService->GetNewQueryOptions(getter_AddRefs(histQueryOpts)); | |||
381 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 381); return rv; } } while (false); | |||
382 | ||||
383 | rv = histQueryOpts->SetSortingMode( | |||
384 | nsINavHistoryQueryOptions::SORT_BY_FRECENCY_DESCENDING); | |||
385 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 385); return rv; } } while (false); | |||
386 | ||||
387 | rv = histQueryOpts->SetMaxResults(MAX_SEARCH_RESULTS_NUM9); | |||
388 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 388); return rv; } } while (false); | |||
389 | ||||
390 | nsCOMPtr<nsINavHistoryResult> histResult; | |||
391 | rv = mHistoryService->ExecuteQuery(histQuery, histQueryOpts, | |||
392 | getter_AddRefs(histResult)); | |||
393 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 393); return rv; } } while (false); | |||
394 | ||||
395 | nsCOMPtr<nsINavHistoryContainerResultNode> resultContainer; | |||
396 | ||||
397 | rv = histResult->GetRoot(getter_AddRefs(resultContainer)); | |||
398 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 398); return rv; } } while (false); | |||
399 | ||||
400 | rv = resultContainer->SetContainerOpen(true); | |||
401 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 401); return rv; } } while (false); | |||
402 | ||||
403 | // Simulate async searching by delayed reply. This search API will | |||
404 | // likely become async in the future and we want to be sure to not rely on | |||
405 | // its current synchronous behavior. | |||
406 | MOZ_ASSERT(MessageLoop::current())do { static_assert( mozilla::detail::AssertionConditionType< decltype(MessageLoop::current())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(MessageLoop::current()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("MessageLoop::current()" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 406); AnnotateMozCrashReason("MOZ_ASSERT" "(" "MessageLoop::current()" ")"); do { *((volatile int*)__null) = 406; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
407 | MessageLoop::current()->PostTask( | |||
408 | NewRunnableFunction("Gnome shell search results", &DispatchSearchResults, | |||
409 | aSearchResult, resultContainer)); | |||
410 | ||||
411 | return NS_OK; | |||
412 | } | |||
413 | ||||
414 | static void DBusGetIDKeyForURI(int aIndex, nsAutoCString& aUri, | |||
415 | nsAutoCString& aIDKey) { | |||
416 | // Compose ID as NN:URL where NN is index to our current history | |||
417 | // result container. | |||
418 | aIDKey = nsPrintfCString("%.2d:%s", aIndex, aUri.get()); | |||
419 | } | |||
420 | ||||
421 | // Send (as) rearch result reply | |||
422 | void nsGNOMEShellHistorySearchResult::HandleSearchResultReply() { | |||
423 | MOZ_ASSERT(mReply)do { static_assert( mozilla::detail::AssertionConditionType< decltype(mReply)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(mReply))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mReply", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 423); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mReply" ")") ; do { *((volatile int*)__null) = 423; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
424 | ||||
425 | GVariantBuilder b; | |||
426 | g_variant_builder_init(&b, G_VARIANT_TYPE("as")(g_variant_type_checked_ (("as")))); | |||
427 | ||||
428 | uint32_t childCount = 0; | |||
429 | nsresult rv = mHistResultContainer->GetChildCount(&childCount); | |||
430 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && childCount > 0) { | |||
431 | // Obtain the favicon service and get the favicon for the specified page | |||
432 | nsCOMPtr<nsIFaviconService> favIconSvc( | |||
433 | do_GetService("@mozilla.org/browser/favicon-service;1")); | |||
434 | nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID"@mozilla.org/network/io-service;1")); | |||
435 | ||||
436 | if (childCount > MAX_SEARCH_RESULTS_NUM9) { | |||
437 | childCount = MAX_SEARCH_RESULTS_NUM9; | |||
438 | } | |||
439 | ||||
440 | for (uint32_t i = 0; i < childCount; i++) { | |||
441 | nsCOMPtr<nsINavHistoryResultNode> child; | |||
442 | rv = mHistResultContainer->GetChild(i, getter_AddRefs(child)); | |||
443 | if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv )), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 443)) { | |||
444 | continue; | |||
445 | } | |||
446 | if (!IsHistoryResultNodeURI(child)) { | |||
447 | continue; | |||
448 | } | |||
449 | ||||
450 | nsAutoCString uri; | |||
451 | child->GetUri(uri); | |||
452 | ||||
453 | nsCOMPtr<nsIURI> iconIri; | |||
454 | ios->NewURI(uri, nullptr, nullptr, getter_AddRefs(iconIri)); | |||
455 | nsCOMPtr<nsIFaviconDataCallback> callback = | |||
456 | new AsyncFaviconDataReady(this, i, mTimeStamp); | |||
457 | favIconSvc->GetFaviconDataForPage(iconIri, callback, 0); | |||
458 | ||||
459 | nsAutoCString idKey; | |||
460 | DBusGetIDKeyForURI(i, uri, idKey); | |||
461 | ||||
462 | g_variant_builder_add(&b, "s", idKey.get()); | |||
463 | } | |||
464 | } | |||
465 | ||||
466 | nsPrintfCString searchString("%s:%s", KEYWORD_SEARCH_STRING"special:search", | |||
467 | mSearchTerm.get()); | |||
468 | g_variant_builder_add(&b, "s", searchString.get()); | |||
469 | ||||
470 | GVariant* v = g_variant_builder_end(&b); | |||
471 | g_dbus_method_invocation_return_value(mReply, g_variant_new_tuple(&v, 1)); | |||
472 | mReply = nullptr; | |||
473 | } | |||
474 | ||||
475 | void nsGNOMEShellHistorySearchResult::ReceiveSearchResultContainer( | |||
476 | nsCOMPtr<nsINavHistoryContainerResultNode> aHistResultContainer) { | |||
477 | // Propagate search results to nsGNOMEShellSearchProvider. | |||
478 | // SetSearchResult() checks this is up-to-date search (our time stamp matches | |||
479 | // latest requested search timestamp). | |||
480 | if (mSearchProvider->SetSearchResult(this)) { | |||
481 | mHistResultContainer = aHistResultContainer; | |||
482 | HandleSearchResultReply(); | |||
483 | } | |||
484 | } | |||
485 | ||||
486 | void nsGNOMEShellHistorySearchResult::SetHistoryIcon(int aTimeStamp, | |||
487 | UniquePtr<uint8_t[]> aData, | |||
488 | int aWidth, int aHeight, | |||
489 | int aIconIndex) { | |||
490 | MOZ_ASSERT(mTimeStamp == aTimeStamp)do { static_assert( mozilla::detail::AssertionConditionType< decltype(mTimeStamp == aTimeStamp)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mTimeStamp == aTimeStamp))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mTimeStamp == aTimeStamp" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 490); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTimeStamp == aTimeStamp" ")"); do { *((volatile int*)__null) = 490; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
491 | MOZ_RELEASE_ASSERT(aIconIndex < MAX_SEARCH_RESULTS_NUM)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aIconIndex < 9)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aIconIndex < 9))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aIconIndex < 9" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 491); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "aIconIndex < 9" ")"); do { *((volatile int*)__null) = 491; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
492 | mHistoryIcons[aIconIndex].Set(mTimeStamp, std::move(aData), aWidth, aHeight); | |||
493 | } | |||
494 | ||||
495 | GnomeHistoryIcon* nsGNOMEShellHistorySearchResult::GetHistoryIcon( | |||
496 | int aIconIndex) { | |||
497 | MOZ_RELEASE_ASSERT(aIconIndex < MAX_SEARCH_RESULTS_NUM)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aIconIndex < 9)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aIconIndex < 9))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aIconIndex < 9" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 497); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "aIconIndex < 9" ")"); do { *((volatile int*)__null) = 497; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
498 | if (mHistoryIcons[aIconIndex].GetTimeStamp() == mTimeStamp && | |||
499 | mHistoryIcons[aIconIndex].IsLoaded()) { | |||
500 | return mHistoryIcons + aIconIndex; | |||
501 | } | |||
502 | return nullptr; | |||
503 | } | |||
504 | ||||
505 | nsGNOMEShellHistoryService* GetGNOMEShellHistoryService() { | |||
506 | static nsGNOMEShellHistoryService gGNOMEShellHistoryService; | |||
507 | return &gGNOMEShellHistoryService; | |||
508 | } |
1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | |
5 | #ifndef mozilla_cxxalloc_h |
6 | #define mozilla_cxxalloc_h |
7 | |
8 | /* |
9 | * We implement the default operators new/delete as part of |
10 | * libmozalloc, replacing their definitions in libstdc++. The |
11 | * operator new* definitions in libmozalloc will never return a NULL |
12 | * pointer. |
13 | * |
14 | * Each operator new immediately below returns a pointer to memory |
15 | * that can be delete'd by any of |
16 | * |
17 | * (1) the matching infallible operator delete immediately below |
18 | * (2) the matching system |operator delete(void*, std::nothrow)| |
19 | * (3) the matching system |operator delete(void*) noexcept(false)| |
20 | * |
21 | * NB: these are declared |noexcept(false)|, though they will never |
22 | * throw that exception. This declaration is consistent with the rule |
23 | * that |::operator new() noexcept(false)| will never return NULL. |
24 | * |
25 | * NB: mozilla::fallible can be used instead of std::nothrow. |
26 | */ |
27 | |
28 | #ifndef MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline |
29 | # define MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) |
30 | #endif |
31 | |
32 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new(size_t size) noexcept(false) { |
33 | return moz_xmalloc(size); |
34 | } |
35 | |
36 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new(size_t size, |
37 | const std::nothrow_t&) noexcept(true) { |
38 | return malloc_implmalloc(size); |
39 | } |
40 | |
41 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new[](size_t size) noexcept(false) { |
42 | return moz_xmalloc(size); |
43 | } |
44 | |
45 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new[](size_t size, |
46 | const std::nothrow_t&) noexcept(true) { |
47 | return malloc_implmalloc(size); |
48 | } |
49 | |
50 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete(void* ptr) noexcept(true) { |
51 | return free_implfree(ptr); |
52 | } |
53 | |
54 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete(void* ptr, |
55 | const std::nothrow_t&) noexcept(true) { |
56 | return free_implfree(ptr); |
57 | } |
58 | |
59 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete[](void* ptr) noexcept(true) { |
60 | return free_implfree(ptr); |
61 | } |
62 | |
63 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete[]( |
64 | void* ptr, const std::nothrow_t&) noexcept(true) { |
65 | return free_implfree(ptr); |
66 | } |
67 | |
68 | #if defined(XP_WIN) |
69 | // We provide the global sized delete overloads unconditionally because the |
70 | // MSVC runtime headers do, despite compiling with /Zc:sizedDealloc- |
71 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete(void* ptr, |
72 | size_t /*size*/) noexcept(true) { |
73 | return free_implfree(ptr); |
74 | } |
75 | |
76 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete[](void* ptr, |
77 | size_t /*size*/) noexcept(true) { |
78 | return free_implfree(ptr); |
79 | } |
80 | #endif |
81 | |
82 | #endif /* mozilla_cxxalloc_h */ |
1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |||
2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ | |||
3 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
4 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
6 | ||||
7 | /* Smart pointer managing sole ownership of a resource. */ | |||
8 | ||||
9 | #ifndef mozilla_UniquePtr_h | |||
10 | #define mozilla_UniquePtr_h | |||
11 | ||||
12 | #include <memory> | |||
13 | #include <type_traits> | |||
14 | #include <utility> | |||
15 | ||||
16 | #include "mozilla/Assertions.h" | |||
17 | #include "mozilla/Attributes.h" | |||
18 | #include "mozilla/CompactPair.h" | |||
19 | #include "mozilla/Compiler.h" | |||
20 | ||||
21 | namespace mozilla { | |||
22 | ||||
23 | template <typename T> | |||
24 | class DefaultDelete; | |||
25 | template <typename T, class D = DefaultDelete<T>> | |||
26 | class UniquePtr; | |||
27 | ||||
28 | } // namespace mozilla | |||
29 | ||||
30 | namespace mozilla { | |||
31 | ||||
32 | namespace detail { | |||
33 | ||||
34 | struct HasPointerTypeHelper { | |||
35 | template <class U> | |||
36 | static double Test(...); | |||
37 | template <class U> | |||
38 | static char Test(typename U::pointer* = 0); | |||
39 | }; | |||
40 | ||||
41 | template <class T> | |||
42 | class HasPointerType | |||
43 | : public std::integral_constant<bool, sizeof(HasPointerTypeHelper::Test<T>( | |||
44 | 0)) == 1> {}; | |||
45 | ||||
46 | template <class T, class D, bool = HasPointerType<D>::value> | |||
47 | struct PointerTypeImpl { | |||
48 | typedef typename D::pointer Type; | |||
49 | }; | |||
50 | ||||
51 | template <class T, class D> | |||
52 | struct PointerTypeImpl<T, D, false> { | |||
53 | typedef T* Type; | |||
54 | }; | |||
55 | ||||
56 | template <class T, class D> | |||
57 | struct PointerType { | |||
58 | typedef typename PointerTypeImpl<T, std::remove_reference_t<D>>::Type Type; | |||
59 | }; | |||
60 | ||||
61 | } // namespace detail | |||
62 | ||||
63 | /** | |||
64 | * UniquePtr is a smart pointer that wholly owns a resource. Ownership may be | |||
65 | * transferred out of a UniquePtr through explicit action, but otherwise the | |||
66 | * resource is destroyed when the UniquePtr is destroyed. | |||
67 | * | |||
68 | * UniquePtr is similar to C++98's std::auto_ptr, but it improves upon auto_ptr | |||
69 | * in one crucial way: it's impossible to copy a UniquePtr. Copying an auto_ptr | |||
70 | * obviously *can't* copy ownership of its singly-owned resource. So what | |||
71 | * happens if you try to copy one? Bizarrely, ownership is implicitly | |||
72 | * *transferred*, preserving single ownership but breaking code that assumes a | |||
73 | * copy of an object is identical to the original. (This is why auto_ptr is | |||
74 | * prohibited in STL containers.) | |||
75 | * | |||
76 | * UniquePtr solves this problem by being *movable* rather than copyable. | |||
77 | * Instead of passing a |UniquePtr u| directly to the constructor or assignment | |||
78 | * operator, you pass |Move(u)|. In doing so you indicate that you're *moving* | |||
79 | * ownership out of |u|, into the target of the construction/assignment. After | |||
80 | * the transfer completes, |u| contains |nullptr| and may be safely destroyed. | |||
81 | * This preserves single ownership but also allows UniquePtr to be moved by | |||
82 | * algorithms that have been made move-safe. (Note: if |u| is instead a | |||
83 | * temporary expression, don't use |Move()|: just pass the expression, because | |||
84 | * it's already move-ready. For more information see Move.h.) | |||
85 | * | |||
86 | * UniquePtr is also better than std::auto_ptr in that the deletion operation is | |||
87 | * customizable. An optional second template parameter specifies a class that | |||
88 | * (through its operator()(T*)) implements the desired deletion policy. If no | |||
89 | * policy is specified, mozilla::DefaultDelete<T> is used -- which will either | |||
90 | * |delete| or |delete[]| the resource, depending whether the resource is an | |||
91 | * array. Custom deletion policies ideally should be empty classes (no member | |||
92 | * fields, no member fields in base classes, no virtual methods/inheritance), | |||
93 | * because then UniquePtr can be just as efficient as a raw pointer. | |||
94 | * | |||
95 | * Use of UniquePtr proceeds like so: | |||
96 | * | |||
97 | * UniquePtr<int> g1; // initializes to nullptr | |||
98 | * g1.reset(new int); // switch resources using reset() | |||
99 | * g1 = nullptr; // clears g1, deletes the int | |||
100 | * | |||
101 | * UniquePtr<int> g2(new int); // owns that int | |||
102 | * int* p = g2.release(); // g2 leaks its int -- still requires deletion | |||
103 | * delete p; // now freed | |||
104 | * | |||
105 | * struct S { int x; S(int x) : x(x) {} }; | |||
106 | * UniquePtr<S> g3, g4(new S(5)); | |||
107 | * g3 = std::move(g4); // g3 owns the S, g4 cleared | |||
108 | * S* p = g3.get(); // g3 still owns |p| | |||
109 | * assert(g3->x == 5); // operator-> works (if .get() != nullptr) | |||
110 | * assert((*g3).x == 5); // also operator* (again, if not cleared) | |||
111 | * std::swap(g3, g4); // g4 now owns the S, g3 cleared | |||
112 | * g3.swap(g4); // g3 now owns the S, g4 cleared | |||
113 | * UniquePtr<S> g5(std::move(g3)); // g5 owns the S, g3 cleared | |||
114 | * g5.reset(); // deletes the S, g5 cleared | |||
115 | * | |||
116 | * struct FreePolicy { void operator()(void* p) { free(p); } }; | |||
117 | * UniquePtr<int, FreePolicy> g6(static_cast<int*>(malloc(sizeof(int)))); | |||
118 | * int* ptr = g6.get(); | |||
119 | * g6 = nullptr; // calls free(ptr) | |||
120 | * | |||
121 | * Now, carefully note a few things you *can't* do: | |||
122 | * | |||
123 | * UniquePtr<int> b1; | |||
124 | * b1 = new int; // BAD: can only assign another UniquePtr | |||
125 | * int* ptr = b1; // BAD: no auto-conversion to pointer, use get() | |||
126 | * | |||
127 | * UniquePtr<int> b2(b1); // BAD: can't copy a UniquePtr | |||
128 | * UniquePtr<int> b3 = b1; // BAD: can't copy-assign a UniquePtr | |||
129 | * | |||
130 | * (Note that changing a UniquePtr to store a direct |new| expression is | |||
131 | * permitted, but usually you should use MakeUnique, defined at the end of this | |||
132 | * header.) | |||
133 | * | |||
134 | * A few miscellaneous notes: | |||
135 | * | |||
136 | * UniquePtr, when not instantiated for an array type, can be move-constructed | |||
137 | * and move-assigned, not only from itself but from "derived" UniquePtr<U, E> | |||
138 | * instantiations where U converts to T and E converts to D. If you want to use | |||
139 | * this, you're going to have to specify a deletion policy for both UniquePtr | |||
140 | * instantations, and T pretty much has to have a virtual destructor. In other | |||
141 | * words, this doesn't work: | |||
142 | * | |||
143 | * struct Base { virtual ~Base() {} }; | |||
144 | * struct Derived : Base {}; | |||
145 | * | |||
146 | * UniquePtr<Base> b1; | |||
147 | * // BAD: DefaultDelete<Base> and DefaultDelete<Derived> don't interconvert | |||
148 | * UniquePtr<Derived> d1(std::move(b)); | |||
149 | * | |||
150 | * UniquePtr<Base> b2; | |||
151 | * UniquePtr<Derived, DefaultDelete<Base>> d2(std::move(b2)); // okay | |||
152 | * | |||
153 | * UniquePtr is specialized for array types. Specializing with an array type | |||
154 | * creates a smart-pointer version of that array -- not a pointer to such an | |||
155 | * array. | |||
156 | * | |||
157 | * UniquePtr<int[]> arr(new int[5]); | |||
158 | * arr[0] = 4; | |||
159 | * | |||
160 | * What else is different? Deletion of course uses |delete[]|. An operator[] | |||
161 | * is provided. Functionality that doesn't make sense for arrays is removed. | |||
162 | * The constructors and mutating methods only accept array pointers (not T*, U* | |||
163 | * that converts to T*, or UniquePtr<U[]> or UniquePtr<U>) or |nullptr|. | |||
164 | * | |||
165 | * It's perfectly okay for a function to return a UniquePtr. This transfers | |||
166 | * the UniquePtr's sole ownership of the data, to the fresh UniquePtr created | |||
167 | * in the calling function, that will then solely own that data. Such functions | |||
168 | * can return a local variable UniquePtr, |nullptr|, |UniquePtr(ptr)| where | |||
169 | * |ptr| is a |T*|, or a UniquePtr |Move()|'d from elsewhere. | |||
170 | * | |||
171 | * UniquePtr will commonly be a member of a class, with lifetime equivalent to | |||
172 | * that of that class. If you want to expose the related resource, you could | |||
173 | * expose a raw pointer via |get()|, but ownership of a raw pointer is | |||
174 | * inherently unclear. So it's better to expose a |const UniquePtr&| instead. | |||
175 | * This prohibits mutation but still allows use of |get()| when needed (but | |||
176 | * operator-> is preferred). Of course, you can only use this smart pointer as | |||
177 | * long as the enclosing class instance remains live -- no different than if you | |||
178 | * exposed the |get()| raw pointer. | |||
179 | * | |||
180 | * To pass a UniquePtr-managed resource as a pointer, use a |const UniquePtr&| | |||
181 | * argument. To specify an inout parameter (where the method may or may not | |||
182 | * take ownership of the resource, or reset it), or to specify an out parameter | |||
183 | * (where simply returning a |UniquePtr| isn't possible), use a |UniquePtr&| | |||
184 | * argument. To unconditionally transfer ownership of a UniquePtr | |||
185 | * into a method, use a |UniquePtr| argument. To conditionally transfer | |||
186 | * ownership of a resource into a method, should the method want it, use a | |||
187 | * |UniquePtr&&| argument. | |||
188 | */ | |||
189 | template <typename T, class D> | |||
190 | class UniquePtr { | |||
191 | public: | |||
192 | typedef T ElementType; | |||
193 | typedef D DeleterType; | |||
194 | typedef typename detail::PointerType<T, DeleterType>::Type Pointer; | |||
195 | ||||
196 | private: | |||
197 | mozilla::CompactPair<Pointer, DeleterType> mTuple; | |||
198 | ||||
199 | Pointer& ptr() { return mTuple.first(); } | |||
200 | const Pointer& ptr() const { return mTuple.first(); } | |||
201 | ||||
202 | DeleterType& del() { return mTuple.second(); } | |||
203 | const DeleterType& del() const { return mTuple.second(); } | |||
204 | ||||
205 | public: | |||
206 | /** | |||
207 | * Construct a UniquePtr containing |nullptr|. | |||
208 | */ | |||
209 | constexpr UniquePtr() : mTuple(static_cast<Pointer>(nullptr), DeleterType()) { | |||
210 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); | |||
211 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); | |||
212 | } | |||
213 | ||||
214 | /** | |||
215 | * Construct a UniquePtr containing |aPtr|. | |||
216 | */ | |||
217 | explicit UniquePtr(Pointer aPtr) : mTuple(aPtr, DeleterType()) { | |||
218 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); | |||
219 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); | |||
220 | } | |||
221 | ||||
222 | UniquePtr(Pointer aPtr, | |||
223 | std::conditional_t<std::is_reference_v<D>, D, const D&> aD1) | |||
224 | : mTuple(aPtr, aD1) {} | |||
225 | ||||
226 | UniquePtr(Pointer aPtr, std::remove_reference_t<D>&& aD2) | |||
227 | : mTuple(aPtr, std::move(aD2)) { | |||
228 | static_assert(!std::is_reference_v<D>, | |||
229 | "rvalue deleter can't be stored by reference"); | |||
230 | } | |||
231 | ||||
232 | UniquePtr(UniquePtr&& aOther) | |||
233 | : mTuple(aOther.release(), | |||
234 | std::forward<DeleterType>(aOther.get_deleter())) {} | |||
235 | ||||
236 | MOZ_IMPLICIT constexpr UniquePtr(decltype(nullptr)) : UniquePtr() {} | |||
237 | ||||
238 | template <typename U, class E> | |||
239 | MOZ_IMPLICIT UniquePtr( | |||
240 | UniquePtr<U, E>&& aOther, | |||
241 | std::enable_if_t< | |||
242 | std::is_convertible_v<typename UniquePtr<U, E>::Pointer, Pointer> && | |||
243 | !std::is_array_v<U> && | |||
244 | (std::is_reference_v<D> ? std::is_same_v<D, E> | |||
245 | : std::is_convertible_v<E, D>), | |||
246 | int> | |||
247 | aDummy = 0) | |||
248 | : mTuple(aOther.release(), std::forward<E>(aOther.get_deleter())) {} | |||
249 | ||||
250 | ~UniquePtr() { reset(nullptr); } | |||
251 | ||||
252 | UniquePtr& operator=(UniquePtr&& aOther) { | |||
253 | reset(aOther.release()); | |||
254 | get_deleter() = std::forward<DeleterType>(aOther.get_deleter()); | |||
255 | return *this; | |||
256 | } | |||
257 | ||||
258 | template <typename U, typename E> | |||
259 | UniquePtr& operator=(UniquePtr<U, E>&& aOther) { | |||
260 | static_assert( | |||
261 | std::is_convertible_v<typename UniquePtr<U, E>::Pointer, Pointer>, | |||
262 | "incompatible UniquePtr pointees"); | |||
263 | static_assert(!std::is_array_v<U>, | |||
264 | "can't assign from UniquePtr holding an array"); | |||
265 | ||||
266 | reset(aOther.release()); | |||
267 | get_deleter() = std::forward<E>(aOther.get_deleter()); | |||
268 | return *this; | |||
269 | } | |||
270 | ||||
271 | UniquePtr& operator=(decltype(nullptr)) { | |||
272 | reset(nullptr); | |||
273 | return *this; | |||
274 | } | |||
275 | ||||
276 | std::add_lvalue_reference_t<T> operator*() const { | |||
277 | MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr with *")do { static_assert( mozilla::detail::AssertionConditionType< decltype(get())>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(get()))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("get()" " (" "dereferencing a UniquePtr containing nullptr with *" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/UniquePtr.h" , 277); AnnotateMozCrashReason("MOZ_ASSERT" "(" "get()" ") (" "dereferencing a UniquePtr containing nullptr with *" ")"); do { *((volatile int*)__null) = 277; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); | |||
278 | return *get(); | |||
279 | } | |||
280 | Pointer operator->() const { | |||
281 | MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr with ->")do { static_assert( mozilla::detail::AssertionConditionType< decltype(get())>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(get()))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("get()" " (" "dereferencing a UniquePtr containing nullptr with ->" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/UniquePtr.h" , 281); AnnotateMozCrashReason("MOZ_ASSERT" "(" "get()" ") (" "dereferencing a UniquePtr containing nullptr with ->" ")" ); do { *((volatile int*)__null) = 281; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
282 | return get(); | |||
283 | } | |||
284 | ||||
285 | explicit operator bool() const { return get() != nullptr; } | |||
286 | ||||
287 | Pointer get() const { return ptr(); } | |||
288 | ||||
289 | DeleterType& get_deleter() { return del(); } | |||
290 | const DeleterType& get_deleter() const { return del(); } | |||
291 | ||||
292 | [[nodiscard]] Pointer release() { | |||
293 | Pointer p = ptr(); | |||
294 | ptr() = nullptr; | |||
295 | return p; | |||
296 | } | |||
297 | ||||
298 | void reset(Pointer aPtr = Pointer()) { | |||
299 | Pointer old = ptr(); | |||
300 | ptr() = aPtr; | |||
301 | if (old != nullptr) { | |||
302 | get_deleter()(old); | |||
303 | } | |||
304 | } | |||
305 | ||||
306 | void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } | |||
307 | ||||
308 | UniquePtr(const UniquePtr& aOther) = delete; // construct using std::move()! | |||
309 | void operator=(const UniquePtr& aOther) = | |||
310 | delete; // assign using std::move()! | |||
311 | }; | |||
312 | ||||
313 | // In case you didn't read the comment by the main definition (you should!): the | |||
314 | // UniquePtr<T[]> specialization exists to manage array pointers. It deletes | |||
315 | // such pointers using delete[], it will reject construction and modification | |||
316 | // attempts using U* or U[]. Otherwise it works like the normal UniquePtr. | |||
317 | template <typename T, class D> | |||
318 | class UniquePtr<T[], D> { | |||
319 | public: | |||
320 | typedef T* Pointer; | |||
321 | typedef T ElementType; | |||
322 | typedef D DeleterType; | |||
323 | ||||
324 | private: | |||
325 | mozilla::CompactPair<Pointer, DeleterType> mTuple; | |||
326 | ||||
327 | public: | |||
328 | /** | |||
329 | * Construct a UniquePtr containing nullptr. | |||
330 | */ | |||
331 | constexpr UniquePtr() : mTuple(static_cast<Pointer>(nullptr), DeleterType()) { | |||
332 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); | |||
333 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); | |||
334 | } | |||
335 | ||||
336 | /** | |||
337 | * Construct a UniquePtr containing |aPtr|. | |||
338 | */ | |||
339 | explicit UniquePtr(Pointer aPtr) : mTuple(aPtr, DeleterType()) { | |||
340 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); | |||
341 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); | |||
342 | } | |||
343 | ||||
344 | // delete[] knows how to handle *only* an array of a single class type. For | |||
345 | // delete[] to work correctly, it must know the size of each element, the | |||
346 | // fields and base classes of each element requiring destruction, and so on. | |||
347 | // So forbid all overloads which would end up invoking delete[] on a pointer | |||
348 | // of the wrong type. | |||
349 | template <typename U> | |||
350 | UniquePtr(U&& aU, | |||
351 | std::enable_if_t< | |||
352 | std::is_pointer_v<U> && std::is_convertible_v<U, Pointer>, int> | |||
353 | aDummy = 0) = delete; | |||
354 | ||||
355 | UniquePtr(Pointer aPtr, | |||
356 | std::conditional_t<std::is_reference_v<D>, D, const D&> aD1) | |||
357 | : mTuple(aPtr, aD1) {} | |||
358 | ||||
359 | UniquePtr(Pointer aPtr, std::remove_reference_t<D>&& aD2) | |||
360 | : mTuple(aPtr, std::move(aD2)) { | |||
361 | static_assert(!std::is_reference_v<D>, | |||
362 | "rvalue deleter can't be stored by reference"); | |||
363 | } | |||
364 | ||||
365 | // Forbidden for the same reasons as stated above. | |||
366 | template <typename U, typename V> | |||
367 | UniquePtr(U&& aU, V&& aV, | |||
368 | std::enable_if_t< | |||
369 | std::is_pointer_v<U> && std::is_convertible_v<U, Pointer>, int> | |||
370 | aDummy = 0) = delete; | |||
371 | ||||
372 | UniquePtr(UniquePtr&& aOther) | |||
373 | : mTuple(aOther.release(), | |||
374 | std::forward<DeleterType>(aOther.get_deleter())) {} | |||
375 | ||||
376 | MOZ_IMPLICIT | |||
377 | UniquePtr(decltype(nullptr)) : mTuple(nullptr, DeleterType()) { | |||
378 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); | |||
379 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); | |||
380 | } | |||
381 | ||||
382 | ~UniquePtr() { reset(nullptr); } | |||
383 | ||||
384 | UniquePtr& operator=(UniquePtr&& aOther) { | |||
385 | reset(aOther.release()); | |||
386 | get_deleter() = std::forward<DeleterType>(aOther.get_deleter()); | |||
387 | return *this; | |||
388 | } | |||
389 | ||||
390 | UniquePtr& operator=(decltype(nullptr)) { | |||
391 | reset(); | |||
392 | return *this; | |||
393 | } | |||
394 | ||||
395 | explicit operator bool() const { return get() != nullptr; } | |||
396 | ||||
397 | T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; } | |||
398 | Pointer get() const { return mTuple.first(); } | |||
399 | ||||
400 | DeleterType& get_deleter() { return mTuple.second(); } | |||
401 | const DeleterType& get_deleter() const { return mTuple.second(); } | |||
402 | ||||
403 | [[nodiscard]] Pointer release() { | |||
404 | Pointer p = mTuple.first(); | |||
405 | mTuple.first() = nullptr; | |||
406 | return p; | |||
407 | } | |||
408 | ||||
409 | void reset(Pointer aPtr = Pointer()) { | |||
410 | Pointer old = mTuple.first(); | |||
411 | mTuple.first() = aPtr; | |||
412 | if (old != nullptr) { | |||
413 | mTuple.second()(old); | |||
414 | } | |||
415 | } | |||
416 | ||||
417 | void reset(decltype(nullptr)) { | |||
418 | Pointer old = mTuple.first(); | |||
419 | mTuple.first() = nullptr; | |||
420 | if (old != nullptr) { | |||
421 | mTuple.second()(old); | |||
422 | } | |||
423 | } | |||
424 | ||||
425 | template <typename U> | |||
426 | void reset(U) = delete; | |||
427 | ||||
428 | void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } | |||
429 | ||||
430 | UniquePtr(const UniquePtr& aOther) = delete; // construct using std::move()! | |||
431 | void operator=(const UniquePtr& aOther) = | |||
432 | delete; // assign using std::move()! | |||
433 | }; | |||
434 | ||||
435 | /** | |||
436 | * A default deletion policy using plain old operator delete. | |||
437 | * | |||
438 | * Note that this type can be specialized, but authors should beware of the risk | |||
439 | * that the specialization may at some point cease to match (either because it | |||
440 | * gets moved to a different compilation unit or the signature changes). If the | |||
441 | * non-specialized (|delete|-based) version compiles for that type but does the | |||
442 | * wrong thing, bad things could happen. | |||
443 | * | |||
444 | * This is a non-issue for types which are always incomplete (i.e. opaque handle | |||
445 | * types), since |delete|-ing such a type will always trigger a compilation | |||
446 | * error. | |||
447 | */ | |||
448 | template <typename T> | |||
449 | class DefaultDelete { | |||
450 | public: | |||
451 | constexpr DefaultDelete() = default; | |||
452 | ||||
453 | template <typename U> | |||
454 | MOZ_IMPLICIT DefaultDelete( | |||
455 | const DefaultDelete<U>& aOther, | |||
456 | std::enable_if_t<std::is_convertible_v<U*, T*>, int> aDummy = 0) {} | |||
457 | ||||
458 | void operator()(T* aPtr) const { | |||
459 | static_assert(sizeof(T) > 0, "T must be complete"); | |||
460 | delete aPtr; | |||
461 | } | |||
462 | }; | |||
463 | ||||
464 | /** A default deletion policy using operator delete[]. */ | |||
465 | template <typename T> | |||
466 | class DefaultDelete<T[]> { | |||
467 | public: | |||
468 | constexpr DefaultDelete() = default; | |||
469 | ||||
470 | void operator()(T* aPtr) const { | |||
471 | static_assert(sizeof(T) > 0, "T must be complete"); | |||
472 | delete[] aPtr; | |||
| ||||
473 | } | |||
474 | ||||
475 | template <typename U> | |||
476 | void operator()(U* aPtr) const = delete; | |||
477 | }; | |||
478 | ||||
479 | template <typename T, class D, typename U, class E> | |||
480 | bool operator==(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY) { | |||
481 | return aX.get() == aY.get(); | |||
482 | } | |||
483 | ||||
484 | template <typename T, class D, typename U, class E> | |||
485 | bool operator!=(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY) { | |||
486 | return aX.get() != aY.get(); | |||
487 | } | |||
488 | ||||
489 | template <typename T, class D> | |||
490 | bool operator==(const UniquePtr<T, D>& aX, const T* aY) { | |||
491 | return aX.get() == aY; | |||
492 | } | |||
493 | ||||
494 | template <typename T, class D> | |||
495 | bool operator==(const T* aY, const UniquePtr<T, D>& aX) { | |||
496 | return aY == aX.get(); | |||
497 | } | |||
498 | ||||
499 | template <typename T, class D> | |||
500 | bool operator!=(const UniquePtr<T, D>& aX, const T* aY) { | |||
501 | return aX.get() != aY; | |||
502 | } | |||
503 | ||||
504 | template <typename T, class D> | |||
505 | bool operator!=(const T* aY, const UniquePtr<T, D>& aX) { | |||
506 | return aY != aX.get(); | |||
507 | } | |||
508 | ||||
509 | template <typename T, class D> | |||
510 | bool operator==(const UniquePtr<T, D>& aX, decltype(nullptr)) { | |||
511 | return !aX; | |||
512 | } | |||
513 | ||||
514 | template <typename T, class D> | |||
515 | bool operator==(decltype(nullptr), const UniquePtr<T, D>& aX) { | |||
516 | return !aX; | |||
517 | } | |||
518 | ||||
519 | template <typename T, class D> | |||
520 | bool operator!=(const UniquePtr<T, D>& aX, decltype(nullptr)) { | |||
521 | return bool(aX); | |||
522 | } | |||
523 | ||||
524 | template <typename T, class D> | |||
525 | bool operator!=(decltype(nullptr), const UniquePtr<T, D>& aX) { | |||
526 | return bool(aX); | |||
527 | } | |||
528 | ||||
529 | // No operator<, operator>, operator<=, operator>= for now because simplicity. | |||
530 | ||||
531 | namespace detail { | |||
532 | ||||
533 | template <typename T> | |||
534 | struct UniqueSelector { | |||
535 | typedef UniquePtr<T> SingleObject; | |||
536 | }; | |||
537 | ||||
538 | template <typename T> | |||
539 | struct UniqueSelector<T[]> { | |||
540 | typedef UniquePtr<T[]> UnknownBound; | |||
541 | }; | |||
542 | ||||
543 | template <typename T, decltype(sizeof(int)) N> | |||
544 | struct UniqueSelector<T[N]> { | |||
545 | typedef UniquePtr<T[N]> KnownBound; | |||
546 | }; | |||
547 | ||||
548 | } // namespace detail | |||
549 | ||||
550 | /** | |||
551 | * MakeUnique is a helper function for allocating new'd objects and arrays, | |||
552 | * returning a UniquePtr containing the resulting pointer. The semantics of | |||
553 | * MakeUnique<Type>(...) are as follows. | |||
554 | * | |||
555 | * If Type is an array T[n]: | |||
556 | * Disallowed, deleted, no overload for you! | |||
557 | * If Type is an array T[]: | |||
558 | * MakeUnique<T[]>(size_t) is the only valid overload. The pointer returned | |||
559 | * is as if by |new T[n]()|, which value-initializes each element. (If T | |||
560 | * isn't a class type, this will zero each element. If T is a class type, | |||
561 | * then roughly speaking, each element will be constructed using its default | |||
562 | * constructor. See C++11 [dcl.init]p7 for the full gory details.) | |||
563 | * If Type is non-array T: | |||
564 | * The arguments passed to MakeUnique<T>(...) are forwarded into a | |||
565 | * |new T(...)| call, initializing the T as would happen if executing | |||
566 | * |T(...)|. | |||
567 | * | |||
568 | * There are various benefits to using MakeUnique instead of |new| expressions. | |||
569 | * | |||
570 | * First, MakeUnique eliminates use of |new| from code entirely. If objects are | |||
571 | * only created through UniquePtr, then (assuming all explicit release() calls | |||
572 | * are safe, including transitively, and no type-safety casting funniness) | |||
573 | * correctly maintained ownership of the UniquePtr guarantees no leaks are | |||
574 | * possible. (This pays off best if a class is only ever created through a | |||
575 | * factory method on the class, using a private constructor.) | |||
576 | * | |||
577 | * Second, initializing a UniquePtr using a |new| expression requires repeating | |||
578 | * the name of the new'd type, whereas MakeUnique in concert with the |auto| | |||
579 | * keyword names it only once: | |||
580 | * | |||
581 | * UniquePtr<char> ptr1(new char()); // repetitive | |||
582 | * auto ptr2 = MakeUnique<char>(); // shorter | |||
583 | * | |||
584 | * Of course this assumes the reader understands the operation MakeUnique | |||
585 | * performs. In the long run this is probably a reasonable assumption. In the | |||
586 | * short run you'll have to use your judgment about what readers can be expected | |||
587 | * to know, or to quickly look up. | |||
588 | * | |||
589 | * Third, a call to MakeUnique can be assigned directly to a UniquePtr. In | |||
590 | * contrast you can't assign a pointer into a UniquePtr without using the | |||
591 | * cumbersome reset(). | |||
592 | * | |||
593 | * UniquePtr<char> p; | |||
594 | * p = new char; // ERROR | |||
595 | * p.reset(new char); // works, but fugly | |||
596 | * p = MakeUnique<char>(); // preferred | |||
597 | * | |||
598 | * (And third, although not relevant to Mozilla: MakeUnique is exception-safe. | |||
599 | * An exception thrown after |new T| succeeds will leak that memory, unless the | |||
600 | * pointer is assigned to an object that will manage its ownership. UniquePtr | |||
601 | * ably serves this function.) | |||
602 | */ | |||
603 | ||||
604 | template <typename T, typename... Args> | |||
605 | typename detail::UniqueSelector<T>::SingleObject MakeUnique(Args&&... aArgs) { | |||
606 | return UniquePtr<T>(new T(std::forward<Args>(aArgs)...)); | |||
607 | } | |||
608 | ||||
609 | template <typename T> | |||
610 | typename detail::UniqueSelector<T>::UnknownBound MakeUnique( | |||
611 | decltype(sizeof(int)) aN) { | |||
612 | using ArrayType = std::remove_extent_t<T>; | |||
613 | return UniquePtr<T>(new ArrayType[aN]()); | |||
614 | } | |||
615 | ||||
616 | template <typename T, typename... Args> | |||
617 | typename detail::UniqueSelector<T>::KnownBound MakeUnique(Args&&... aArgs) = | |||
618 | delete; | |||
619 | ||||
620 | /** | |||
621 | * WrapUnique is a helper function to transfer ownership from a raw pointer | |||
622 | * into a UniquePtr<T>. It can only be used with a single non-array type. | |||
623 | * | |||
624 | * It is generally used this way: | |||
625 | * | |||
626 | * auto p = WrapUnique(new char); | |||
627 | * | |||
628 | * It can be used when MakeUnique is not usable, for example, when the | |||
629 | * constructor you are using is private, or you want to use aggregate | |||
630 | * initialization. | |||
631 | */ | |||
632 | ||||
633 | template <typename T> | |||
634 | typename detail::UniqueSelector<T>::SingleObject WrapUnique(T* aPtr) { | |||
635 | return UniquePtr<T>(aPtr); | |||
636 | } | |||
637 | ||||
638 | } // namespace mozilla | |||
639 | ||||
640 | namespace std { | |||
641 | ||||
642 | template <typename T, class D> | |||
643 | void swap(mozilla::UniquePtr<T, D>& aX, mozilla::UniquePtr<T, D>& aY) { | |||
644 | aX.swap(aY); | |||
645 | } | |||
646 | ||||
647 | } // namespace std | |||
648 | ||||
649 | /** | |||
650 | TempPtrToSetter(UniquePtr<T>*) -> T**-ish | |||
651 | TempPtrToSetter(std::unique_ptr<T>*) -> T**-ish | |||
652 | ||||
653 | Make a temporary class to support assigning to UniquePtr/unique_ptr via passing | |||
654 | a pointer to the callee. | |||
655 | ||||
656 | Often, APIs will be shaped like this trivial example: | |||
657 | ``` | |||
658 | nsresult Foo::NewChildBar(Bar** out) { | |||
659 | if (!IsOk()) return NS_ERROR_FAILURE; | |||
660 | *out = new Bar(this); | |||
661 | return NS_OK; | |||
662 | } | |||
663 | ``` | |||
664 | ||||
665 | In order to make this work with unique ptrs, it's often either risky or | |||
666 | overwrought: | |||
667 | ``` | |||
668 | Bar* bar = nullptr; | |||
669 | const auto cleanup = MakeScopeExit([&]() { | |||
670 | if (bar) { | |||
671 | delete bar; | |||
672 | } | |||
673 | }); | |||
674 | if (FAILED(foo->NewChildBar(&bar)) { | |||
675 | // handle it | |||
676 | } | |||
677 | ``` | |||
678 | ||||
679 | ``` | |||
680 | UniquePtr<Bar> bar; | |||
681 | { | |||
682 | Bar* raw = nullptr; | |||
683 | const auto res = foo->NewChildBar(&bar); | |||
684 | bar.reset(raw); | |||
685 | if (FAILED(res) { | |||
686 | // handle it | |||
687 | } | |||
688 | } | |||
689 | ``` | |||
690 | TempPtrToSettable is a shorthand for the latter approach, allowing something | |||
691 | cleaner but also safe: | |||
692 | ||||
693 | ``` | |||
694 | UniquePtr<Bar> bar; | |||
695 | if (FAILED(foo->NewChildBar(TempPtrToSetter(&bar))) { | |||
696 | // handle it | |||
697 | } | |||
698 | ``` | |||
699 | */ | |||
700 | ||||
701 | namespace mozilla { | |||
702 | namespace detail { | |||
703 | ||||
704 | template <class T, class UniquePtrT> | |||
705 | class MOZ_TEMPORARY_CLASS TempPtrToSetterT final { | |||
706 | private: | |||
707 | UniquePtrT* const mDest; | |||
708 | T* mNewVal; | |||
709 | ||||
710 | public: | |||
711 | explicit TempPtrToSetterT(UniquePtrT* dest) | |||
712 | : mDest(dest), mNewVal(mDest->get()) {} | |||
713 | ||||
714 | operator T**() { return &mNewVal; } | |||
715 | ||||
716 | ~TempPtrToSetterT() { | |||
717 | if (mDest->get() != mNewVal) { | |||
718 | mDest->reset(mNewVal); | |||
719 | } | |||
720 | } | |||
721 | }; | |||
722 | ||||
723 | } // namespace detail | |||
724 | ||||
725 | template <class T, class Deleter> | |||
726 | auto TempPtrToSetter(UniquePtr<T, Deleter>* const p) { | |||
727 | return detail::TempPtrToSetterT<T, UniquePtr<T, Deleter>>{p}; | |||
728 | } | |||
729 | ||||
730 | template <class T, class Deleter> | |||
731 | auto TempPtrToSetter(std::unique_ptr<T, Deleter>* const p) { | |||
732 | return detail::TempPtrToSetterT<T, std::unique_ptr<T, Deleter>>{p}; | |||
733 | } | |||
734 | ||||
735 | } // namespace mozilla | |||
736 | ||||
737 | #endif /* mozilla_UniquePtr_h */ |