遊戲年代 GOAL GOAL

 找回密碼
 立即註冊
搜索
查看: 60|回復: 3

[PC版模擬器] [DC模擬器] Flycast 2.6 繁、簡、英文版(測試版)

[複製鏈接]

14

主題

112

帖子

3096

積分

銀牌會員

Rank: 5Rank: 5

積分
3096
發表於 昨天 20:09 | 顯示全部樓層 |閱讀模式
Flycast 2.6 繁、簡、英文版(測試版)

這個檔案是從 github 下載原始碼編譯而成的,翻譯差不多都已經完成了,
也有修正一些安全性漏洞,以及一些最佳化。
有加了一點功能。後續再一起列出來。

有興趣的可以先玩玩,這是測試版,有問題可以反應上來,謝謝。

下載:
https://u.pcloud.link/publink/sh ... x4npJ82J0PqnRfplJTX



01.png

評分

參與人數 1威望 +1 金錢 +30 貢獻 +1 收起 理由
ili789 + 1 + 30 + 1 感謝分享

查看全部評分

回復

使用道具 舉報

14

主題

112

帖子

3096

積分

銀牌會員

Rank: 5Rank: 5

積分
3096
 樓主| 發表於 昨天 20:42 | 顯示全部樓層
本帖最後由 good7 於 2026-7-24 20:54 編輯

================================================================================
                Flycast 專案最佳化、安全性漏洞及其它記錄
================================================================================
整理日期:2026-07-24
工作目錄:Z:\f
================================================================================


================================================================================
一、Critical 級安全漏洞修復(7 項)
================================================================================

[C-01] CHD sscanf 堆疊緩衝區溢位
  檔案:core/imgread/chd.cpp:198,203,218
  修改:三處 sscanf 的格式字串中 %s → %15s,限制寫入寬度
  行數:309 → 312 (+3)
  說明:type[16] 等四個 16 byte 緩衝區不再被超長元資料溢位

[C-02] ISO9660 目錄記錄越界讀取
  檔案:core/imgread/isofs.cpp:76
  修改:if (index >= data.size()) → if (index + 34 > data.size())
  行數:156 → 156 (0)
  說明:確保剩餘空間足夠容納完整的目錄記錄結構(至少 34 byte)

[C-03] RetroArch 存檔 MEM 區段大小未驗證
  檔案:core/serialize.cpp:117-122
  修改:加入 if (sectionSize > limit) throw Exception(...)
  行數:157 → 158 (+1)
  說明:MEM 區段的 sectionSize 現在會與剩餘資料長度比較

[C-05] JIT 代碼緩衝區 RWX(W^X 違規)
  檔案:core/windows/win_vmem.cpp:188
  修改:mem_alloc 初始分配 PAGE_EXECUTE_READWRITE → PAGE_READWRITE
  行數:282 → 282 (0)
  說明:初始分配改為 RW,編譯完成後 jit_set_exec(true) 切為 RX

[C-06] jit_set_exec 為空操作
  檔案:core/windows/win_vmem.cpp:254-256
  修改:實作 VirtualProtect 切換 PAGE_READWRITE / PAGE_EXECUTE_READ
  行數:277 → 282 (+5)
  說明:JIT 代碼區現在能在寫入時設為 RW、執行時設為 RX

[C-08] Lua 無沙箱 — 任意程式碼執行
  檔案:core/lua/lua.cpp:622-623
  修改:luaL_openlibs(L) 替換為白名單載入(base/table/string/math/utf8)
  行數:652 → 663 (+11)
  說明:移除 os/io/package/debug 函式庫,消除任意命令執行能力

[C-10] getSubPath 路徑遍歷漏洞
  檔案:core/oslib/storage.cpp:151-155
  修改:加入 .. 和絕對路徑檢查,不合法時 throw StorageException
  行數:353 → 355 (+2)
  說明:所有 36+ 處呼叫端現在都受到路徑遍歷保護


================================================================================
二、High 級安全漏洞修復(20 項)
================================================================================

[H-01] CDI fread 回傳值未檢查
  檔案:core/deps/chdpsr/cdipsr.cpp:47-103
  修改:CDI_read_track 中 13 處 fread 全部加入 != 1 return false 檢查
  行數:161 → 161 (0)

[H-02] GDI 軌道計數無上限 → OOM DoS
  檔案:core/imgread/gdi.cpp:34
  修改:iso_tc == 0 → iso_tc == 0 || iso_tc > 100

