VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/compiler/vcc/stacksup-vcc.cpp@ 106558

Last change on this file since 106558 was 106558, checked in by vboxsync, 5 months ago

IPRT: Some nocrt/arm64 build fixes. jiraref:VBP-1171

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.2 KB
Line 
1/* $Id: stacksup-vcc.cpp 106558 2024-10-21 11:31:16Z vboxsync $ */
2/** @file
3 * IPRT - Visual C++ Compiler - Stack Checking C/C++ Support.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "internal/nocrt.h"
42
43#include <iprt/asm.h>
44#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
45# include <iprt/asm-amd64-x86.h>
46#elif defined(RT_ARCH_ARM64)
47# include <iprt/asm-arm.h>
48#endif
49#ifndef IPRT_NOCRT_WITHOUT_FATAL_WRITE
50# include <iprt/assert.h>
51#endif
52
53#include "internal/compiler-vcc.h"
54#ifdef IN_RING3
55# include <iprt/win/windows.h>
56# include "../../../r3/win/internal-r3-win.h" /* ugly, but need some windows API function pointers */
57#endif
58
59
60/*********************************************************************************************************************************
61* Defined Constants And Macros *
62*********************************************************************************************************************************/
63/** Gets the program counter member of Windows' CONTEXT structure. */
64#if defined(RT_ARCH_AMD64)
65# define MY_GET_PC_FROM_CONTEXT(a_pCtx) ((a_pCtx)->Rip)
66#elif defined(RT_ARCH_X86)
67# define MY_GET_PC_FROM_CONTEXT(a_pCtx) ((a_pCtx)->Eip)
68#elif defined(RT_ARCH_ARM64)
69# define MY_GET_PC_FROM_CONTEXT(a_pCtx) ((a_pCtx)->Pc)
70#else
71# error "Port Me!"
72#endif
73
74
75/*********************************************************************************************************************************
76* Structures and Typedefs *
77*********************************************************************************************************************************/
78/** Variable descriptor. */
79typedef struct RTC_VAR_DESC_T
80{
81 int32_t offFrame;
82 uint32_t cbVar;
83 const char *pszName;
84} RTC_VAR_DESC_T;
85
86/** Frame descriptor. */
87typedef struct RTC_FRAME_DESC_T
88{
89 uint32_t cVars;
90 RTC_VAR_DESC_T const *paVars;
91} RTC_FRAME_DESC_T;
92
93#define VARIABLE_MARKER_PRE 0xcccccccc
94#define VARIABLE_MARKER_POST 0xcccccccc
95
96
97/**
98 * Alloca allocation entry.
99 * @note For whatever reason the pNext and cb members are misaligned on 64-bit
100 * targets. 32-bit targets OTOH adds padding to keep the structure size
101 * and pNext + cb offsets the same.
102 */
103#pragma pack(4)
104typedef struct RTC_ALLOC_ENTRY
105{
106 uint32_t uGuard1;
107 RTC_ALLOC_ENTRY *pNext;
108#if ARCH_BITS == 32
109 uint32_t pNextPad;
110#endif
111 size_t cb;
112#if ARCH_BITS == 32
113 uint32_t cbPad;
114#endif
115 uint32_t auGuard2[3];
116} RTC_ALLOC_ENTRY;
117#pragma pack()
118
119#define ALLOCA_FILLER_BYTE 0xcc
120#define ALLOCA_FILLER_32 0xcccccccc
121
122
123/*********************************************************************************************************************************
124* External Symbols *
125*********************************************************************************************************************************/
126extern "C" void __fastcall _RTC_CheckStackVars(uint8_t *pbFrame, RTC_VAR_DESC_T const *pVar); /* nocrt-stack.asm */
127extern "C" uintptr_t __security_cookie;
128
129
130/**
131 * Initializes the security cookie value.
132 *
133 * This must be called as the first thing by the startup code. We must also no
134 * do anything fancy here.
135 */
136void rtVccInitSecurityCookie(void) RT_NOEXCEPT
137{
138 __security_cookie = (uintptr_t)ASMReadTSC() ^ (uintptr_t)&__security_cookie;
139}
140
141
142/**
143 * Reports a security error.
144 *
145 * @param uFastFailCode The fast fail code.
146 * @param pCpuCtx The CPU context at the failure location.
147 */
148static DECL_NO_RETURN(void) rtVccFatalSecurityErrorWithCtx(uint32_t uFastFailCode, PCONTEXT pCpuCtx)
149{
150#ifdef IN_RING3
151 /*
152 * Use the __fastfail() approach if available, it is more secure than the stuff below:
153 */
154 if (g_pfnIsProcessorFeaturePresent && g_pfnIsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
155 __fastfail(uFastFailCode);
156
157 /*
158 * Fallback for legacy systems.
159 */
160 if (g_pfnIsDebuggerPresent && g_pfnIsDebuggerPresent())
161 __debugbreak();
162
163 /* If we can, clear the unhandled exception filter and report and unhandled exception. */
164 if (g_pfnSetUnhandledExceptionFilter && g_pfnUnhandledExceptionFilter)
165 {
166 g_pfnSetUnhandledExceptionFilter(NULL);
167
168 EXCEPTION_RECORD XcptRec =
169 {
170 /* .ExceptionCode = */ STATUS_STACK_BUFFER_OVERRUN,
171 /* .ExceptionFlags = */ EXCEPTION_NONCONTINUABLE,
172 /* .ExceptionRecord = */ NULL,
173# ifdef RT_ARCH_AMD64
174 /* .ExceptionAddress = */ (void *)pCpuCtx->Rip,
175# elif defined(RT_ARCH_X86)
176 /* .ExceptionAddress = */ (void *)pCpuCtx->Eip,
177# elif defined(RT_ARCH_ARM64)
178 /* .ExceptionAddress = */ (void *)pCpuCtx->Pc,
179# else
180# error "Port me!"
181# endif
182 /* .NumberParameters = */ 1,
183 /* .ExceptionInformation = */ { uFastFailCode, }
184 };
185
186 EXCEPTION_POINTERS XcptPtrs = { &XcptRec, pCpuCtx };
187 g_pfnUnhandledExceptionFilter(&XcptPtrs);
188 }
189
190 for (;;)
191 TerminateProcess(GetCurrentProcess(), STATUS_STACK_BUFFER_OVERRUN);
192
193#else
194# error "Port ME!"
195#endif
196}
197
198
199DECLASM(void) rtVccStackVarCorrupted(uint8_t *pbFrame, RTC_VAR_DESC_T const *pVar, PCONTEXT pCpuCtx)
200{
201#ifdef IPRT_NOCRT_WITHOUT_FATAL_WRITE
202 RTAssertMsg2("\n\n!!Stack corruption!!\n\n"
203 "%p LB %#x - %s\n",
204 pbFrame + pVar->offFrame, pVar->cbVar, pVar->pszName);
205#else
206 rtNoCrtFatalWriteBegin(RT_STR_TUPLE("\r\n\r\n!!Stack corruption!!\r\n\r\n"));
207 rtNoCrtFatalWritePtr(pbFrame + pVar->offFrame);
208 rtNoCrtFatalWrite(RT_STR_TUPLE(" LB "));
209 rtNoCrtFatalWriteX32(pVar->cbVar);
210 rtNoCrtFatalWrite(RT_STR_TUPLE(" - "));
211 rtNoCrtFatalWriteStr(pVar->pszName);
212 rtNoCrtFatalWriteEnd(RT_STR_TUPLE("\r\n"));
213#endif
214 rtVccFatalSecurityErrorWithCtx(FAST_FAIL_INCORRECT_STACK, pCpuCtx);
215}
216
217
218DECLASM(void) rtVccSecurityCookieMismatch(uintptr_t uCookie, PCONTEXT pCpuCtx)
219{
220#ifdef IPRT_NOCRT_WITHOUT_FATAL_WRITE
221 RTAssertMsg2("\n\n!!Stack cookie corruption!!\n\n"
222 "expected %p, found %p\n",
223 __security_cookie, uCookie);
224#else
225 rtNoCrtFatalWriteBegin(RT_STR_TUPLE("\r\n\r\n!!Stack cookie corruption!!\r\n\r\n"
226 "expected"));
227 rtNoCrtFatalWritePtr((void *)__security_cookie);
228 rtNoCrtFatalWrite(RT_STR_TUPLE(", found "));
229 rtNoCrtFatalWritePtr((void *)uCookie);
230 rtNoCrtFatalWriteEnd(RT_STR_TUPLE("\r\n"));
231#endif
232 rtVccFatalSecurityErrorWithCtx(FAST_FAIL_STACK_COOKIE_CHECK_FAILURE, pCpuCtx);
233}
234
235
236#ifdef RT_ARCH_X86
237DECLASM(void) rtVccCheckEspFailed(PCONTEXT pCpuCtx)
238{
239# ifdef IPRT_NOCRT_WITHOUT_FATAL_WRITE
240 RTAssertMsg2("\n\n!!ESP check failed!!\n\n"
241 "eip=%p esp=%p ebp=%p\n",
242 pCpuCtx->Eip, pCpuCtx->Esp, pCpuCtx->Ebp);
243# else
244 rtNoCrtFatalWriteBegin(RT_STR_TUPLE("\r\n\r\n!!ESP check failed!!\r\n\r\n"
245 "eip="));
246 rtNoCrtFatalWritePtr((void *)pCpuCtx->Eip);
247 rtNoCrtFatalWrite(RT_STR_TUPLE(" esp="));
248 rtNoCrtFatalWritePtr((void *)pCpuCtx->Esp);
249 rtNoCrtFatalWrite(RT_STR_TUPLE(" ebp="));
250 rtNoCrtFatalWritePtr((void *)pCpuCtx->Ebp);
251 rtNoCrtFatalWriteEnd(RT_STR_TUPLE("\r\n"));
252# endif
253 rtVccFatalSecurityErrorWithCtx(FAST_FAIL_INCORRECT_STACK, pCpuCtx);
254}
255#endif
256
257
258/** @todo reimplement in assembly (feeling too lazy right now). */
259extern "C" void __fastcall _RTC_CheckStackVars2(uint8_t *pbFrame, RTC_VAR_DESC_T const *pVar, RTC_ALLOC_ENTRY *pHead)
260{
261 while (pHead)
262 {
263 if ( pHead->uGuard1 == ALLOCA_FILLER_32
264#if 1 && ARCH_BITS == 32
265 && pHead->pNextPad == ALLOCA_FILLER_32
266 && pHead->cbPad == ALLOCA_FILLER_32
267#endif
268 && pHead->auGuard2[0] == ALLOCA_FILLER_32
269 && pHead->auGuard2[1] == ALLOCA_FILLER_32
270 && pHead->auGuard2[2] == ALLOCA_FILLER_32
271 && *(uint32_t const *)((uint8_t const *)pHead + pHead->cb - sizeof(uint32_t)) == ALLOCA_FILLER_32)
272 { /* likely */ }
273 else
274 {
275#ifdef IPRT_NOCRT_WITHOUT_FATAL_WRITE
276 RTAssertMsg2("\n\n!!Stack corruption (alloca)!!\n\n"
277 "%p LB %#x\n",
278 pHead, pHead->cb);
279#else
280 rtNoCrtFatalWriteBegin(RT_STR_TUPLE("\r\n\r\n!!Stack corruption (alloca)!!\r\n\r\n"));
281 rtNoCrtFatalWritePtr(pHead);
282 rtNoCrtFatalWrite(RT_STR_TUPLE(" LB "));
283 rtNoCrtFatalWriteX64(pHead->cb);
284 rtNoCrtFatalWriteEnd(RT_STR_TUPLE("\r\n"));
285#endif
286#ifdef IN_RING3
287 if (g_pfnIsDebuggerPresent && g_pfnIsDebuggerPresent())
288#endif
289 RT_BREAKPOINT();
290 }
291 pHead = pHead->pNext;
292 }
293
294 _RTC_CheckStackVars(pbFrame, pVar);
295}
296
297
298DECLASM(void) rtVccRangeCheckFailed(PCONTEXT pCpuCtx)
299{
300# ifdef IPRT_NOCRT_WITHOUT_FATAL_WRITE
301 RTAssertMsg2("\n\n!!Range check failed at %p!!\n\n", MY_GET_PC_FROM_CONTEXT(pCpuCtx));
302# else
303 rtNoCrtFatalWriteBegin(RT_STR_TUPLE("\r\n\r\n!!Range check failed at "));
304 rtNoCrtFatalWritePtr((void *)MY_GET_PC_FROM_CONTEXT(pCpuCtx));
305 rtNoCrtFatalWriteEnd(RT_STR_TUPLE("!!\r\n"));
306# endif
307 rtVccFatalSecurityErrorWithCtx(FAST_FAIL_RANGE_CHECK_FAILURE, pCpuCtx);
308}
309
310
311/** Whether or not this should be a fatal issue remains to be seen. See
312 * explanation in stack-vcc.asm. */
313#if 0
314DECLASM(void) rtVccUninitializedVariableUse(const char *pszVar, PCONTEXT pCpuCtx)
315#else
316extern "C" void __cdecl _RTC_UninitUse(const char *pszVar)
317#endif
318{
319#ifdef IPRT_NOCRT_WITHOUT_FATAL_WRITE
320 RTAssertMsg2("\n\n!!Used uninitialized variable %s at %p!!\n\n",
321 pszVar ? pszVar : "", ASMReturnAddress());
322#else
323 rtNoCrtFatalWriteBegin(RT_STR_TUPLE("\r\n\r\n!!Used uninitialized variable "));
324 rtNoCrtFatalWriteStr(pszVar);
325 rtNoCrtFatalWrite(RT_STR_TUPLE(" at "));
326 rtNoCrtFatalWritePtr(ASMReturnAddress());
327 rtNoCrtFatalWriteEnd(RT_STR_TUPLE("!!\r\n\r\n"));
328#endif
329#if 0
330 rtVccFatalSecurityErrorWithCtx(FAST_FAIL_FATAL_APP_EXIT, pCpuCtx);
331#else
332# ifdef IN_RING3
333 if (g_pfnIsDebuggerPresent && g_pfnIsDebuggerPresent())
334# endif
335 RT_BREAKPOINT();
336#endif
337}
338
339
340void rtVccCheckContextFailed(PCONTEXT pCpuCtx)
341{
342#ifdef IPRT_NOCRT_WITHOUT_FATAL_WRITE
343 RTAssertMsg2("\n\n!!Context (stack) check failed!!\n\n"
344 "PC=%p SP=%p BP=%p\n",
345# ifdef RT_ARCH_AMD64
346 pCpuCtx->Rip, pCpuCtx->Rsp, pCpuCtx->Rbp
347# elif defined(RT_ARCH_X86)
348 pCpuCtx->Eip, pCpuCtx->Esp, pCpuCtx->Ebp
349# elif defined(RT_ARCH_ARM64)
350 pCpuCtx->Pc, pCpuCtx->Sp, pCpuCtx->Bp
351# else
352# error "unsupported arch"
353# endif
354 );
355#else
356 rtNoCrtFatalWriteBegin(RT_STR_TUPLE("\r\n\r\n!!Context (stack) check failed!!\r\n\r\n"
357 "PC="));
358# ifdef RT_ARCH_AMD64
359 rtNoCrtFatalWritePtr((void *)pCpuCtx->Rip);
360# elif defined(RT_ARCH_X86)
361 rtNoCrtFatalWritePtr((void *)pCpuCtx->Eip);
362# elif defined(RT_ARCH_ARM64)
363 rtNoCrtFatalWritePtr((void *)pCpuCtx->Pc);
364# else
365# error "unsupported arch"
366# endif
367 rtNoCrtFatalWrite(RT_STR_TUPLE(" SP="));
368# ifdef RT_ARCH_AMD64
369 rtNoCrtFatalWritePtr((void *)pCpuCtx->Rsp);
370# elif defined(RT_ARCH_X86)
371 rtNoCrtFatalWritePtr((void *)pCpuCtx->Esp);
372# endif
373 rtNoCrtFatalWrite(RT_STR_TUPLE(" BP="));
374# ifdef RT_ARCH_AMD64
375 rtNoCrtFatalWritePtr((void *)pCpuCtx->Rbp);
376# elif defined(RT_ARCH_X86)
377 rtNoCrtFatalWritePtr((void *)pCpuCtx->Ebp);
378# endif
379 rtNoCrtFatalWriteEnd(RT_STR_TUPLE("\r\n"));
380#endif
381 rtVccFatalSecurityErrorWithCtx(FAST_FAIL_INVALID_SET_OF_CONTEXT, pCpuCtx);
382}
383
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette