从发现.NET Framework中SmtpClient的Bug并拿出解决方案,然后给微软开发者社区提交Bug开始,总共耗时一个多月,对Bug修复的代码最终被采纳,现已合并到.NET Core Libraries (CoreFX)主线中。

修复记录https://github.com/dotnet/corefx/commit/94b1f1eae84fd4823cfa2bbdde6fc87c46b57908

虽然对Bug修复实际生效的代码只有20个字符,但意义重大,这个Bug不遇上一点事没有,遇上了不对框架开刀是非常棘手的,而且备受折磨也稍微有点难摸得清头脑。

相关详情见我的另外一篇博客《记录一次.Net框架Bug发现和提交过程:.Net Framework和.Net Core均受影响

问题描述

我们用SmtpClientSendAsyncSendMailAsync异步方法发送邮件,并且要求使用DeliveryFormat = SmtpDeliveryFormat.SevenBit 格式来编码中文内容,本来预期是邮件内容中带中文的SubjectAttachments file name 都会进行Base64编码。

但实际结果是:如果邮件服务器支持SMTPUTF8扩展,那么异步发送SevenBit邮件并不会进行Base64编码,同步方法没有此问题。

问题根源

原因是在SmtpClient.SendMailCallback方法中,message.BeginSend allowUnicode参数直接使用的ServerSupportsEai,而不是统一的IsUnicodeSupported()

 private void SendMailCallback(IAsyncResult result)
{
......
_message.BeginSend(_writer, DeliveryMethod != SmtpDeliveryMethod.Network,
ServerSupportsEai, new AsyncCallback(SendMessageCallback), result.AsyncState);
......
}

ServerSupportsEai改成IsUnicodeSupported()问题解决。就这20个字符的改动~

另外附对现有带Bug的.Net框架修复方法

比如使用的.NET Framework 4.7.2,纯天然原生自带此Bug,我们可以用我们的代码修复它。

最开始测试时以为此方法无效,没想到是Hook错了地方,换到最深层次调用地方,一抓一个准。

使用DotNetDetour库对.Net框架内方法进行Hook,找出SmtpClient.ServerSupportsEai最结果最终是从SmtpConnection.ServerSupportsEai得来的,也许是C#编译后把整个调用过程都优化掉了,变成了取值的地方直接调用的SmtpConnection中的方法,导致Hook前面的方法都是不会被执行,Hook SmtpConnection.ServerSupportsEai一抓一个准。

附上Hook代码:

public class Hook : IMethodMonitor {
public bool ServerSupportsEai {
[Monitor("System.Net.Mail", "SmtpConnection")]
get {
Console.WriteLine("Hook");
return !true?org():false;//什么情况下要Hook? AsyncLocal和CallContext上下文为什么在这里传不进来?
}
}
[Original]
public bool org() {
return false;
}
}

另外引出了另外一个折磨人Bug,异步环境下,ServerSupportsEai的调用栈中上下文怎么会丢失?难道哪里使用了类似ThreadPool.UnsafeXXX这种效果?我们没法通过CallContext(AsyncLocal)给Hook代码传参数,只能写死,不管调用方要不要修改返回值,都只能得到修改后的结果,尴尬不尴尬。