[H-03] GDI EndFAD 整數下溢
  檔案:core/imgread/gdi.cpp:99-100
  修改:加入 OFFSET 範圍檢查(< 0 或 > fileInfo.size 時 throw)
  行數:125 → 129 (+4)

[H-04] CDI fseek 偏移量整數溢位
  檔案:core/imgread/cdi.cpp:183
  修改:track.total_length * track.sector_size → (long long)... * ...
  行數:212 → 212 (0)

[H-05] CHD 數值欄位無範圍驗證
  檔案:core/imgread/chd.cpp:222
  修改:加入 frames/padframes/pregap/postgap 範圍檢查

[H-06] DNS 回應解析無邊界 strlen
  檔案:core/network/dns.cpp:130-137
  修改:加入最小長度檢查;strlen → strnlen;加 reader > end 檢查
  行數:207 → 211 (+4)

[H-07] DHCP 選項越界讀取
  檔案:core/network/dcnet.cpp:709
  修改:while 條件 options - frame < len → options - frame + 2 < len
  行數:793 → 793 (0)

[H-08] GGPO VF4Card 缺少長度驗證
  檔案:core/network/ggpo.cpp:468
  修改:加入 len >= sizeof(type) + sizeof(card) 檢查
  行數:947 → 948 (+1)

[H-09] registerHandler 使用 assert(Release 被移除)
  檔案:core/hw/mem/addrspace.cpp:236
  修改:assert(rv < HANDLER_COUNT) → verify(rv < HANDLER_COUNT)
  行數:556 → 558 (+2)

[H-10] 處理器 ID 索引無邊界檢查
  檔案:core/hw/mem/addrspace.cpp:123,168
  修改:readt/writet 中加入 verify(id < HANDLER_COUNT)

[H-11] init() 中分配無錯誤檢查
  檔案:core/windows/win_vmem.cpp:67,72
  修改:加入 verify(mem_handle != NULL) 和 verify(base_alloc != NULL)

[H-13] UAF 風險:Stale Block 與代碼快取重用
  檔案:core/hw/sh4/dyna/blockmanager.cpp:316
  修改:bm_ResetCache 中加入 del_blocks.clear()
  行數:604 → 605 (+1)

[H-14] cheats 計數無上限 → DoS/OOM
  檔案:core/cheats.cpp:401
  修改:加入 count 範圍檢查 (0-10000)
  行數:1136 → 1149 (+13)

[H-15] cheat.size 位元移位 UB
  檔案:core/cheats.cpp:417
  修改:1 << → 1u <<,限制 memSize 範圍 [0,5]

[H-16] apply() 位址遞增無邊界
  檔案:core/cheats.cpp:765,785
  修改:copy 迴圈加邊界條件;setValue 迴圈加 address >= RAM_SIZE break

[H-17] INI 格式注入
  檔案:core/cfg/ini.cpp:282-296
  修改:加入 sanitizeIniValue() 過濾 \n \r;save() 兩處 fprintf 套用
  行數:319 → 332 (+13)

[H-20] GDB stack 命令堆疊緩衝區溢位
  檔案:core/debug/gdb_server.cpp:587-605
  修改:固定/VLA 緩衝區改為 std::string 動態分配
  行數:989 → 984 (-5)

[H-22] ELF 載入器越界讀取 + 整數下溢
  檔案:core/reios/reios_elf.cpp:55-66
  修改:加入 offset+len <= filesize 和 memSize >= len 檢查
  行數:71 → 77 (+6)

[H-23] readdir 非執行緒安全
  檔案:core/oslib/directory.cpp:52
  修改:static dirent d → thread_local dirent d
  行數:122 → 122 (0)

[H-24] UDP AP 發現越界讀取
  檔案:core/network/dcnet.cpp:470
  修改:while 條件改為 p + 5 <= recvbuf + len

[H-25] GDB 繫結所有介面
  檔案:core/debug/gdb_server.cpp:140
  修改:tcp::v4() → address_v4::loopback()

[H-26] getArcadeFlashPath 路徑遍歷
  檔案:core/oslib/oslib.cpp:103
  修改:加入 fileName 淨化(拒絕 .. / \)
  行數:491 → 500 (+9)


================================================================================
三、Medium 級安全漏洞修復(8 項)
================================================================================

[M-12] GGPO Deserializer 限制不一致
  檔案:core/network/ggpo.cpp:448
  修改:1_MB → settings.platform.isNaomi() ? 20_MB : 10_MB

