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 https://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_WindowsStackCookie_h
8 #define mozilla_WindowsStackCookie_h
10 #if defined(DEBUG) && defined(_M_X64) && !defined(__MINGW64__)
17 # include "mozilla/Types.h"
21 // This function does pattern matching on the instructions generated for a
22 // given function, to detect whether it uses stack buffers. More specifically,
23 // it looks for instructions that characterize the presence of stack cookie
24 // checks. When this function returns true, it can be a false positive, but we
25 // use a rather long pattern to make false positives very unlikely.
26 // Note: Do not use this function inside the function that lives at
27 // aFunctionAddress, as that could introduce stack buffers.
28 // Note: The pattern we use does not work for MinGW builds.
29 inline bool HasStackCookieCheck(uintptr_t aFunctionAddress
) {
31 auto entry
= ::RtlLookupFunctionEntry(
32 reinterpret_cast<DWORD64
>(aFunctionAddress
), &imageBase
, nullptr);
33 if (entry
&& entry
->EndAddress
> entry
->BeginAddress
+ 14) {
34 auto begin
= reinterpret_cast<uint8_t*>(imageBase
+ entry
->BeginAddress
);
35 auto end
= reinterpret_cast<uint8_t*>(imageBase
+ entry
->EndAddress
- 14);
36 for (auto pc
= begin
; pc
!= end
; ++pc
) {
37 // 48 8b 05 XX XX XX XX: mov rax, qword ptr [rip + XXXXXXXX]
38 if ((pc
[0] == 0x48 && pc
[1] == 0x8b && pc
[2] == 0x05) &&
39 // 48 31 e0: xor rax, rsp
40 (pc
[7] == 0x48 && pc
[8] == 0x31 && pc
[9] == 0xe0) &&
41 // 48 89 (8|4)4 24 ...: mov qword ptr [rsp + ...], rax
42 (pc
[10] == 0x48 && pc
[11] == 0x89 &&
43 (pc
[12] == 0x44 || pc
[12] == 0x84) && pc
[13] == 0x24)) {
48 // In x64, if there is no entry, then there is no stack allocation, hence
49 // there is no stack cookie check: "Table-based exception handling requires a
50 // table entry for all functions that allocate stack space or call another
51 // function (for example, nonleaf functions)."
52 // https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64
53 // Similarly, if the gap between begin and end is less than 14 bytes, then
54 // the function cannot contain the pattern we are looking for, therefore it
55 // has no cookie check either.
59 } // namespace mozilla
61 #endif // defined(DEBUG) && defined(_M_X64) && !defined(__MINGW64__)
63 #endif // mozilla_WindowsStackCookie_h