由苹果的低级Bug想到的

前段时间的问题,本来想写篇文章说说代码规范,code review相关的,不过看到果壳已经有篇很棒的文章,借来放在这里,也是对自己的指导。果壳很好,里面的文章都很有很有含金量,建议大家都收藏起来


原文:http://coolshell.cn/articles/11112.html

作者:陈皓


————————————————————————————————————


2014年2月22日,在这个“这么二”的日子里,苹果公司推送了 iOS 7.0.6(版本号11B651)修复了 SSL 连接验证的一个 bug。官方网页在这里:http://support.apple.com/kb/HT6147,网页中如下描述:

Impact: An attacker with a privileged network position may capture or modify data in sessions protected by SSL/TLS

Description: Secure Transport failed to validate the authenticity of the connection. This issue was addressed by restoring missing validation steps.

也就是说,这个bug会引起中间人攻击,bug的描述中说,这个问题是因为miss了对连接认证的合法性检查的步骤。

这里多说一句,一旦网上发生任何的和SSL/TL相关的bug或安全问题,不管是做为用户,还是做为程序员的你,你一定要高度重视起来。因为这个网络通信的加密协议被广泛的应用在很多很多最最需要安全的地方,如果SSL/TLS有问题的话,意味着这个世界的计算机安全体系的崩溃。

Bug的代码原因

Adam Langley的《Apple’s SSL/TLS bug 》的博文暴出了这个bug的细节。(在苹果的开源网站上,通过查看苹果的和SSL/TLS有关的代码变更,我们可以在文件sslKeyExchange.c中找到下面的代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
                                  uint8_t *signature, UInt16 signatureLen)
{
     OSStatus        err;
     ...
     if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
         goto fail;
     if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
         goto fail;
         goto fail;
     if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
         goto fail;
     err = sslRawVerify(ctx,
                        ctx->peerPubKey,
                        dataToSign,              /* plaintext */
                        dataToSignLen,           /* plaintext length */
                        signature,
                        signatureLen);
     if (err) {
         sslErrorLog( "SSLDecodeSignedServerKeyExchange: sslRawVerify "
                     "returned %d\n" , ( int )err);
         goto fail;
     }
fail:
     SSLFreeBuffer(&signedHashes);
     SSLFreeBuffer(&hashCtx);
     return err;
}

注意,我高亮的地方,也就是那里有两个goto fail; 因为if语句没有加大括号,所以,只有第一个goto是属于if的,而第二个goto则是永远都会被执行到的(注:这里不是Python是C语言,缩进不代表这个语句属于同一个语句块)。也就是说,就算是前面的if检查都失败了(err  == 0),也会goto fail。我们可以看到fail标签中释放完内存后就会return err;

你想一下,这段程序在SSLHashSHA1.update()  返回成功,也就是返回0 的时候会发生什么样的事?是的,真正干活的 sslRawVerify()被bypass了。而且这个函数SSLVerifySignedServerKeyExchange() 还返回了0,也就是成功了!尼玛!你可能想到酷壳网上之前《一个空格引发的惨剧》的文章。都是低级bug。

这个低级bug在这个周末在网上被炒翻了天,你可以上Twiter上看看#gotofail的标签的盛况Goto Fail必然会成为历史上的一个经典事件

如果你喜欢XKCD,你一定会想到这个漫画:

注意:这个bug不会影响TLS 1.2版本,因为1.2版本不会用这个函数,走的是另一套机制。但是别忘了client端是可以选择版本的。

如果你想测试一下你的浏览器是否会有问题,你可以上一下当天就上线的 https://gotofail.com 网站

一些思考

下面是我对这个问题的一些思考。

0)关于编译报警

有人在说苹果的这个代码中的goto语句会产生死代码——dead code,也就是永远都不会执行到的代码,C/C++的编程器是会报警的。但,实际上,dead code在默认上的不会报警的。即使你加上-Wall,GCC 4.8.2 或 Clang 3.3 都不会报警,包括Visual Studio 2012在默认的报警级别也不会(默认是/W3级,需要上升到/W4级以上,但是升级到/W4上,你的工程可能会有N多的Warning,你不一定能看得过来)。gcc和Clang有一个参数叫:-Wunreachable-code,是可以对这种情况报警的,但即没有被包括在-Wall里。原因是,这个参数有很多的问题,因为编译器的优化代码的行为,这个参数并不能对每种情况都准确地报告。另请注意,GCC的新版本中剔除了这个参数。当然,其它一些静态的代码检查工具也可以检查这个低级的问题。