[M-13] CDI 負軌道長度僅警告
  檔案:core/imgread/cdi.cpp:166
  修改:track.length < 0 WARN → track.length <= 0 throw
  行數:212 → 212 (0)

[M-14b] repeatCount 無上限
  檔案:core/cheats.cpp:419
  修改:限制 repeatCount ≤ 65536

[M-15] INI get_int/64 strstr("0x") 邏輯缺陷
  檔案:core/cfg/ini.cpp:15-25, 27-33
  修改:strstr → 字首檢查 value[0]=='0' && value[1]=='x'/'X'

[M-16] option.h 路徑列表越界存取
  檔案:core/cfg/option.h:212,220
  修改:加入 if (start >= paths.size()) break 邊界檢查
  行數:553 → 557 (+4)

[M-24] saveScreenshot 路徑遍歷
  檔案:core/oslib/oslib.cpp:301
  修改:加入 name 淨化(拒絕 .. / \)

[M-25] descrambl 非執行緒安全全域狀態
  檔案:core/reios/descrambl.cpp:16,33
  修改:static → thread_local(seed 和 idx[])
  行數:76 → 76 (0)

[M-27] stdclass 路徑拼接無驗證
  檔案:core/stdclass.cpp:67-81,100-114
  修改:get_writable_config_path/data_path 加入 filename 淨化
  行數:257 → 273 (+16)

[M-29] HTTP 回應無大小限制
  檔案:core/oslib/http_client.cpp:62,233
  修改:加入 10MB 上限檢查(Windows + curl 兩處)
  行數:342 → 346 (+4)

[M-31] GDB unpack 無輸入驗證
  檔案:core/debug/gdb_server.cpp:38-46
  修改:加入嚴格 hex 字元範圍驗證,非 hex 回傳 0


================================================================================
四、系統級防護強化(CMAKE 級,3 項)
================================================================================

[CMAKE-01] Stack Canary 恢復
  檔案:CMakeLists.txt:102
  修改前:target_compile_options(${PROJECT_NAME} PRIVATE /GR /GS-)
  修改後:target_compile_options(${PROJECT_NAME} PRIVATE /GR /GS)
  說明:/GS- 明確關閉 stack canary,改為 /GS 恢復保護

[CMAKE-02] GCC Stack Protector 啟用
  檔案:CMakeLists.txt:106
  修改:加入 -fstack-protector-strong 編譯選項
  說明:GCC build 加入 stack protector,與 MSVC 的 /GS 對等

[CMAKE-03] 移除 _CRT_SECURE_NO_WARNINGS
  檔案:CMakeLists.txt:112
  修改:移除 $<$<BOOL{MSVC}>:_CRT_SECURE_NO_WARNINGS> 定義
  說明:恢復 MSVC 對不安全 CRT 函數的編譯警告


================================================================================
五、穩定性問題修復(7 項)
================================================================================

