18video性欧美19sex,欧美高清videosddfsexhd,性少妇videosexfreexxx片中国,激情五月激情综合五月看花,亚洲人成网77777色在线播放

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

一只發(fā)生概率小于萬分之一的Bug

程序人生 ? 來源:程序新視界 ? 作者:二師兄 ? 2022-05-05 09:36 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在開始這篇文章之前想先說一句:如果一套系統(tǒng)暫時沒問題,那只是因為它的并發(fā)量不夠而已。

上周在查看系統(tǒng)日志時,發(fā)現(xiàn)了一條與眾不同的日志。日志中有一半內容是正常的報文數(shù)據(jù),而另一半內容是0x00這樣的空數(shù)據(jù)。

雖然系統(tǒng)沒拋出任何異常,但這些日志肯定是反常的。多年的經(jīng)驗告訴我,這其中一定有什么不對的地方,加上好奇心的驅使,終于揭開了一個隱藏非常深的Bug。

有時候找到Bug,解決Bug很容易,難的是如何發(fā)現(xiàn)Bug,并推理出哪里出問題解決。下面就帶大家來剖析一下這個Bug。

奇怪的日志輸出

一個調用外部接口的基礎類,打印出類似如下的日志:

abcdabcdabcdabcdabcdabcdabcd《0x00》《0x00》《0x00》《0x00》《0x00》

其中前面的abcd是正常的業(yè)務數(shù)據(jù),后面莫名其妙的多出了很多《0x00》。

那么,這個基礎工具類有多基礎?多處使用該方法,每天大約被調用幾十萬次吧,而上面的情況一天只會出現(xiàn)幾次。就是那么巧,恰好被看到了。

查看代碼,初步推斷,可能是byte數(shù)組轉String時,byte數(shù)組后半部分為空或存在一些無法轉換的數(shù)據(jù)導致的。

舊代碼分析

這里先把業(yè)務代碼脫敏,寫成一個demo展示給大家看看:

public static void oldCode() throws IOException

{

// 通過HttpURLConnection讀取的外部系統(tǒng)返回的流

InputStream in = new ByteArrayInputStream(“abc”.getBytes());

// 明確知道的報文長度(解析Header獲得)

int bodyLen = 2048;

byte[] body = new byte[bodyLen];

int recvLen = 0; while (recvLen 《 bodyLen)

{

recvLen = in.read(body, recvLen, bodyLen - recvLen);

if(recvLen == -1){

break;

}

}

System.out.println(new String(body, “GBK”));}

上述代碼進行了業(yè)務脫敏處理,僅為還原基本的使用過程。

業(yè)務場景的大概使用流程是:第一,通過HTTP調用遠程接口;第二,讀取接口返回的字節(jié)流,Inputstream;第三,解析字節(jié)流,存入字節(jié)數(shù)組;第四,將字節(jié)數(shù)組轉換為String。

而日志中看到的異常內容,便是打印String時出現(xiàn)的。前面我們已經(jīng)推斷,出現(xiàn)《0x00》的可能性是字節(jié)數(shù)組有一部分為空導致或數(shù)據(jù)錯誤導致的。

上述代碼有一個明顯的錯誤,你是否能夠看出來?根據(jù)代碼原始的寫法,推測之所以出現(xiàn)這個錯誤是因為使用者對InputStream的read方法并不熟悉導致的。

這里讀者先自行閱讀看看上述代碼的Bug在哪里,下面我們來介紹一下InputStream的read方法。

InputStream的read方法

InputStream這個抽象類是表示字節(jié)輸入流的所有類的超類,它提供了3個經(jīng)常被使用的read()方法:

read(),無參方法。該方法從輸入流中讀取數(shù)據(jù)的下一個字節(jié)。返回0到255范圍內的int字節(jié)值。如果因為已經(jīng)到達流末尾而沒有可用的字節(jié),則返回值 -1 。該方法會處于阻塞狀態(tài),等待數(shù)據(jù)的到達,直到返回值為-1或拋出異常。

