我有几个同事在查看 Excel VBA 中的一些错误代码,想知道调用堆栈中的级别数是否有限制
需要通过线程句柄打印 C++ 应用程序线程的调用堆栈,我转向了之前的 stackoverflow 答案中提到的StackWalker 。
然而,StakWalker 代码的日期是 2005 年。我怀疑从那时起有些东西发生了变化。
当我编译并运行它时,出现错误(如下),并且输出似乎不完整,在错误时被截断。测试应打印更多测试用例。
有人有更新的或不同的工作调用堆栈打印已发布的代码吗?
e:\boris\stackwalker\stackwalker\main.cpp (31): Func5
e:\boris\stackwalker\stackwalker\main.cpp (32): Func4
e:\boris\stackwalker\stackwalker\main.cpp (33): Func3
e:\boris\stackwalker\stackwalker\main.cpp (34): Func2
e:\boris\stackwalker\stackwalker\main.cpp (35): TestCurrentThread
e:\boris\stackwalker\stackwalker\main.cpp (139): main
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (582): __tmainCRTStartup
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (399): mainCRTStartup
VVVVV
ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 7C817077)
^^^^^
7C817077 (kernel32): (filename not available): RegisterWaitForInputIdle
Run Code Online (Sandbox Code Playgroud) 如果我传递的参数多于函数所需的参数,会发生什么情况?我预计被调用函数中的某些内容会被损坏,但在一些小型测试代码中一切正常。
例如:
void print()
{
int x=10;
printf("%d\n",x);
}
void main()
{
print(0,0,0,0,0);
}
Run Code Online (Sandbox Code Playgroud) 我试图了解当某些东西被推入和拉出时堆栈是如何工作的,如果问题听起来很简单,那么抱歉。
我想从一些超级基础的东西开始,比如 8 位内存(我知道这会过于简单,但让我们从简单开始)
我设计堆栈的方式如下:
SP 最初将指向内存中的最高位置:0xFF
0xFF: <- SP
Run Code Online (Sandbox Code Playgroud)
当发出push命令时,我会保存val在SP指向的位置,然后减少SP。
0xFE: <- SP
0xFF: val
Run Code Online (Sandbox Code Playgroud)
pop 命令将首先增加 SP,然后将 SP 指向的值移入寄存器。
基本上我的 SP 指向堆栈中的第一个可用位置。
然而,这似乎不是它在实际系统中的实现方式。
查看组装手册中的推送说明:
Decrements the stack pointer and then stores the source operand on the top of the stack.
Run Code Online (Sandbox Code Playgroud)
所以基本上SP指向最新的存储值。
我的问题是:首先减少堆栈指针,堆栈的最顶部是不是不可用?如果我们在保存数据之前先减少指针,我们如何将数据存储到堆栈的第一个位置?
是否有理由以这种方式设计堆栈指针?
假设我有一个名为 func 的函数:
PROC func:
;Bla bla
ret
ENDP func
Run Code Online (Sandbox Code Playgroud)
现在,假设我使用 register ax,bx例如,为了保存它们的初始值,我将它们推送到函数内部的堆栈中。
现在的问题是:在创建堆栈帧之前推送寄存器之间是否有很大的不同:
PROC func:
push bp
push ax
push bx
mov bp, sp
;Bla bla
ret
ENDP func
Run Code Online (Sandbox Code Playgroud)
还是之后?
PROC func:
push bp
mov bp, sp
push ax
push bx
;Bla bla
ret
ENDP func
Run Code Online (Sandbox Code Playgroud)
我应该在我的程序中使用什么?一种方法比另一种更好或更“正确”吗?因为我目前使用第一种方法。
基于Microsoft MASM 文档,.STACK 指令的用法是
当与 .MODEL 一起使用时,定义一个堆栈段(具有段名称 STACK)。可选大小指定堆栈的字节数(默认为 1,024)。.STACK 指令自动关闭堆栈语句。(仅限 32 位 MASM。)
为了实验,我做了.STACK分配1,073,741,824 bytes (1 GB)
请注意,我在 Visual Studio 2013 控制台项目中运行代码。
.586
.MODEL FLAT
.STACK 1073741824
.DATA
a DWORD 50
b DWORD 55
.CODE
main PROC
addLoop: mov eax, a
push eax
mov eax, 0
mov ebx, b
push ebx
jmp addLoop
RET
main ENDP
END
Run Code Online (Sandbox Code Playgroud)
该代码将溢出堆栈。我所做的是记下ESP寄存器的第一个地址,让代码运行直到溢出,然后ESP从第一个中减去最后一个以获得堆栈的大小。
在我的上下文中,它是00DAFEE4 - 00CB3000 + 1 = 000FCEE5. 这只是1036005 bytes (~1 …
考虑到C中函数内部的局部变量一旦被调用就会被压入堆栈(在压入传递给函数的变量之后),在堆栈缓冲区溢出之前,所述变量的数量是否有限制?或者该限制仅由确定的主机拥有的 RAM 量决定?
我尝试通过创建一个 4,6gb .C 文件来测试这一点,其中包含一个函数,该函数声明了 25000*13 个变量并将其初始化为 0。该函数在内部调用,main()但它编译得很好(使用 -O0)并且没有'崩溃。
我遇到了一个类实例函数,它需要临时更改一个类实例变量,然后在函数完成时恢复它.该函数在整个地方都有返回语句,并且在每次返回之前都有一个恢复语句.这对我来说似乎很混乱,更不用说在抛出异常时会感到害怕.
作为一种改进,我使用内部类定义提出了这种泛化.这是一个示例驱动程序(类恢复程序).
class Unwind {
private:
bool b_active_; ///< the thing I want to be restored
template<typename T>
class restorer {
T* ref_;
T save_;
public:
restorer(T* perm) : ref_(perm), save_(*ref_) {};
~restorer() { *ref_ = save_; }
};
public:
Unwind() : b_active_(false) {};
void a() { out("a in"); b(); out("a end"); }
void b() {
out("b in");
{
restorer<bool> trust_in_the_stack(&b_active_); // "restorer" created on the stack
b_active_ = true; // change b_active_ only while "within" b()
c();
out("b inner …Run Code Online (Sandbox Code Playgroud) 我的理解是,当您通过Windows XP中的任务管理器终止C++应用程序时,应用程序仍然"干净地"被破坏 - 即调用堆栈将展开并且将调用所有相关的对象析构函数.不确定我的理解是不是错了.
是否有可能立即杀死这样的应用程序,而无需展开堆栈?
例如,应用程序可以使用RAII模式,当对象被破坏时,RAII模式将破坏或释放资源.如果通过任务管理器的传统"终止进程"是优雅的,提供一种立即终止应用程序的方法将允许我测试非正常关闭(例如断电).
编辑:
只是为了澄清,我正在使用现有的实用程序或程序来允许我这样做.我应该能够在我没有源代码的程序上使用该解决方案,这意味着程序化解决方案不是真的可以接受.
编辑:
只是为了提供更多的上下文,有时候我必须使用非常干扰的第三方服务(例如,每隔一小时唠叨我就重新启动).因为我知道我不需要重新启动,所以我想杀死进程/服务,所以它不再惹恼我了.不幸的是,一些第三方开发人员"聪明"足以阻止我这样做,当我通过任务管理器终止进程时,系统将立即重启(我猜这是使用RAII来实现这一点).
当我从Windows 7切换到Windows 10(当然是新的SDK)时,在使用命令"kc"显示callstack时,我在WinDBG中遇到了这种不同的行为:Windows 7:
KERNELBASE!RaiseException
msvcr120!_CxxThrowException
msvcp120!std::_Xout_of_range
Run Code Online (Sandbox Code Playgroud)
Windows 10:
00 KERNELBASE!RaiseException
01 msvcr120!_CxxThrowException
02 msvcp120!std::_Xout_of_range
Run Code Online (Sandbox Code Playgroud)
如何摆脱行号?
00
01
02
Run Code Online (Sandbox Code Playgroud)
这是像".frame 0n0; dv/t/v"这样的链接
callstack ×10
assembly ×3
c++ ×3
c ×2
compilation ×1
excel ×1
masm ×1
memory ×1
process ×1
raii ×1
stack ×1
stack-frame ×1
stack-trace ×1
vba ×1
winapi ×1
windbg ×1
windows-10 ×1
windows-xp ×1
x86 ×1