[#2] Renderer 例外導致死結
  目標:core\hw\pvr\Renderer_if.cpp:194-215
  問題:renderer->rocess/Render 拋出例外時,FinishRender 不執行 → rqueue 不清空
        → frame_finished 不 Set → 下一幀 QueueRender 永久阻塞 → 模擬器死結
  對策:用 try/catch 包裝 Process+Render+present 區段;catch 中執行
        renderEnd.Set() + rend_allow_rollback() 確保渲染狀態一致
  行數:548 → 553 (+5)

[#4] ctx_list 跨執行緒無鎖存取
  目標:core\hw\pvr\ta_ctx.cpp
  問題:ctx_list 在 Emu 執行緒與主執行緒之間無鎖存取,可能導致迭代器失效
  對策:新增 static std::recursive_mutex mtx_list;在 5 個存取點加入 lock_guard
  行數:297 → 305 (+8)

[#6] FrameCount 非原子跨執行緒讀寫
  目標:core\hw\pvr\Renderer_if.h:7, Renderer_if.cpp:22, ta_ctx.cpp:87, spg.cpp:184
  問題:FrameCount 為普通 u32,多執行緒讀寫 → C++ data race (UB)
  對策:將 u32 FrameCount 改為 std::atomic<u32> FrameCount
  行數:Renderer_if.h 120→121(+1)

[#9] TA FSM ListEndInterrupt 陣列越界
  目標:core\hw\pvr\ta.cpp:228-234
  問題:ListEndInterrupt[5] 僅 5 元素(索引 0-4),ListType 5-7 時越界讀取
  對策:在陣列存取前加邊界檢查
  行數:595 → 598 (+3)

[#11] GDROM SPI_SET_MODE 整數下溢導致堆積溢寫
  目標:core\hw\gdrom\gdromv3.cpp:826-827
  問題:u32 Offset = data_8[2](0-255);10 - Offset 在 Offset>10 時無號下溢
        為 0xFFFFFFFF → memcpy 溢寫堆積
  對策:在計算前加 Offset >= 10 的 early break
  行數:1471 → 1478 (+7)

[#12] GDROM SPI_REQ_MODE 緩衝區越界讀取
  目標:core\hw\gdrom\gdromv3.cpp:739
  問題:gd_spi_pio_end 中 offset 和 length 完全由遊戲控制,無邊界檢查
  對策:加 offset + length <= sizeof(GD_HardwareInfo) 的邊界檢查

[#21] dc_reset 軟重設與 unloadGame 可能並行
  目標:core\emulator.cpp:720-726
  問題:dc_reset(false) 不在 Emulator::mutex 內,可能與 unloadGame 並行修改
  對策:在 dc_reset 呼叫外包裹 std::lock_guard<std::mutex>
  行數:1139 → 1142 (+3)


================================================================================
六、效能最佳化(6 項)
================================================================================

【最佳化 1】ta_thd_data32_i() — TA 資料接收瓶頸
  目標:core/hw/pvr/ta.cpp:545-588
  方法:非時態寫入 + 預取 + 批次展開 + PCW 讀取合併
  行數:598 → 624 (+26)
  修改:
    1. 新增 simd256_t::stream_copy() 方法(非時態寫入)
    2. 新增 #include <emmintrin.h>(x86 SSE2 標頭)
    3. ta_thd_data32_i():使用 dst->stream_copy(data)、__builtin_prefetch、PCW 讀取合併
    4. ta_vtx_data():批次展開從 4 次增加到 8 次

【最佳化 2】ReadFramebuffer() — 像素格式轉換 SIMD 化
  目標:core/rend/TexCache.cpp:634-757
  方法:SSE2 SIMD 加速 fbde_0555 和 fbde_565 格式的像素轉換
  行數:1181 → 1258 (+77)
  修改:
    1. 新增 #include <emmintrin.h>、#include <type_traits>
    2. fbde_0555 格式 SIMD 路徑:每次處理 4 個 16 位元像素
    3. fbde_565 格式 SIMD 路徑:每次處理 4 個 16 位元像素
    4. 標量回退路徑:保留原始程式碼處理剩餘像素
    5. 條件編譯:#if HOST_CPU == CPU_X86

【最佳化 3】GLES Shader Uniform 迴圈 — 版本計數器延遲更新
  目標:core/rend/gles/gles.cpp:1185-1190
  方法:版本計數器機制,消除每幀 N 次 UseProgram + Set
  行數:gles.h 582→586(+4)、gles.cpp 1371→1366(-5)、gldraw.cpp 1067→1073(+6)
  修改:
    1. PipelineShader 新增 u32 uniformVersion = 0
    2. ShaderUniforms_t 新增 u32 version = 0
    3. renderFrame 中 6 行迴圈取代為 ShaderUniforms.version++
    4. SetGPState 中 UseProgram 後加延遲檢查

【最佳化 4】makeIndex / makePrimRestartIndex — reserve + is_vertex_inf 位元級最佳化
  目標:core/hw/pvr/ta_util.cpp:520, 438, 29
  方法:is_vertex_inf 位元級檢查 + idx 向量 reserve
  行數:ta_util.cpp 608 → 625 (+17)
  修改:
    1. is_vertex_inf:使用 float_bits() 輔助函式,6 浮點運算 → 2 整數 AND+比較
    2. makeIndex/makePrimRestartIndex:函式開頭加 reserve(size + totalVerts*2)

【最佳化 5】AppendPolyVertex — verts/idx 初始 reserve 提升
  目標:core/hw/pvr/ta_ctx.h:359-360
  行數:441 → 441 (0,常數值修改)
  修改:rend.verts.reserve(32768) → 65536、rend.idx.reserve(32768) → 65536
  理由:遊戲實測 vtx 最大 34,046、idx 最大 47,178,原始 32768 不足

【最佳化 6】Provoking Vertex 修正 — memcpy 合併
  目標:core/rend/sorter.cpp:23
  方法:將 4 次 4B memcpy 合併為 2 次 8B memcpy
  行數:80 → 76 (-4)
  修改:sizeof(vertex.col) + sizeof(vertex.spc) 合併複製


================================================================================
七、GLES u32→u16 索引轉換最佳化
================================================================================

[#6] GLES u32→u16 索引轉換 — resize + 自動向量化
  目標:core/rend/gles/gles.cpp:1090(upload_vertex_indices)
  行數:gles.cpp 1395 → 1397 (+2)
  修改:
    1. resize 替代 clear+reserve:單一呼叫設定大小
    2. 直接賦值替代 push_back:消除每元素容量檢查分支
    3. 緊密迴圈 + const 指標:GCC 13 可自動向量化(SSE2 pack 指令)


================================================================================
八、GLES/GL4 後端移植至新 core API
================================================================================

對策日期:2026-07-22
目標:core/rend/gles/ + core/rend/gl4/(整個 OpenGL/GLES 後端)

修改檔案(10 個):
  CMakeLists.txt:     USE_OPENGL 區塊加入 gles/gl4 原始碼 + 編譯定義 + opengl32
  11.bat:             USE_OPENGL=OFF → ON
  wsi/context.h:      加 virtual void swap() {}
  wsi/sdl.h:          swap() → swap() override
  gles/gles.h:        TransformMatrix → TransformMatrix<COORD_OPENGL>
  gles/gles.cpp:      FlycastException×3, GLGraphicsContext cast, 移除swapInterval
  gles/gldraw.cpp:    setTileClip用GetTileClip, Rect→int[4], writeFramebufferToVRAM重寫
  gles/gltex.cpp:     fbClip→fb_X/Y_CLIP, WriteTextureToVRam去除clip參數
  gl4/gldraw.cpp:     FlycastException, setTileClip新API, Rect→int[4]
  gl4/gles.cpp:       getBaseScissor新API

解決的 12 個不相容點:
  1.  TransformMatrix 模板化
  2.  Rect 型別消除(改用 int clip_rect[4])
  3.  getTileClip → GetTileClip 自由函式
  4.  getBaseScissor → GetScissorMatrix + fb_X/Y_CLIP 計算
  5.  GraphicsContext 版本方法
  6.  swap() → GraphicsContext 加虛擬方法
  7.  setSwapInterval → 移除
  8.  globClip → ta_GLOB_TILE_CLIP 計算
  9.  fbClip → fb_X_CLIP/fb_Y_CLIP
  10. swapInterval → 移除
  11. RendererException → FlycastException
  12. getWriteFBToVramParams/writeFramebufferToVRAM → 重寫


================================================================================
九、UploadToGPUGl4 immutable storage 尺寸/格式變化檢查缺失修復
================================================================================

目標:core/rend/gles/gltex.cpp:97-105
問題:UploadToGPUGl4 使用 glTexStorage2D 建立不可變紋理,但只在 texID == 0 時建立
      後續紋理更新時不檢查尺寸/格式/mipmapLevels 是否一致
修改:
  1. gles.h — TextureCacheData 加入 4 個 storage 追蹤成員變數
  2. gltex.cpp — UploadToGPUGl4 加入屬性變化檢查 + 刪舊建新邏輯
行數:gles.h 586→590(+4)、gltex.cpp 532→542(+10)


================================================================================
十一、未修復項目(需外部配合)
================================================================================

[M-08] 未加密 WebSocket (ice.cpp:234, ws:// → wss://)
  原因:需伺服器端(lobby.flyca.st)支援 wss://

[M-09] 硬編碼 TURN 憑證 (ice.cpp:436)
  原因:需伺服器端 REST API 發放短期憑證

[M-10] NaomiNetwork 競態條件 (naomi_network.h)
  原因:需架構調整(_startNow 改為 atomic)


================================================================================
記錄整理完成:2026-07-24
================================================================================

回復

使用道具 舉報

0

主題

4906

帖子

4408

積分

金牌會員

Rank: 6Rank: 6

積分
4408
發表於 昨天 23:36 | 顯示全部樓層
感謝大大的分享
回復

使用道具 舉報

7

主題

5518

帖子

5122

積分

金牌會員

Rank: 6Rank: 6

積分
5122
發表於 4 小時前 | 顯示全部樓層
感謝大大無私熱心提供的分享遊戲資訊
回復

使用道具 舉報

您需要登錄後才可以回帖 登錄 | 立即註冊

本版積分規則

Archiver|小黑屋|遊戲年代 GOAL GOAL

GMT+8, 2026-7-25 04:55 , Processed in 0.018788 second(s), 23 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回復 返回頂部 返回列表