read(byte b[], int off, int len):將輸入流中最多l(xiāng)en個數(shù)據(jù)字節(jié)讀入byte數(shù)組。嘗試讀取len個字節(jié),但讀取的字節(jié)也可能小于該值。以整數(shù)形式返回實際讀取的字節(jié)數(shù)。

read (byte[] b):從輸入流中讀取一定數(shù)量的字節(jié),并將其存儲在緩沖區(qū)數(shù)組b中。以整數(shù)形式返回實際讀取的字節(jié)數(shù)。

分析一下上面的三個方法。

其中第一個方法,本質上來說后兩個方法都是調用第一個方法來實現(xiàn)的,但第一個方法直接使用缺點很明顯,就是處理效率低下,一個字節(jié)一個字節(jié)的讀。而后兩個方法都加入了byte數(shù)組,用來作為緩存區(qū)。

而第三個方法又相當于第二個方法被如下方式調用:

read(b, 0, b.length)

而有Bug的代碼中使用的是第二個方法。

Bug分析

看了read方法的API說明,你是不是已經(jīng)找到Bug了?對的,當初寫這段代碼的人把read方法返回值理解錯了。

recvLen = in.read(body, recvLen, bodyLen - recvLen);

最初寫代碼的人可能把read方法的返回值當中參數(shù)off經(jīng)過讀取之后新的位置了。這樣在調用read方法之后,獲得了填充的位置,然后拿總長度減去已經(jīng)填充的位置,再繼續(xù)讀取后面的內容,繼續(xù)填充。

但實際上read方法的返回結果是:以整數(shù)形式返回實際讀取的字節(jié)數(shù),可能與off的位置值相同,但并不是off的位置。

下面來分析一下while循環(huán)中的邏輯處理情況:

while (recvLen 《 bodyLen)

{

recvLen = in.read(body, recvLen,

bodyLen - recvLen);

if(recvLen == -1){

break;

}}

我們舉個例子來推演一下2種情況(為了方便推算,暫且用比較小的數(shù)來舉例)。

情況一:假設bodyLen長度為10,read一次性讀完。

在這種情況中,先進入while循環(huán),read一次性讀完,返回值為10,此時recvLen賦值為10,不再滿足循環(huán)條件(recvLen 《 bodyLen),退出循環(huán),繼續(xù)執(zhí)行。此時,代碼沒問題。這種情況可能占到99.9%-99.99%(取決于請求頻次和報文大小)。

情況二:假設bodyLen長度為10,read 2次讀完(發(fā)生粘包拆包現(xiàn)象)。

第一次循環(huán),read讀取6個字節(jié)長度,返回值為6,recvLen賦值為6。第二次循環(huán),off參數(shù)取recvLen的值為6,讀取剩余4個字節(jié)(10 - 6)。完成第二次讀取,循環(huán)本應該結束的,但你會發(fā)現(xiàn)此時recvLen被賦值為4,依舊滿足while循環(huán)的判斷條件(recvLen 《 bodyLen),進行下一輪讀取。

下一輪讀取時,off變?yōu)?,len變?yōu)椋?0 - 4)。本來經(jīng)過第二輪循環(huán)off已經(jīng)讀取到10了,現(xiàn)在又指定為4,又去流中讀取。這就造成了日志中出現(xiàn)很多《0x00》。

Bug原因

經(jīng)過上述分析,我們已經(jīng)找到Bug,并獲得了Bug原因。

首先,Bug之所以沒有大面積爆發(fā),那是因為大多數(shù)請求都是一次性讀完流中的數(shù)據(jù),循環(huán)直接結束,當不會進入第二次循環(huán)時,這個Bug就被隱藏了。

其次,Bug之所以發(fā)生除了使用者對API的返回值不了解,更重要的原因是對于read方法可能會將結果分多次返回(粘包拆包現(xiàn)象)不了解。

