运行返回签名不正确_如果调用约定不匹配,会发生什么?

蝎子

信不信由你,调用约定不匹配是程序经常出问题的原因之一。当你的程序代码中出现不相匹配的调动约定的时候,编译器会”大吼大叫”,但是懒惰的程序员只会在其中进行强制转换,以使编译器”尽快闭嘴”。
结果是:Windows不得不永远支持你编写的错误代码。

Windows窗口过程

有很多人会错误地声明了Windows窗口过程(通常是将它声明为__cdecl,而不是__stdcall),因为这个原因,我们分发消息给窗口过程的函数添加了额外的保护,这样它就可以检测到错误的函数声明,并执行适当的修复。
这是你为什么在堆栈上经常会看到神秘的0xdcbaabcd的原因。向窗口过程分发消息的函数会检查这个值是否在堆栈中的正确位置。如果不是,那么它会检查窗口过程是否从堆栈中弹出了一个多余的双字(如果是这样的话,它将尝试修复堆栈),或者窗口过程是否错误地声明为__cdecl而不是__stdcall(如果是这样的话,它将参数从窗口过程的堆栈中弹出)。

DirectX回调函数

在DirectX库中大量地使用了回调函数,并且人们再次将其回调函数声明为__cdecl,而不是__stdcall。因此DirectX枚举器必须对这些错误声明的函数进行特殊的堆栈清理。(真难啊…)

IShellFolder::CreateViewObject
我记得,曾经这么一个程序,它错误地声明了一个名为CreateViewWindow的函数,并且开发者设法以某种方式欺骗了编译器以接受它。如下图所示:

7ad35841d0338f5e33d42031bc313e58.png

他们不仅错误地声明了函数签名,而且在函数的内部,即使函数没有成功完成,它也返回了S_OK。调用此函数后,我不得不添加额外的代码来清理堆栈,并确认它的返回值是不是正确的。

Rundll32.exe入口点函数

在Microsoft的知识库文章中,介绍了rundll32.exe调用的函数所需要的函数签名。但这并没有阻止人们使用rundll32调用那些并非由rundll32设计的随机函数,例如user32模块里的LockWorkStation或ExitWindowsEx。
下面,就让我们来看看,如果使用rundll32.exe调用ExitWindowsEx之类的函数时,会发生什么情况。
rundll32.exe会解析其命令行,并假定函数的编写方式如下:
void CALLBACK ExitWindowsEx(HWND hwnd, HINSTANCE hinst,LPSTR pszCmdLine, int nCmdShow);

但是,实际的ExitWindowsEx的函数原型是这样的:
BOOL WINAPI ExitWindowsEx(UINT uFlags, DWORD dwReserved);

接下来会发生什么呢?
当进入ExitWindowsEx函数时,堆栈看起来像这样:

5075b6dc5726329e66805d0dbe5cf74d.png

但是,函数希望看到堆栈是这样的:

d30d81b37dda64060ea4f345dcea2323.png

会发生什么?

rundll32.exe传递的hwnd窗口句柄,会被误认为是uFlags,而hinst会误认为为dwReserved。由于窗口句柄是随机的,因此最终会将这个随机标志传递给ExitWindowsEx。也许今天是EWX_LOGOFF,明天是EWX_FORCE,下次是EWX_POWEROFF。

现在假设该函数设法返回。(例如,函数执行失败)。ExitWindowsEx函数清除堆栈中的两个参数,而不知道它已传递给四个参数。生成的堆栈是这样的:

880c42223dc81b8fda697757e99d3e5f.png

现在堆栈的数据已经被破坏了,真正有趣的事情即将发生。
例如,假设上图中的”.. rest of the stack ..”里保存的是一个返回地址。好了,原始代码将执行”返回”指令以通过该返回地址返回,但是在堆栈被破坏的情况下,”返回”指令将返回命令行并尝试像执行代码一样尝试执行它。

Random custom functions

开发者可能会将一个函数导出为__cdecl,但将其视为__stdcall。这似乎可行,但是返回时,堆栈将被破坏(因为调用者期望使用__stdcall函数来清理堆栈,但是得到的却是无法使用的__cdecl函数)。
好的,我们已经举了这么多的例子了。我想你应该可以明白我想表达的要点了,下面是一些你肯定会问的问题。

为什么编译器不能捕获这些错误呢?

编译器确实这样做了。(不是上面的那个rundll32例子啊)
但是人们似乎已经习惯了只使用强制转换来关闭编译器的警告。

