線上程式設計競賽期間,線上判題系統為什麼會崩潰?
我們都知道,如今各種編碼平臺都包含了競技程式設計,例如 GeeksforGeeks、CodeChef、Codeforces、atCoder、SPOJ、HackerRank、HackerEarth 等等,在這些平臺上,使用者需要自己編寫程式碼,可以透過連線本地編輯器檔案(例如 Sublime 編輯器)或直接在平臺提供的編輯器中編寫。
那麼,這些測試用例是如何被訪問的呢?或者換句話說,我們的程式碼是如何被編譯和執行的呢?在這些用於競技程式設計的平臺上,線上判題系統充當了程式碼編譯和執行的核心。
線上判題系統
線上判題系統用於判斷使用者提交的程式碼,這些程式碼將在一個同質的環境中進行編譯和測試。線上判題系統被分類為各種不同的系統,這些系統支援建立競技程式設計競賽、增強教育和招聘流程、促進資料探勘挑戰的解決,以及作為其他自定義系統元件的線上編譯器和開發平臺。因此,它將被實現為一個高效的系統,幫助學生學習資料結構和程式設計技能。該系統包括使用者介面、沙盒判題環境、用於評估分數和將報告更新到資料庫的功能。本文將討論線上判題系統在程式設計競賽期間是如何崩潰的。下圖將幫助我們更好地解釋其崩潰的原因。
時間限制完成 - 程式碼應在一定時間內執行完成。我們能否在預設情況下設定作業系統執行執行緒的時間限制?
記憶體限制完成 - 程式不應該佔用 CPU 上的所有記憶體。我們如何以更簡單的方式更改這一點?
棧溢位錯誤 - 系統在跟蹤程式後,會了解程式是否成功執行。那麼,這些資訊是如何傳遞給我們的?
以上所有要點都解釋了系統檢查和執行程式的問題。使用者被允許在程式中提交任何程式碼。我們如何確定提交的程式碼是否具有惡意性,或者其惡意程度如何?
一些程式碼可以執行不同的程序,或者它們可以調查您的文件目錄,獲取少量資訊,或者可以執行管理命令,或者可以吞噬伺服器的頻寬,程式碼還可以執行各種操作。我們不需要允許系統執行這些操作。所以問題是,我們如何將這些許可權準則付諸實施?為了處理上述場景,我們將解釋以下方法:
方法
用於應用系統許可權和硬體的技術稱為程式碼沙箱。有兩種程式碼沙箱方法,網路決定透過這些方法來處理上述不同的場景。
糟糕的方法
冗長的歷史方法
方法 1:糟糕的方法
有一些可見的線上決策計劃,開發人員試圖在執行程式碼之前發現程式碼中的惡意功能。例如,如果我們的程式碼是用 C++ 編寫的,則決策將首先檢視是否存在任何使用“system”短語的程式碼行。這種方法不會出於各種原因而有效,因為許多程式語言的工作方式並不相同。您可以動態地生成一個函式並在某些程式語言中呼叫它,因此過濾在這些程式碼中將不起作用。還有一點,如果您想列印“system”作為輸出怎麼辦?這種方法會認為程式碼是惡意的,但實際上並非如此。
方法 2:冗長的歷史方法
在這種方法中,網路決定了大多數工作。並且此方法主要與基於 Linux 的系統相關。可以透過程式的返回值檢查棧溢位/執行時錯誤。如果返回值為 0,則可以認為系統能夠成功執行,否則表示崩潰。
透過使用各種基於 Unix 的完整庫,可以提供記憶體限制問題和時間限制。一些程式語言預設支援這種限制標誌功能,例如 Java。可以使用各種基於 Unix 的庫提供時間限制和記憶體限制。一些程式語言預設支援此類邊界標誌,例如 Java。
在 Linux 上,目錄許可權很簡單。我們可以簡單地建立一個使用者,並允許該使用者訪問某些目錄以及一些讀/寫許可權。然後透過使用該使用者執行應用程式,可以解決文件列表問題。此外,程式碼無法執行某些管理命令。
使用一些庫(例如 Trickle)也可以限制網路功能。為了簡單地解決一個安全漏洞,我們可以設定不同的庫並編寫不同的程式碼。
結論
如果我們使用 Docker 或基於 VM(虛擬機器)的容器,則可以解決以上所有問題。如果我們想要預設記憶體、預設網路許可權、容器的時間限制,可以建立一個容器。透過使用虛擬機器,所有這些問題都可以被忽略。開發人員可能知道一些替代方案。在這種解決方案中,整個判題系統可能看起來比其他方法慢,但從大規模來看,它實際上更快,並且比其他任何解決方案都更安全、更乾淨。您可以檢視此 GitHub 儲存庫以瞭解如何使用 docker 進行判題。
整個判題過程是線上判題系統最重要的組成部分之一。要實現一個判題系統,需要了解作業系統的工作原理,或者程式語言的工作原理。