Bug改造

找到原因,改造起來就非常容易了。針對demo我們重新改造一下:

public static void oldCode()

throws IOException

{

// 通過HttpURLConnection讀取的外部系統(tǒng)返回的流

InputStream in = new ByteArrayInputStream(“abc”.getBytes());

// 明確知道的報文長度(解析Header獲得)

int bodyLen = “abc”.getBytes().length;

System.out.println(bodyLen);

byte[] body = new byte[6];

int recvLen = 0; while (recvLen 《 bodyLen)

{

// 改造點1

int currentLen = in.read(body, recvLen, bodyLen - recvLen);

if(currentLen == -1){

break;

}

// 改造點2

recvLen += currentLen;

}

System.out.println(new String(body, “GBK”));}

上述改造只改動了兩處,將read方法的返回值用新變量接收,然后讓recvLen每次累加read讀取的字節(jié)數(shù)。

改造是不是非常簡單?正應了那句話:改bug很容易,難的是如何找到bug。

小結

有時候我們對自己寫的代碼很自信,有時候總以為代碼之前能夠正常運行,以后也能夠正常運行。但往往事與愿違,誰能想到一直“運行良好”的代碼中深藏著這樣的Bug?所以,還是那句話,如果你覺得你的代碼沒問題,那只是因為系統(tǒng)的并發(fā)量還不夠而已。代碼不僅要實現(xiàn)功能,還要滿足性能和健壯性。

審核編輯 :李倩

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 數(shù)組
    +關注

    關注

    1

    文章

    420

    瀏覽量

    27054
  • BUG
    BUG
    +關注

    關注

    0

    文章

    156

    瀏覽量

    16189

原文標題:捕獲了一只發(fā)生概率小于萬分之一的Bug

