安全的腳本開發是多數引擎類語言所追求的目標,像java就試圖消滅了指針和崩潰的問題,但沒有成功。
說道腳本的安全無外乎兩大部分,內存指針的使用安全和數據安全,
指針和內存的使用是c語言的一大優勢,傳遞指針其實是數據集中管理的編程理念的體現。
假設一個指針被創建後永遠不會被刪除,
那麼程序內的所有函數都在這塊內存內操作數據並傳遞數據,
假設非常理想的情況下,這樣的數據管理的效率將是最高的。
任何數據都不會存在複製傳遞的開銷,
也不會有多個數據copy的一致性問題。
以java爲例消滅指針之後也並沒有什麼不便利的地方,因爲java本來就不是針對大數據流優化的語言,
對於new出來的對象在沒有使用之後自動釋放即可。
但引擎類的腳本就不能如此的簡單,因爲腳本不能預判要釋放的對象,
所以要對數據做統一的管理和限制。
那麼不得不說即便消滅了指針java也不是安全的語言因爲經常會出現數據越界的情況,
例如api參數規定是1到5,輸入6就會不知道該如何處理而程序崩潰。
這類問題也多半是可以處理但要看開發成本,每個變量邏輯數值的邊界是更具體邏輯息息相關,
質量控制能到這樣的地步是很不容易的事情。還有些狀況是無法處理的例如輸入asic字符串卻
錯誤的輸入了uft8的編碼,這樣造成的亂碼和api的崩潰是通過代碼檢查是很難做到的,只能在
邏輯結構上加以預防。
總的來說腳本的安全指針只是原因之一,數據越界,數值錯誤這類問題是引擎無法解決的,
或者解決起來成本遠遠大於普通的開發成本。
對於腳本來說還有一大天敵就是異步接口,所謂異步接口就是被調用的接口功能的完成在另一個
線程,導致當前線程所使用的數據出現嚴重的邏輯錯誤。
假設有一個join函數功能是加入某個家族,這個函數是一個異步函數,也就是函數調用之後就會立即返回,
真正的加入功能是在另一個線程內完成的。
void fun()
{
...
join();
...
}
考慮上面的代碼段,在fun函數內是不知道join是否成功的,因爲join是異步函數。
通常會使用回調函數的方式或者事件等通知的方式告知是否加入成功。
如果存在另一個函數判斷是否在家族內isin()就保不齊會設計出這樣的代碼
void fun()
{
while(isin())
{
join();
}
}
循環判斷是否在家族內,如不在就調用加入函數直到成功....
這種異步數據的邏輯錯誤也是引擎無能爲力的,
會空載大量的引擎資源而且不仔細檢查代碼還很難發現。
雖然可以對join加上報警或者日誌,
如果調用錯誤過多,像上述代碼就會有大量加入已經加入的家族導致加入失敗的錯誤。
如果只是單純的set數值就會產生大量重複的set。
上述錯誤是在腳本調用異步函數的數據問題,
做爲異步調用本身也存在的極大的風險,
雖然事件或者通知的概念很誘人,但事件本身就把邏輯程序拆分的支離破碎。
例如一段程序加入家族並且發送禮包異步函數
void fun()
{
join()
}
void eventjoin()
{
givebox()
}
顯然沒有
void fun()
{
if(join())
{
givebox()
}
}
來的簡潔流暢。
這時會想到linux下的fork()語句,奇葩的運行在兩個進程空間但邏輯可讀並且看起來連續。
多線程引擎的存在就是力圖解決在腳本中這種異步函數調用所引起的邏輯問題,
雖然現在看起來還沒有什麼更好的辦法。