摘要:典型的緩沖區(qū)越界注入等攻擊手段,或者網(wǎng)絡異常等。這假設實際上往往是錯誤的,絕大多數(shù)系統(tǒng)實際對用戶信息的要求不僅僅是滿足基本類型信息即可,而有顯式或隱式的其他條件。當然對于這種可能出現(xiàn)的異常應該在程序的其他地方捕獲并加以恰當?shù)恼故尽?/p>
不管你的水平多高,多么認真仔細,程序員總是會制造出 bug。bug 的根本來源是:
預期之外的用戶輸入或系統(tǒng)輸入。典型的緩沖區(qū)越界、SQL 注入等攻擊手段,或者網(wǎng)絡異常等。它的特點是在通常的用戶輸入時,程序表現(xiàn)得非常正常;但對于不普通、或者異常的用戶輸入沒有做任何防御。
程序員的疏忽或理解錯誤。例如不正確地調(diào)用了參數(shù),按照不正確地次序調(diào)用函數(shù),錯誤的線程數(shù)據(jù)共享。
開發(fā)組件之外的系統(tǒng)其他部分,如中間件、數(shù)據(jù)庫系統(tǒng)或其他組件本身的 bug,也會給我們本來完美的程序帶來 bug。但這種 bug 我們可以稱為是衍生錯誤,本質(zhì)是上述兩種 bug 之一。
所謂防御性編程(Defensive Programming) 一般針對第一類錯誤,它的原則是:只要有用戶或系統(tǒng)輸入,就應該對它的合規(guī)性進行嚴格的檢查。例如:
javapublic String findUserName(String userId) { return db.userNameFrom(db, userId); }
如果 nameInput 是直接來自于用戶輸入(不論是通過頁面,還是 URL,還是應用程序),上述簡單程序意味著:只要 userId 是一個字符串,它就是合法的!而我們就將它作為合法字符串在系統(tǒng)各處傳遞。這假設實際上往往是錯誤的,絕大多數(shù)系統(tǒng)實際對用戶信息的要求不僅僅是滿足基本類型信息即可,而有顯式或隱式的其他條件。例如,userId 很可能有長度限制,例如長于 6 個,短于20個字符;它很可能有取值限制,例如只能是字符和數(shù)字。而我們的編譯器,即使是 Java 的強類型編譯器,對這種要求一無所知。是程序員的責任來檢查這些額外要求:
java//一個特別的類 InputChecker 來檢查輸入 public void checkUserId(String userIdInput) { if (userIdInput.length < 6 || userIdInput.length > 20) throw new InvalidInputException("userId", userIdInput); } //需要和用戶輸入直接打交道的地方調(diào)用 inputChecker public String findUserName(String userId) { inputChecker.checkUserId(userId); return db.userNameFrom(db, userId); }
注意,由于異常輸入是一種異常,用運行時異常來表達它是合理的。當然對于這種可能出現(xiàn)的異常應該在程序的其他地方捕獲并加以恰當?shù)恼故尽?/p>
這樣的防御性編程代碼是可靠設計的一個良好習慣,實際上它也廣泛地被使用。但也有很多程序員將它錯誤地過多使用,或者錯誤地用它來覆蓋第二類 bug (程序員錯誤)。
javapublic ListtransferGameResult(GameRoom room, List gameResult) { if (null == gameResult || gameResult.size() == 0) { return null; ..... }
這段程序的目的是將一種游戲結果轉(zhuǎn)化為另一種表達式來方便計算。其中第一句語句的目的是?
看起來這似乎是防御性編程,想要檢查 gameResult 的輸入錯誤:如果 gameResult 不正確輸入,就返回空值。
但這里的 gameResult 是用戶輸入嗎?不可能是,它是一個 int[],只可能是來自于程序其他地方,也就是說來自于這段代碼的調(diào)用者,另一個程序員。
用正確的參數(shù)來調(diào)用是程序員的責任,我們不能假裝我們的程序可以正常處理 null 的參數(shù)或者長度為0 的輸入,實際上對此我們沒有處理能力。因此,這里真正防御性編程的處理是:
javapublic ListtransferGameResult(GameRoom room, List gameResult) { assert(gameResult != null && gameResult.size() > 0); ..... }
表明我們的這段程序?qū)斎雲(yún)?shù)的嚴格要求。有人可能會說,assert 不是不應該出現(xiàn)在運行時的系統(tǒng)中嗎?至少對于 Java 語言來說,assert 將立即拋出一個異常(如果你沒有停用 assert 的話),調(diào)用程序員如果對引用這段代碼的程序做了合理的測試,他會立即發(fā)現(xiàn)這個錯誤,就有了糾正它的機會。但按照之前的寫法,調(diào)用程序員則很可能不能看到任何問題,而使用不正確的參數(shù)調(diào)用,本身就是一個錯誤!這樣,我們成功地幫助程序員掩蓋了他的錯誤,增加了將 bug 帶到生產(chǎn)系統(tǒng)中的機會。
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/64292.html
摘要:網(wǎng)易跨境電商考拉海購在線筆試現(xiàn)場技術面面。如何看待校招面試招聘,對公司而言,是尋找勞動力對員工而言,是尋找未來的同事。 如何準備校招技術面試 標簽 : 面試 [TOC] 2017 年互聯(lián)網(wǎng)校招已近尾聲,作為一個非 CS 專業(yè)的應屆生,零 ACM 經(jīng)驗、零期刊論文發(fā)表,我通過自己的努力和準備,從找實習到校招一路運氣不錯,面試全部通過,謹以此文記錄我的校招感悟。 寫在前面 寫作動機 ...
摘要:單元測試過后,機器狀態(tài)保持不變。單元測試應該產(chǎn)生可重復一致的結果。然并卵都說國內(nèi)很多程序員是不寫單元測試的,甚至從來都不寫,筆者當年做的時候也沒寫過幾次捂臉。回歸測試在單元測試的基礎上,我們就能夠建立關于這一模塊的回歸測試。 showImg(https://segmentfault.com/img/bVPMPd?w=463&h=312); 送給初級程序員的測試認知文 作為開發(fā)同學,一些...
摘要:關于自己屆畢業(yè)生一本雙非學校,非科班可能和很多人一樣,因為小時候喜歡打游戲,所以大學一直想學編程,但因為種種原因,自己來到了一個硬件相關專業(yè),但由于現(xiàn)實和興趣,自己又從事了軟件相關的工作。找實習實習對于之后的秋招來說,是非常非常重要的。 ...
閱讀 1118·2021-10-09 09:43
閱讀 18475·2021-09-22 15:52
閱讀 1059·2019-08-30 15:44
閱讀 3050·2019-08-30 15:44
閱讀 3244·2019-08-26 14:07
閱讀 904·2019-08-26 13:55
閱讀 2566·2019-08-26 13:41
閱讀 3087·2019-08-26 13:29