我们看看下面的函数原型:
LRESULT CALLBACK DlgProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

上面的函数原型是错误的,正确的版本请看下面:
INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg,WPARAM wParam, LPARAM lParam);

如果你这样调用:
DialogBox(hInst, MAKEINTRESOURCE(IDD_CONTROLS_DLG), hWnd, DlgProc);

编译器会马上发出如下的编译器错误信息:
error C2664: ‘DialogBoxParamA’ : cannot convert parameter 4 from ‘LRESULT (HWND,UINT,WPARAM,LPARAM)’ to ‘DLGPROC’.

然后,你想懒惰一下,使用下面的强制转换来关闭错误信息:
DialogBox(hInst, MAKEINTRESOURCE(IDD_CONTROLS_DLG), hWnd, reinterpret_cast(DlgProc));

“噢,拜托,谁会这么愚蠢,会在没有实际修复代码错误的情况下,仅仅是加入强制类型转换来以使编译错误消失?”
看来,大部分人都会这样做。

在网络上,我还看到了很多开发者犯了这样的错误,这里就不一一列举了。

带有这些错误的程序代码是如何工作的?
当然,这些程序在某种程度上可以正常工作,要不然使用者肯定会注意到并要求开发者修复这个错误。
但是,程序如何在被破坏的堆栈中生存呢?(这个问题我后面会回答)

总结

强制类型转换,不应该出现在任何一个完美代码主义者的字典里。
但,没它,还真不行。

最后

Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《What can go wrong when you mismatch the calling convention?》

6f92b0d4b0cff05bc21bd836ee6af580.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/571683.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mac svn 使用

上传文件$ svn import file.xls svn://ip/sursen/05I\&V周报 -m "te"备注: -m "冒号里面一定填写文件 "下载文件svn checkout svn://ip/sursen/05I\&V周报查看文件:svn list svn://ip/sursen/05I\&V周报MacBook-Pro:05I…

计算机硬件教学设计高中信息,重大版信息技术七上《计算机硬件系统》教学设计.doc...

重大版信息技术七上《计算机硬件系统》教学设计.doc文档编号:745134文档页数:3上传时间: 2019-09-19文档级别:文档类型:doc文档大小:33.00KB计算机硬件系统教学设计 知识目标 1、学生了解计算机组成各部分的…

感谢Thunder团队

在这次alpha版本开发的过程中,我想感谢团队中的每一个成员。 第一次合作完成一个完整的项目,让我深刻的感受到了合作的重要性。在一个优秀的团队中,能不断地学习到很多东西。 感谢组长王航,对项目认真,对成员负责。合理…

html 循环_一个不被程序员认为是编程语言的语言——HTML,你怎么看?

HTML究竟算不算是一门编程语言,这是争执已久的话题。其实,从本质来讲,HTML确实算不上是一门编程语言。HTML全称,HyperText Markup Language。字面理解,HTML就是一种超文本语言,何谓超文本,就是其…

第一学期计算机网络作业,2010-2011学年第一学期计算机网络(33973)试卷