另外,是不是用IDE的代码自动化格式工具也可以帮上一点忙呢?至少可以把那个缩进变成让人一看就觉得有问题。

1)关于Code Merge 和 Code Review

你可以通过这里的代码比较看到这个bug的diff,也可以到这里看看(631行)。

diff -urN <(curl -s http://opensource.apple.com/source/Security/Security-55179.13/libsecurity_ssl/lib/sslKeyExchange.c\?txt) \ <(curl -s http://opensource.apple.com/source/Security/Security-55471/libsecurity_ssl/lib/sslKeyExchange.c\?txt) \

通过code diff你可以看到,苹果公司是在重构代码——为很多函数去掉了ctx的参数

所以,我们可以猜测,两个goto fail语句,可能是因为对code在不同branch上做merge发生的。版本工具merge代码的时候,经常性的会出现这样的问题。如果代码的diff很多,这个问题会很容易就没有注意到。就算有code review,这个有问题的代码也很难被找出来的。如果你来review下面的diff,你会注意到这个错误吗?

也就是说,在重构分支上的代码是对的,但是在分支merge的时候,被merge工具搞乱了。所以说,我们在做code merge的时候,一定要小心小心再小心,不能完全相信merge工具

2)关于测试

很明显,这个bug很难被code review发现。对于重构代码和代码merge里众多的diff,是很难被review的。

当然,“事后诸葛亮”的人们总是很容易地说这个问题可以被测试发现,但是实际情况是这样的吗?

这个问题也很难被功能测试发现,因为这个函数在是在网络握手里很深的地方,功能 测试不一定能覆盖得那么深,你要写这样的case,必需对TLS的协议栈非常熟悉,熟悉到对他所有的参数都很熟悉,并能写出针对每一个参数以及这些参数的组合做一堆test case,这个事情也是一件很复杂的事。要写出所有的case本身就是一件很难很难的事情。关于这个叫SSLVerifySignedServerKeyExchange()函数的细节,你可以看看相关的ServerKeyExchange RFC文档。

如果只看这个问题的话,你会说对这个函数做的 Unit Test 可以发现这个问题,是的。但是,别忘了SSL/TLS这么多年了,这些基础函数都应该是很稳定的了, 在事前,我们可能不会想到要去为这些稳定了多少年的函数写几个Unit Test。

只要有足够多的时间,我们是可以对所有的功能点,所有的函数都做UT,也可以去追求做代码覆盖和分支覆盖一样。但有一点我们却永远无法做到,那就是——穷举所有的负面案例。所以,对于测试来说,我们不能走极端,需要更聪明的测试。就像我在《我们需要专职的QA》文章里的说过的——测试比coding难度大多了,测试这个工作只有高级的开发人员才做得好。我从来不相信不写代码的人能做好测试。

这里,我并不是说通过测试来发现这个问题的可能性不大,我想说的是,测试很重要,单测更重要。但是,我们无法面面俱到。在我们没有关注到的地方,总会发生愚蠢的错误。

P.S.,在各大网站对这个事的讨论中,我们可以看到OS X下的curl命令居然可以接受一个没有验证过的IP地址的https的请求,虽然现在还没有人知道这事的原因,但是,这可能是没有在测试中查到的一个原因。

3)关于编码风格

对于程序员来说,在C语言中,省掉语句大括号是一件非常不明智 的事情。如我们强制使用语句块括号,那么,这两个goto fail都会在一个if的语句块里,而且也容易维护并且易读。(另外,通过这个bug,我们可以感受到,像Python那样,用缩进来表示语句块,的确是挺好的一件事)

也有人说,如果你硬要用只有单条语句,且不用语句块括号,那么,这就是一条语句,应该放在同一行上。如下所示:

1
if   (check_something)   do_something();

但是这样一来,你在单步调试代码的时候,就有点不爽了,当你step over的时候,你完全不知道if的条件是真还是假。所以,还是分多行,加上大括号会好一些。

