用List和Map文件定位bug

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
	char* ptr = NULL;
	*ptr = 'A';
	return 0;
}

这段程序bug很显见,要定位bug也不难。但是,如果把这代码发布出去,直接运行会有这样的错误,最多看到汇编指令:

这时怎么定位程序?

首先0x00CA1378,这地址看着有点高,一般程序加载在0x00400000,看着就是随机地址加载。怎么验证是随机地址加载?程序的bug只有一处,每次运行都应该在同一处发生bug。但是再次运行程序,bug的地址发生了变化:

这就可以确定是随机地址加载。因此首先在属性-链接器-高级选项中关闭随机基址和打开固定基址。

这之后,每次发生bug的地址都是固定的,到此可以确定bug地址。

但是,源码不在发布现场,现场也没调试器。定位代码还是不方便。有什么办法可以大概的定位到哪条语句?这时就如文章标题所说用到Map文件和List文件:

产生List文件:属性-c/c++-输出文件-汇编程序输出:程序集、机器码和源代码 (/FAcs)

产生Map文件:属性-连接器-调试-生成映射文件:是 (/MAP)

这里解释一下各个文件的意义:

List文件,包含源文件编译后(未连接)的行号和重定位汇编代码,如下:

; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01 

	TITLE	C:\studio\mapAsm\mapAsm\mapAsm\mapAsm.cpp
	.686P
	.XMM
	include listing.inc
	.model	flat

INCLUDELIB MSVCRTD
INCLUDELIB OLDNAMES

PUBLIC	_wmain
EXTRN	__RTC_Shutdown:PROC
EXTRN	__RTC_InitBase:PROC
;	COMDAT rtc$TMZ
; File c:\studio\mapasm\mapasm\mapasm\mapasm.cpp
rtc$TMZ	SEGMENT
__RTC_Shutdown.rtc$TMZ DD FLAT:__RTC_Shutdown
rtc$TMZ	ENDS
;	COMDAT rtc$IMZ
rtc$IMZ	SEGMENT
__RTC_InitBase.rtc$IMZ DD FLAT:__RTC_InitBase
; Function compile flags: /Odtp /RTCsu /ZI
rtc$IMZ	ENDS
;	COMDAT _wmain
_TEXT	SEGMENT
_ptr$ = -8						; size = 4
_argc$ = 8						; size = 4
_argv$ = 12						; size = 4
_wmain	PROC						; COMDAT

; 8    : {

  00000	55		 push	 ebp
  00001	8b ec		 mov	 ebp, esp
  00003	81 ec cc 00 00
	00		 sub	 esp, 204		; 000000ccH
  00009	53		 push	 ebx
  0000a	56		 push	 esi
  0000b	57		 push	 edi
  0000c	8d bd 34 ff ff
	ff		 lea	 edi, DWORD PTR [ebp-204]
  00012	b9 33 00 00 00	 mov	 ecx, 51			; 00000033H
  00017	b8 cc cc cc cc	 mov	 eax, -858993460		; ccccccccH
  0001c	f3 ab		 rep stosd

; 9    : 	char* ptr = NULL;

  0001e	c7 45 f8 00 00
	00 00		 mov	 DWORD PTR _ptr$[ebp], 0

; 10   : 	*ptr = 'A';

  00025	8b 45 f8	 mov	 eax, DWORD PTR _ptr$[ebp]
  00028	c6 00 41	 mov	 BYTE PTR [eax], 65	; 00000041H

; 11   : 	return 0;

  0002b	33 c0		 xor	 eax, eax

; 12   : }

  0002d	5f		 pop	 edi
  0002e	5e		 pop	 esi
  0002f	5b		 pop	 ebx
  00030	8b e5		 mov	 esp, ebp
  00032	5d		 pop	 ebp
  00033	c3		 ret	 0
_wmain	ENDP
_TEXT	ENDS
END
Map文件:连接后各个符号的链接地址,因为编译器假设连接地址就是加载地址,所以在固定基址的情况下程序会按链接地址加载到内存0x40000;但是启用了随机基址,那就连接地址跟加载地址不同,真心不好定位了。如图,显示了各个文件的链接地址:

  Address         Publics by Value              Rva+Base       Lib:Object

 0000:00000000       ___safe_se_handler_table   00000000     <absolute>
 0000:00000000       ___safe_se_handler_count   00000000     <absolute>
 0000:00000000       ___ImageBase               00400000     <linker-defined>
 0001:00000000       __enc$textbss$begin        00401000     <linker-defined>
 0001:00010000       __enc$textbss$end          00411000     <linker-defined>
 0002:00000350       _wmain                     00411350 f   mapAsm.obj
 0002:000003a0       __RTC_InitBase             004113a0 f   MSVCRTD:_init_.obj
 0002:000003e0       __RTC_Shutdown             004113e0 f   MSVCRTD:_init_.obj
 0002:00000520       _wmainCRTStartup           00411520 f   MSVCRTD:wcrtexe.obj
 0002:00000840       _NtCurrentTeb              00411840 f i MSVCRTD:wcrtexe.obj
 0002:000008e0       __RTC_NumErrors            004118e0 f   MSVCRTD:_userapi_.obj
 0002:000008f0       __RTC_GetErrDesc           004118f0 f   MSVCRTD:_userapi_.obj
 0002:00000910       __RTC_SetErrorType         00411910 f   MSVCRTD:_userapi_.obj
 0002:00000940       __RTC_SetErrorFunc         00411940 f   MSVCRTD:_userapi_.obj
 0002:00000970       __RTC_SetErrorFuncW        00411970 f   MSVCRTD:_userapi_.obj