文章出處:【微信號:coder_life,微信公眾號:程序人生】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    世界上最小的傳感器有多小 頭發(fā)絲的十萬分之一到百萬分之一

    世界上最小的傳感器有多????世界上最小的傳感器可以達到人類頭發(fā)絲的十萬分之一到百萬分之一。據(jù)央視報道,在2025年9月,我國科研團隊開發(fā)的量子傳感器尺寸僅0.5納米,相當于人類頭發(fā)絲的百萬分之一,可測量細胞、分子級微觀信號及超弱
    的頭像 發(fā)表于 09-22 11:17 ?793次閱讀

    H5021B+H5442L+H5227Y支持數(shù)轉模無頻閃調光的48V降壓36V10A高效調光調色電源芯片方案 百級VS千級VS萬分級調光

    定要求的產(chǎn)品?!? 3.H5227Y 與萬分級調光? “H5227Y設置了DIM引腳,可接受PWM信號調光,最低調光深度可達萬分之一,低的調光深度適用于些對調光深度要求高的產(chǎn)品?!?三、場景化選型指南(附
    發(fā)表于 09-12 16:25

    H5227Y 升壓恒流芯片 24V36V48V轉54V-60V 10A大電流無頻閃萬分之一調光攝影燈方案

    的LED驅動芯片的款外置mos升壓恒流芯片,支持升壓、降壓和升降壓三種拓撲結構,支持萬分之一調光深度,RGBW調光,調光無頻閃,支持PWM調光,線性調光和數(shù)轉模調光功能。 技術參數(shù) ★支持降壓、升壓
    發(fā)表于 04-24 10:29

    如何制作和控制一只仿生手

    這個項目介紹了如何制作和控制一只仿生手。作者最初受到Instagram上個視頻的啟發(fā),該視頻展示了使用MPU6050傳感器追蹤手部動作并在屏幕上顯示3D模型。作者決定將這個想法進步發(fā)展
    的頭像 發(fā)表于 04-15 11:52 ?794次閱讀
    如何制作和控制<b class='flag-5'>一只</b>仿生手

    唯卓仕135mm LAB VS 尼康135 Plena:四分之一價格能否撼動尼康Plena?

    卡口的上市,場“四倍價差”的較量正式拉開帷幕——尼康Z135mmf/1.8SPlena售價19999元,唯卓仕LAB版本僅為其四分之一。究竟元差價是品牌溢價,
    的頭像 發(fā)表于 03-21 16:28 ?688次閱讀
    唯卓仕135mm LAB VS 尼康135 Plena:四<b class='flag-5'>分之一</b>價格能否撼動尼康Plena?

    JCMsuite應用:四分之一波片

    電場分量或磁場分量的解決方案。這是由于需要對該場進行額外的導數(shù)求解。 對四分之一波片近場(見上圖)的分析證實了幾何光學的預期: 在周圍的空氣中波片內偏振變化發(fā)生 為零(和界面)。向下傳播(輸出)平面波
    發(fā)表于 02-21 08:49

    DAC3482設置DACCLK時,到底需要設置成和DATACLK相等還是二分之一的關系?

    =DACCLK時則可以看到報警寄存器先為不沖突,段時間后變?yōu)?-away,再過段時間變?yōu)?-away,再過段時間變?yōu)閒ifo-collision,依次循環(huán),請問我設置DACCLK時到底需要設置成和DATACLK相等還是二
    發(fā)表于 01-08 07:24

    ADS1278存在1/1000的增益誤差,這個誤差在每次啟動會變化嗎?

    請教大伙個問題哈,ADS1278存在1/1000的增益誤差,這個誤差在每次啟動會變化么?當然我們不考慮溫度的影響,比方說第次啟動增益誤差萬分之二,第二次啟動為負萬分之一?還是說
    發(fā)表于 12-25 08:28

    ads8332采集值偏差很大是什么原因導致的?

    5v供電,參考電壓4.096V。使用兩個萬分之一誤差的10K電阻串聯(lián),端接地,端接REF電壓,中間連接至ads8332的ADCIN管腳。每次讀取的ADC值在32780附近。無論如何配置都不能
    發(fā)表于 12-24 06:56

    為什么DAC7811輸出電壓是理論值的二分之一?

    為什么輸出電壓是理論值的二分之一?
    發(fā)表于 12-12 07:58

    請問DAC8760超量程10%如何使用設置?

    因DAC8760內部自帶基準或外部基準精度準確度十有限誤差都在正負5mV,目前還沒有萬分之一精度即5V正負0.01%的基準,我想使用DAC8760的超量程10%功能,手冊上找不到10%超量
    發(fā)表于 12-02 07:53

    FP7128 LED降壓調節(jié)器 精細恒流輸出 PWM數(shù)位調光 萬分之一的調光深度

    降壓調節(jié)器
    jf_15550837
    發(fā)布于 :2024年11月08日 15:20:12

    APS54083,輸出10A大電流,帶65536無頻閃調光,調光深度可達萬分之一

    APS54083 采用外部供電,需要提供約 680uA的電流才能保證芯片的正常工作,外部供電壓電阻可以根據(jù)這個電流參數(shù)設計,同時注意選擇合適的電阻封裝適應不同輸入電壓情況。 ◆過溫保護
    的頭像 發(fā)表于 11-06 09:56 ?787次閱讀

    谷歌:超四分之一新代碼由人工智能生成

    10月30日最新消息顯示,谷歌正積極投身于系列人工智能產(chǎn)品的開發(fā)中,并且在其構建過程中,人工智能也扮演著舉足輕重的角色。谷歌首席執(zhí)行官桑達爾?皮查伊在公司2024年第三季度財報電話會議上透露:“我們超過四分之一的新代碼現(xiàn)由人工智能自動生成,隨后經(jīng)過工程師的審核與接納?!?/div>
    的頭像 發(fā)表于 10-30 15:13 ?1032次閱讀