相似的问题,我很十多年前也犯过,而且那次我出的问题也比较大,导致了用户的数据出错。那次就是维护别人的代码,别人的代码就是没有if的语句块括号,就像苹果的代码那样。我想在return z之前调用一个函数,结果就杯具了:

1
2
3
4
5
6
7
if ( ...... )
     return x;
if ( ...... )
     return y;
if ( ...... )
     foo();
     return z;

这个错误一不小心就犯了,因为人的大脑会相当然地认为缩进的都是一个语句块里的。但是如果原来的代码都加上了大括号,然后把缩进做正常,那么对后面维护的人会是一个非常好的事情。就不会犯我这个低级错误了。就像下面的代码一样,虽然写起来有点罗嗦,但利人利己。

1
2
3
4
5
6
7
8
9
if ( ...... ){
     return x;
}
if ( ...... ){
     return y;
}
if ( ...... ){
     return z;
}

与此类似的代码风格还有如下,你觉得哪个更容易阅读呢?

  • if (!p)    和  if (p == NULL)
  • if (p)    和  if (p != NULL)
  • if (!bflag)  和 if  (bflag == false)
  • if ( CheckSomthing() )  和 if ( CheckSomething() == true )

另外还有很多人在switch 语句里用case来做if,也就是说case后面没有break。就像Duff’s Device一样,再配以goto,代码就写得相当精彩了(这里有个例子)

所以说,代码不是炫酷的地方是给别人读的。

另外,我在想,为什么苹果的这段代码不写成下面这样的形式?你看,下面这种情况不也很干净吗?

1
2
3
4
5
6
7
8
if (  ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0 )
        || ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0)
        || ((err = SSLHashSHA1.update(&hashCtx, &serverRandom) != 0)
        || ((err = SSLHashSHA1.update(&hashCtx, &signedParams) != 0)
        || ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)) {
      goto fail;
}

其实,还可以做一些代码上的优化,比如,把fail标签里的那些东西写成一个宏,这样就可以去掉goto语句了。

4)关于goto语句

关于goto语句,1968年,Edsger Dijkstra 投了一篇文章到Communications of the ACM。原本的标题是《A Case Against the Goto Statement》。CACM编辑Niklaus Wirth灵感来了,把标题改为我们熟知的 《Go To Statement Considered Harmful》Dijkstra写的内容也是其一贯的犀利语气,文中说:“几年前我就观察到,一个程序员的品质是其程序中goto语句的密度成反比的”,他还说,“后来我发现了为什么goto语句的使用有这么严重的后果,并相信所有高级语言都应该把goto废除掉。”  (花絮:因为,这篇文章的出现,计算学界开始用’ X considered harmful ’当文章标题的风潮,直到有人终于受不了为止)

为什么goto语句不好呢?Dijkstra说,一个变量代表什么意义要看其上下文。一个程序用N记录房间里的人数,在大部分时候,N代表的是“目前房间里的人”。但在观察到又有一个人进房间后、把N递增的指令前的这段程序区块中,N的值代表的是“目前房间里的人数加一”。因此,要正确诠释程序的状态,必须知道程序执行的历史,或着说,知道现在“算到哪”了。

怎么谈“算到哪了”?如果是一直线执行下来的程序,我们只要指到那条语句,说“就是这里”,就可以了。如果是有循环程序,我们可能得说:“现在在循环的这个地方,循环已经执行了第i次”。如果是在函数中,我们可能得说:“现在执行到函数p的这一点;p刚刚被q调用,调用点在一个循环中,这个循环已经执行了i次”。

如果有goto语句了呢?那就麻烦了。因为电脑在执行某个指令前,可能是从程序中许许多多goto其中之一跳过来的。要谈某变量的性质也几乎变得不可能了。这就是为什么goto语句问题。

Dijkstra的这篇文章对后面很多程序员有非常深的影响,包括我在内,都觉得Goto语句能不用就不用,虽然,我在十年前的《编程修养》(这篇文章已经严重过时,某些条目已经漏洞百出)中的第23条也说过,我只认为在goto语句只有一种情况可以使用,就是苹果这个bug里的用法。但是我也同意Dijkstra,goto语句能不用就不用了。就苹果的这个问题而言,在更为高级的C++中,使用RAII技术,这样的goto语句已经没有什么存在的意义了。