程序异常发生在0x411378,正好在mapAsm.obj文件范围内:

异常指令的地址是0x411378,而mapAsm的地址是0x411350,两者相差0x28B。来看下这个偏移上的源文件和汇编代码:

; 10   : 	*ptr = 'A';

  00025	8b 45 f8	 mov	 eax, DWORD PTR _ptr$[ebp]
  00028	c6 00 41	 mov	 BYTE PTR [eax], 65	; 00000041H

果然是给空指针赋值引起~。知道Map文件和List文件的作用了吧。

附注,gcc也有类似功能,可参考如下连接:

http://blog.youkuaiyun.com/lanxinju/article/details/5900986

http://blog.chinaunix.net/uid-24567872-id-209622.html


### MapStruct 中 `@Mapping` 注解常见问题及解决方案 #### 一、背景介绍 MapStruct 是一种用于 Java 对象映射的强大框架,它通过注解驱动的方式减少手动编写模板代码的需求[^2]。其中,`@Mapping` 注解被广泛应用于指定字段之间的复杂映射关系。 然而,在实际开发过程中,开发者可能会遇到一些与 `@Mapping` 注解相关的问题,这些问题通常涉及配置不当或构建流程中的缺失部分[^3]。 --- #### 二、常见问题及其解决方案 ##### 1. **运行时报错:Cannot find implementation** 当在 Spring 项目中使用 MapStruct 的 `@Mapper` 或 `@Mapping` 注解时,如果运行时抛出 `Cannot find implementation` 错误,则表明 MapStruct 并未成功生成对应的 Mapper 实现类[^4]。 ###### 解决方案: - 确保 Maven/Gradle 配置文件中已正确引入 MapStruct 处理器依赖项。 ```xml <!-- Maven Example --> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.5.0.Final</version> <scope>provided</scope> </dependency> ``` - 如果使用的是 IDE(如 IntelliJ IDEA),需确认启用了 Annotation Processor 功能。对于 IntelliJ 用户,可以通过以下路径启用: - 打开设置菜单 (`File -> Settings`)。 - 导航至 `Build, Execution, Deployment -> Compiler -> Annotation Processors`。 - 勾选 “Enable annotation processing”。 --- ##### 2. **`@Mapping` 注解无效果** 即使编译阶段没有任何警告或错误提示,但在运行时发现某些字段并未按照预期完成映射操作。 ###### 可能原因: - 映射的目标字段名称拼写有误。 - 数据源对象缺少必要的 getter 方法或者目标对象缺少 setter 方法。 - 使用了自定义方法但未正确声明。 ###### 解决方案: - 检查 `source` `target` 属性是否完全匹配字段名大小写敏感度。 ```java @Mapping(source = "sourceField", target = "targetField") TargetObject map(SourceObject source); ``` - 若存在嵌套结构或其他特殊需求,可以尝试显式定义表达式逻辑: ```java @Mapping(target = "complexProperty", expression = "java(complexLogic(source))") ``` --- ##### 3. **集合类型的映射失败** 针对列表 (List) 或其他集合类型的数据映射出现问题。 ###### 解决方案: 利用内置支持的 Collection 类型处理器即可轻松解决问题。例如: ```java @Mapper public interface MyMapper { List<TargetType> convert(List<SourceType> sources); default TargetType singleConvert(SourceType source) { // 自定义单个元素转换规则 return new TargetType(...); } } ``` 注意此处默认方法的设计有助于增强灵活性并简化多层嵌套场景下的处理过程。 --- ##### 4. **忽略特定字段** 有时希望跳过某几个不需要参与映射的属性。 ###### 实现方式: 借助 `-` 符号标记那些应被排除在外的部分。 ```java @Mapping(target = "ignoredField", ignore = true) TargetObject map(SourceObject source); ``` --- ### 总结 上述列举了几种典型的关于 MapStruct `@Mapping` 注解可能遭遇的技术挑战以及相应的应对策略。合理调整项目环境设定配合细致入微地审查每一步骤能够有效规避大部分潜在障碍。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值