江西财经大学2010-2011第一学期期末考试试卷试卷代码:33973 授课课时:48 考试时间:150分钟 课程名称:计算机网络 适用对象:本科选课班 试卷命题人 凌传繁 试卷审核人 万 征一、单项选择题(从下列各题四个备…

Java Web学习总结(10)学习总结-EL表达式

一,EL 表达式概述(EL主要从域中取数据) EL(Express Lanuage)表达式可以嵌入在jsp页面内部,减少jsp脚本的编写,EL出现的目的是要替代jsp页面中脚本的编写。 二,EL从域中取出数据(EL…

图片测量尺寸软件_3D扫描之工件测量检测

一.技术简介消费者追求品质和时尚的需求使制造领域发生了一系列变革,最明显的两点:一是产品外形增加了更多的曲面设计;二是产品的质量控制标准越来越严格。而这两点的变化又对检测行业提出了更高的要求,传统的测量或检…

计算机词汇查询,计算机辅助英语词汇查询系统的设计.doc

计算机辅助英语词汇查询系统的设计计算机辅助英语词汇查询系统的设计摘 要: 以往所使用的基于Visual Studio的计算机辅助英语词汇查询系统存在查询页面过于繁琐运行效率低,导致查询系统速度慢以及实用性差等缺点。因此设计基于Struts的计算机辅助英语词汇…

input只能输入数字_Python基础第一个案例:猜数字游戏,这个都写不出,那就放弃吧...

前言本文案例只适合新手,老司机请绕路。游戏介绍:程序自己有一个数字,用户输入一个数字,两个数字进行比较。知识点:input函数字符串while循环if条件判断语句break语句开始撸代码先来看看效果图代码# 1. 有一个数字 my_…

远程服务器任务,远程大批量操作windows服务器的计划任务

在工作过程中,经常需要大批量对某一批次机器进行计划任务设置,可以通过组策略实现,也可以通过脚本操作。本文演示如何通过powershell脚本远程大批量给若干台机器设置周期重启的操作。#生成10到30的数组$a(10..30);#初始化空的数组$pcname();#…

java 异或_Javase第一部分:操作符的使用(按位异或运算)(含视频讲解)

本套课程讲解详细深入,内容丰富,包含了数据结构、JVM、GC等大厂常见的面试知识精讲,而且配有在线的预习文档课堂笔记每天作业,可以缩短你的学习周期,提高学习效率。Java精讲视频六大板块----带你轻松入门Java​mp.weixin.qq.com本…

js 设计模式

首先我们需要知道JavaScript与传统的面向对象编程(oop)不同,它没有传统意义上的类,该语言的一切都是基于对象,依靠的是一套原型(prototype)系统。JavaScript通过原型委托的方式实现对象与对象之…

电子科大计算机调试,电子科大计算机学院 汇编语言程序设计 实验报告 99分精品版.doc...

电子科技大学 计算机科学与工程 学院标 准 实 验 报 告(实验)课程名称 汇编语言与微机接口技术综合实验电子科技大学教务处制表电 子 科 技 大 学实 验 报 告 (一)学生姓名:郫县英格拉姆 学 号:2014123456789 指导教师:皮皮怪实验地点&#x…

python环境变量配置步骤_关于人工智能Python系统环境变量设置步骤

最近无论是JAVA的环境变量配置,还是Python环境变量配置都有学生问我,我在这里写一下回答,当然我以配置Python的环境变脸来举例.首先需要确定本机电脑上安装上了Python首先解释一下为什么需要配置环境变量,我们平时打开一个应用程序,一般都是在桌面双击该软件的快捷方…

图文详解linux/windows mysql忘记root密码解决方案

经常有用户过来咨询说自己的mysql服务器忘记密码了怎么办,为了更好的解决大家的困扰,本文特归档整理了windows和linux系统下,mysql忘记密码的解决方案。本文内容是我亲测实用,当然过程中踩过的坑我也会在本文中一并分享交流。废话…

jquery 判断控件css样式,jQuery获取并设置CSS类

jQuery获取并设置CSS类通过 jQuery,可以很容易地对 CSS 元素进行操作。jQuery 操作 CSSjQuery 拥有若干进行 CSS 操作的方法。我们将学习下面这些:• addClass() - 向被选元素添加一个或多个类• removeClass() - 从被选元素删除一个或多个类• toggleCl…

零宽断言 python_正则表达式-零宽断言

[toc]一、零宽断言-介绍零宽断言,它匹配的内容不会提取,其作用是在一个限定位置的字符串向前或向后进行匹配查找。1.1、应用场景排除查找,查找不含有某段字符串的行包含查找,查找含有某段字符串的行二、断言的分类2.1、正先行断言…

JS闭包—你不知道的JavaScript上卷读书笔记(二)

关于闭包,初学者会被绕的晕头转向,在学习的路上也付出了很多精力来理解。 让我们一起来揭开闭包神秘的面纱。 闭包晦涩的定义 看过很多关于闭包的定义,很多讲的云里雾里,晦涩难懂。让不少人以为闭包是多么玄乎的东西。在我看过的所…

img 错误样式css,css设置图片大小_css 控制img图片的大小样式

摘要 腾兴网为您分享:css 控制img图片的大小样式,掌上财富,优品多多,问作业,淘客联盟等软件知识,以及手机游戏开挂神器,au补丁,局域网监测,苹果录屏专家,重复文件删除&am…

python读取视频流做人脸识别_基于 Python + OpenCV 进行人脸识别,视频追踪代码全注释...

1 #-*- coding: utf-8 -*-2 from __future__ importunicode_literals3 #操作文件4 importos5 #科学计算6 importnumpy as np7 #图像识别8 importcv2 as cv9 #数据预处理, 该项目中只使用了标签编码10 importsklearn.preprocessing as sp111213 defload_imgs(directory):14 加载…