Dijkstra这篇文章后来成为结构化程式论战最有名的文章之一。长达19年之后,Frank Rubin投了一篇文章到CACM,标题为《‘ Go To Considered Harmful’ Considered Harmful 》Rubin说,「虽然Dijkstra的说法既太学术又缺乏说服力」,却似乎烙到每个程序员的心里了。这样,当有人说“用goto语句来解这题可能会比较好”会被严重鄙视。于是Rubin出了一道这样的题:令XN * N的整数阵列。如果X的第i行全都是零,请输出i。如果不只一行,输出最小的i .

Rubin找了一些惯用goto和不用goto的程序员来解题,发现用goto的程序又快又清楚。而不用goto通常花了更多的时间,写出很复杂的解答。你觉得呢? 另外,你会怎么写这题的程序呢?

花絮:以后几个月的CACM热闹死了。编辑收到许多回应,两个月后刊出了其中五篇。文章也包括了《“‘GOTO Considered Harmful’ Considered Harmful” Considered Harmful? 》)

对于我而言,goto语句的弊远远大于利,在99%的情况下,我是站在反goto这边的。Java和Python就没有提供Goto语句,原因就是因为goto语句很容易被滥用!

花絮:这段时间,我在开发Nginx的模块,因为以前没有做过,而且Nginx的开发文档也不好,所以就得读一些别人的源代码。当我看了某个nginx redis的模块里的这段代码 ngx_http_redis2_reply.c 看到里面飞沙走石的goto语句,我崩溃了,当然,这是代码自动生成工具生成出来的,只是想以这个例子说明goto也是混乱代码的一种黑魔法(另,这位同学看似很喜欢goto语句,在很多代码里都能看得见,比如:这里,这里,还有这里……,虽然我觉得很多goto都没有必要)。我想说,如果人把代码写成这样,那我看到这样的代码的时候,就像我在某个餐馆看到了他那肮脏的厨房,无论做菜的技艺有多高超,做的菜做得有多好看多好吃,我都恶心得一点也不想吃了)

更新:2014年3月5日 - RedHat 近日也发现个GnuTLS安全问题,与苹果的类似:无法正确检验特定的伪造SSL证书,这个总是会将伪造证书识别为有效证书。虽然Redhat的代码为if加上了花括号,但还是因为没有控制好goto,造成了bug。所以说啊,goto语句的坑是很多。

  • BUG页面:https://bugzilla.redhat.com/show_bug.cgi?id=1069865
  • 相关的Diff: https://bugzilla.redhat.com/attachment.cgi?id=867911&action=diff

goto语句在写代码的时候也许你会很爽,但是在维护的时候,绝对是一堆坑!redhat的这个patch为原来本来只有一个label的goto又加了另一个label,现在两个label交差goto,继续挖坑……

总结

你看,我们不能完全消灭问题,但是,我们可以用下面几个手段来减少问题:

1)尽量在编译上发生错误,而不是在运行时

2)代码是让人读的,顺便让机器运行。不要怕麻烦,好的代码风格,易读的代码会减少很多问题。

3)Code Review是一件很严肃的事情,但 Code Reivew的前提条件是代码的可读性一定要很好。

4)测试是一件很重要也是很难的事情,尤其是开发人员要非常重视

5)不要走飞线,用飞线来解决问题是可耻的!所以,用goto语句来组织代码的时代过去了,你可以有很多种方式不用goto也可以把代码组织得很好。

最后,我在淘宝过去的一年里,经历过一些P1/P2故障,尤其是去年的8-9月份故障频发的月份,我发现其中有70%的P1/P2故障,就是因为没有code review,没有做好测试,大量地用飞线来解决问题,归根结底就是只重业务结果,对技术没有应有的严谨的态度和敬畏之心。

正如苹果的这个“goto fail”事件所暗喻的,如果你对技术没有应有的严谨和敬畏之心,你一定会——

Go To Fail !!!

在这里唠叨这么多,与大家共勉!

(全文完)

(转载本站文章请注明作者和出处 酷 壳 – CoolShell.cn ,请勿用于任何商业用途)