从.Net框架Bug的提交到修复代码成功合并到.NET CoreFX主线的更多相关文章

  1. 记录一次.Net框架Bug发现和提交过程:.Net Framework和.Net Core均受影响

    SmtpClient一处代码编写错误导致异步发送邮件时DeliveryFormat配置项无法正确工作,异步操作已经完全不受我们设置属性控制了,UTF-8内容(如中文)转不转码完全看对方邮件服务器心情! ...

  2. Bug报告提交规范

    首先声明,bug的测试规范应该在公司的正式文档建立.本建议非正式文档,有些内容可能不正确,有些内容可能需要继续商榷,甚至有些内容同公司规范有冲突.如果发现问题,直接忽略本文相应内容.本帖本意仅就工作中 ...

  3. tp框架表单提交注意!不要提交到当前方法

    tp框架  表单提交到当前方法,会重复执行显示部分和保存部分的代码.导致不知名的错误.

  4. github上测试服出现bug,如何回滚并获得合并之前的分支

    使用场景: 当我们提交了一个pr,但是该pr合并之后,经过在测试测试有问题,需要回滚.这个时候主master代码将会被回滚到提交你的pr之前的代码.而你的pr由于已经被合并过了,所以无法继续提交. 这 ...

  5. FDMemTable三层提交数据总是不成功的原因

    提交数据的代码如下: procedure TForm1.btnSaveClick(Sender: TObject);var LDeltas: TFDJSONDeltas;begin if FDMemT ...

  6. 意外作出了一个javascript的服务器,可以通过js调用并执行任何java(包括 所有java 内核基本库)及C#类库,并最终由 C# 执行你提交的javascript代码! 不敢藏私,特与大家分

    最近研发BDC 云开发部署平台的数据路由及服务管理器意外作出了一个javascript的服务器,可以通过js调用并执行任何java(包括 所有java 内核基本库)及C#类库,并最终由 C# 执行你提 ...

  7. 从bug中学习怎么写代码

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:从bug中学习怎么写代码.

  8. github的拉取、提交,创建分支与合并

    前期准备: 1.安装git  官网地址:https://git-scm.com/(下载下来,直接下一步)   2.github账号(这有点废话)   3.配置github密钥 下载及安装好git后,右 ...

  9. 基于Gitlab统计代码行--统计所有仓库、所有提交人的代码总行数(新增加-删除)

    公司绩效考核要求,统计GITLAB仓库所有人提示有效代码行业 脚本1: 统计所有仓库.所有提交人的代码总行数(新增加-删除) 脚本2: 统计所有仓库.所有提交人的代码提交汇总与删除汇总 脚本3: 统计 ...

随机推荐

  1. RESTful相关理解

    just 一种接口规范,写法种类不止一种  类似python的那啥标准

  2. Docker Compose 安装 on centos7

    本文演示如何在CentOS7上安装Docker Compose. 1 在线安装 1.1 下载安装包 $ curl -L https://github.com/docker/compose/releas ...

  3. [20180926]共享池中的NETWORK BUFFER.txt

    [20180926]共享池中的NETWORK BUFFER.txt --//最近几天一直在探究SQL*Net more data from client 相关等待事件,发现SDU相关,自己也网上探究一 ...

  4. 洗礼灵魂,修炼python(88)-- 知识拾遗篇 —— 线程(2)/多线程爬虫

    线程(下) 7.同步锁 这个例子很经典,实话说,这个例子我是直接照搬前辈的,并不是原创,不过真的也很有意思,请看: #!usr/bin/env python #-*- coding:utf-8 -*- ...

  5. 百度地图在web中的使用(一)

    百度地图在web中的使用(js) 背景:在公司做一个地理位置的自定义字段,需要用到地图来获取经纬度和地址,在这选择了百度地图 准备工作 注册百度地图开发者,创建应用获取key http://lbsyu ...

  6. Jetbrains IntelliJ IDEA PyCharm 注册激活(2018最新)

    AppCode CLion DataGrip GoLand IntelliJ IDEA PhpStorm PyCharm Rider RubyMine WebStorm下载注册激活 官方下载地址 Ap ...

  7. 【Linux基础】VM使用

    VM三种联网方法和原理 (1)Bridged桥接 使用VMnet0虚拟交换机,此时虚拟机相当与网络上的一台独立计算机与主机一样,拥有一个独立的IP地址,所有机器均可互访,可以联网.使用桥接方式,A,A ...

  8. C#基础知识之键盘对应的键值

    1.一般的按键禁用 一般的按键禁用只要找出相应的keycode禁用即可.例如:window.event.keyCode==13 //Enter键 其他可以对照一下的keyCode进行选择. 字母和数字 ...

  9. Automatically migrating data to new machines kafka集群扩充迁移topic

    The partition reassignment tool can be used to move some topics off of the current set of brokers to ...

  10. B. Yet Another Array Partitioning Task ——cf

    B. Yet Another Array Partitioning Task time limit per test 2 seconds memory limit per test 256 megab ...