——===  访问 酷壳404页面 寻找遗失儿童。 ===——



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

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

相关文章

关于人工智能不会使大脑变懒惰的议论文_台湾人工智能学校执行长陈升玮:孩子成为这型人,就不怕被AI取代...

陪伴每个父母和小孩&#xff0c;成为更好的自己。 搜寻公众号 "亲子天下"(微信 ID&#xff1a;cn-parenting)关注 世界经济论坛〈工作大未来〉报告二○一六年的预测&#xff1a;二○二一年全世界会产生两百万个新工作&#xff0c;但随着人工智能(AI)兴起&#xff0c;…

关于人工智能不会使大脑变懒惰的议论文_人工智能的好处和风险:所有您需要知道的...

​ 人工智能不是想象中的未来。现在,在我们的搜索引擎中,人工智能不仅仅是自动完成,也不仅仅是自动驾驶汽车。从机器学习到机器人,人工智能为我们提供了多种技术,使机器能够感知,理解,学习和行动。 是否考虑将绝佳的AI机会纳入您的业务?在您做出决定之前,这里有一些AI…

有可以模拟钢琴弹奏乐曲的手机软件吗?

我们常常喜欢抱着手机做很多有趣的事。其实现在的智能手机真的可以做很多以前意想不到的事。像是手机里有可以模拟钢琴弹奏乐曲的手机软件&#xff0c;钢琴键盘模拟器很有趣。所以很受年轻的小伙伴欢迎。今天我就在这里和大家分享一下&#xff0c;可以模拟钢琴弹奏乐曲的手机软…

普通计算机可以演奏音乐吗,用电脑演奏的音乐还是音乐吗?

现代电子科技迅猛发展&#xff0c;很多作曲家都用电脑作曲&#xff0c;非常方便&#xff0c;就是演奏的时候也能交给电脑负责&#xff0c;合成多个音轨&#xff0c;演奏出复杂的音乐作品。那么&#xff0c;用电脑演奏的音乐还是音乐吗&#xff1f; 当然是音乐。电脑可以负责人脑…

freepiano 手残党也想弹钢琴(在电脑上弹奏电子钢琴自娱自乐,也许还是有点困难,不如试试freepiano+鼠标宏,这样用简谱就不怕残疾了)

我不懂五线谱&#xff0c;勉强能看看简谱&#xff0c;喜欢音乐&#xff0c;但又手残玩不好乐器&#xff0c;像是钢琴电子琴都是双手一起像打键盘一样弹右手位&#xff0c;没法自己搞伴奏&#xff0c;吉他也按不住大横按的和弦&#xff0c;简直没有音乐细菌。 自己想玩吧&#…

毛利率低至个位数,甚至为负?车载语音赛道「现实很骨感」

作为座舱智能化交互的关键角色之一&#xff0c;语音识别及交互一直以来也是不少汽车品牌的主打功能之一。 比如&#xff0c;随意打断语音助手&#xff0c;连续下达指令&#xff0c;融合更多车身控制功能&#xff0c;甚至是ChatGPT大模型的结合&#xff0c;给了消费者更多的想象…

北森控股,云端HCM解决方案“一哥”胜算几成?

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 近日&#xff0c;云端HCM解决方案“一哥”北森控股有限公司&#xff08;以下简称“北森控股”&#xff09;再度递表港交所&#xff0c;摩根士丹利及中金公司为联席保荐人。 资料来源&#xff1a;北森控股招股书 此次IPO北森…

第四范式,第四次递表!能否凭借SageGPT挤进大模型赛道?

4月24日消息&#xff0c;据港交所文件&#xff0c;北京第四范式智能技术股份有限公司向港交所提交上市申请书&#xff0c;中金公司担任独家保荐人。如能顺利上市&#xff0c;第四范式将成为继商汤科技&#xff08;00020.HK&#xff09;、创新奇智&#xff08;02121.HK&#xff…

机械图样解读——回转面

回转面的形成 直线或曲线绕轴线回转形成的曲面称为回转面。 回转面的表示

机械制图 机械识图 三视图画法认图视频教程

机械制图 机械识图 三视图画法认图视频教程 链接&#xff1a;https://pan.baidu.com/s/1fUtYooCRIkoLN5lyFURWCA 提取码&#xff1a;1612

解读机械图样——斜视图

斜视图是零件向不平行于基本投影面的平面投射所得的视图&#xff0c;用于表达零件上倾斜结构的真实形状&#xff0c;如图1-8所示。对于垂直于斜面的孔和槽&#xff0c;用斜视图可以按照实际的尺寸画出它的形状&#xff0c;也易于标注尺寸。 绘制斜视图时&#xff0c;一般在原图…

【CAD】机械类制图实用功能总结

【CAD】机械类制图实用功能总结 一、简介二、正文&#xff08;一&#xff09;快捷键/快捷字母&#xff08;二&#xff09;实用功能1、块2、零件件号标注及材料表关联&#xff08;Vault&#xff09;3、粗糙度标准更改4、增加图纸页数&#xff08;Vault&#xff09;5、尺寸对齐6、…

Highcharts绘制饼图

1、使用Highcharts制作饼图的效果图如下: 2、对应的JavaScript代码---pie-chart.js如下: $(function () {var chart;var totalMoney=50000$(document).ready(function() {chart = new Highcharts.Chart({chart: {renderTo: pie_chart,plotBackgroundColor: white,//背景颜色…

helm和chart

Helm helm是Kubernetes 应用的包管理工具&#xff0c;主要用来管理 Charts&#xff0c;类似Linux系统的yum。Helm Chart 是用来封装 Kubernetes 原生应用程序的一系列 YAML 文件。可以在你部署应用的时候自定义应用程序的一些 Metadata&#xff0c;以便于应用程序的分发。 he…

控制highcharts饼图四周线的长短

var colors [#08c60c,//绿色#ffc002,//黄色#eb3928,//红色#B5B5B5//灰色 ]; // 创建渐变色 Highcharts.getOptions().colors Highcharts.map(colors, function (color) {return {radialGradient: { cx: 0.5, cy: 0.3, r: 0.7 },stops: [[0, color],[1, Highcharts.Color(colo…

CAD轴测图怎么画?快来试试浩辰CAD超级轴测命令!

很多新手设计师小伙伴&#xff0c;不知道CAD轴测图怎么画&#xff1f;其实很简单&#xff0c;浩辰CAD中的超级轴测功能&#xff0c;可以方便地将CAD平面图转化为轴侧图&#xff0c;是绘制管线系统图的好帮手。今天就和小编一起来看看在浩辰CAD软件中通过调用超级轴测命令来绘制…

使用highchart实现3D饼图(重点是3D图、饼图图例不显示问题)

一&#xff1a;使用highchart实现3D饼图 HTML&#xff1a;需要一个容器来绘图 <div class"dataItemRight" id"trafficData"></div>JS&#xff1a;所需js文件 <script src"js/jquery.min.js" type"text/javascript" c…

TeeChart基础使用手册

TeeChart使用手册 pdf版下载地址 TeeChart库下载 文章目录 TeeChart使用手册1、TeeChart.dll、TeeChart8.ocx、TeeChart.WPF.dll优缺点1.1 TeeChart.dll1.2 TeeChart8.ocx1.3 TeeChart.WPF.dll 2、Windows窗体应用(.NET Framework) TeeChart.dll2.1 创建工程2.2 添加TeeChart…

解读机械图样——基本视图

1.投影基本知识 机械图样的绘制必须按照投影法则进行。零件在太阳光、灯光等光源的照射下会产生影子&#xff0c;在此现象的启示下&#xff0c;假设光源发出的光线能透过零件&#xff0c;则零件表面的顶点、棱线就会在选定的平面上投下影子&#xff0c;产生的平面图形即为投影&…

机械设计:如何能看懂复杂机械图纸中的尺寸标注,赶快学起来

小编的话:出入加工现场,各种繁杂的加工工序图纸,你是否都看得懂?这次小编为各位社友带来机械设计中尺寸标注类知识,再也不用担心看不懂图纸啦—— 常见结构的尺寸注法常见孔的尺寸注法(盲孔、螺纹孔、沉孔、锪平孔);倒角的尺寸注法。 ❖ 盲孔 ❖ 螺纹孔 ❖ 沉孔 …