Stopped infinite "Handling DRM" bug#1575
Conversation
📝 WalkthroughWalkthroughThis PR refactors process output capture to use background drainer threads in ProcessHelper, updates Wine command invocation in XServerScreen to chain wineserver restart, and removes debug temperature logging from the PerformanceHudView. ChangesCore utilities and UI maintenance updates
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt`:
- Line 4145: The generated command concatenates relDllPath unquoted into genCmd
in XServerScreen.kt causing breakage when the DLL path contains spaces or
metacharacters; change the construction of genCmd (the variable using "wine cmd
/c ... generate_interfaces_file.exe A:\\...") to wrap the A:\... argument in
properly escaped quotes and escape any embedded quotes in relDllPath (e.g.,
replace " with \") so the cmd /c payload receives a single quoted path token;
update the string building around genCmd (and any helper that constructs this
payload) to produce ...generate_interfaces_file.exe "A:\<escaped relDllPath>"...
so wineserver -k remains outside the inner quoted argument.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ee05d8df-88fb-4ed4-ae42-b07b1ec6726e
📒 Files selected for processing (3)
app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.ktapp/src/main/java/app/gamenative/ui/widget/PerformanceHudView.ktapp/src/main/java/com/winlator/core/ProcessHelper.java
💤 Files with no reviewable changes (1)
- app/src/main/java/app/gamenative/ui/widget/PerformanceHudView.kt
| val origDll = File("${imageFs.wineprefix}/dosdevices/a:/$relDllPath") | ||
| if (origDll.exists()) { | ||
| val genCmd = "wine z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') | ||
| val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\"" |
There was a problem hiding this comment.
Quote and escape the DLL path inside the cmd /c payload.
At Line 4145, relDllPath is concatenated unquoted into wine cmd /c "...". If the path contains spaces (or cmd metacharacters), generate_interfaces_file.exe parsing breaks and may execute unintended fragments. Wrap the A:\... argument in quotes and escape embedded quotes.
Suggested patch
- val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\""
+ val dllPathArg = relDllPath
+ .replace('/', '\\')
+ .replace("\"", "\\\"")
+ val genCmd =
+ "wine cmd /c \"z:\\generate_interfaces_file.exe \\\"A:\\$dllPathArg\\\" & wineserver -k\""📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\"" | |
| val dllPathArg = relDllPath | |
| .replace('/', '\\') | |
| .replace("\"", "\\\"") | |
| val genCmd = | |
| "wine cmd /c \"z:\\generate_interfaces_file.exe \\\"A:\\$dllPathArg\\\" & wineserver -k\"" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt` at line
4145, The generated command concatenates relDllPath unquoted into genCmd in
XServerScreen.kt causing breakage when the DLL path contains spaces or
metacharacters; change the construction of genCmd (the variable using "wine cmd
/c ... generate_interfaces_file.exe A:\\...") to wrap the A:\... argument in
properly escaped quotes and escape any embedded quotes in relDllPath (e.g.,
replace " with \") so the cmd /c payload receives a single quoted path token;
update the string building around genCmd (and any helper that constructs this
payload) to produce ...generate_interfaces_file.exe "A:\<escaped relDllPath>"...
so wineserver -k remains outside the inner quoted argument.
There was a problem hiding this comment.
3 issues found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt">
<violation number="1" location="app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt:4145">
P2: The `relDllPath` is interpolated unquoted inside the `cmd /c "..."` payload. If the DLL path contains spaces or cmd metacharacters (e.g., `&`, `^`, `"`), the command will break or execute unintended fragments. Wrap the `A:\...` argument in escaped quotes and escape any embedded quotes in the path.</violation>
<violation number="2" location="app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt:4145">
P2: `&` runs commands sequentially in cmd — if `generate_interfaces_file.exe` hangs, `wineserver -k` never executes</violation>
</file>
<file name="app/src/main/java/com/winlator/core/ProcessHelper.java">
<violation number="1" location="app/src/main/java/com/winlator/core/ProcessHelper.java:253">
P1: Streams are closed before drainer threads finish, which can truncate captured output/logs.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| try { stdoutStream.close(); } catch (IOException ignored) {} | ||
| try { stderrStream.close(); } catch (IOException ignored) {} | ||
| stdoutDrainer.join(5_000); | ||
| stderrDrainer.join(5_000); |
There was a problem hiding this comment.
P1: Streams are closed before drainer threads finish, which can truncate captured output/logs.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/com/winlator/core/ProcessHelper.java, line 253:
<comment>Streams are closed before drainer threads finish, which can truncate captured output/logs.</comment>
<file context>
@@ -221,45 +224,43 @@ public static String execWithOutput(String command, String[] envp, File workingD
- // Process has already exited (we drained its stdout to EOF).
- // waitFor() reaps the OS process-table entry.
process.waitFor();
+ try { stdoutStream.close(); } catch (IOException ignored) {}
+ try { stderrStream.close(); } catch (IOException ignored) {}
+ stdoutDrainer.join(5_000);
</file context>
| try { stdoutStream.close(); } catch (IOException ignored) {} | |
| try { stderrStream.close(); } catch (IOException ignored) {} | |
| stdoutDrainer.join(5_000); | |
| stderrDrainer.join(5_000); | |
| stdoutDrainer.join(5_000); | |
| stderrDrainer.join(5_000); |
| val origDll = File("${imageFs.wineprefix}/dosdevices/a:/$relDllPath") | ||
| if (origDll.exists()) { | ||
| val genCmd = "wine z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') | ||
| val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\"" |
There was a problem hiding this comment.
P2: The relDllPath is interpolated unquoted inside the cmd /c "..." payload. If the DLL path contains spaces or cmd metacharacters (e.g., &, ^, "), the command will break or execute unintended fragments. Wrap the A:\... argument in escaped quotes and escape any embedded quotes in the path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt, line 4145:
<comment>The `relDllPath` is interpolated unquoted inside the `cmd /c "..."` payload. If the DLL path contains spaces or cmd metacharacters (e.g., `&`, `^`, `"`), the command will break or execute unintended fragments. Wrap the `A:\...` argument in escaped quotes and escape any embedded quotes in the path.</comment>
<file context>
@@ -4142,7 +4142,7 @@ private fun unpackExecutableFile(
val origDll = File("${imageFs.wineprefix}/dosdevices/a:/$relDllPath")
if (origDll.exists()) {
- val genCmd = "wine z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\')
+ val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\""
Timber.i("Running generate_interfaces_file $genCmd")
val genOutput = guestProgramLauncherComponent.execShellCommand(genCmd)
</file context>
| val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\"" | |
| val dllPathArg = relDllPath | |
| .replace('/', '\\') | |
| .replace("\"", "\\\"") | |
| val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe \\\"A:\\$dllPathArg\\\" & wineserver -k\"" |
| val origDll = File("${imageFs.wineprefix}/dosdevices/a:/$relDllPath") | ||
| if (origDll.exists()) { | ||
| val genCmd = "wine z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') | ||
| val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\"" |
There was a problem hiding this comment.
P2: & runs commands sequentially in cmd — if generate_interfaces_file.exe hangs, wineserver -k never executes
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt, line 4145:
<comment>`&` runs commands sequentially in cmd — if `generate_interfaces_file.exe` hangs, `wineserver -k` never executes</comment>
<file context>
@@ -4142,7 +4142,7 @@ private fun unpackExecutableFile(
val origDll = File("${imageFs.wineprefix}/dosdevices/a:/$relDllPath")
if (origDll.exists()) {
- val genCmd = "wine z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\')
+ val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\""
Timber.i("Running generate_interfaces_file $genCmd")
val genOutput = guestProgramLauncherComponent.execShellCommand(genCmd)
</file context>
Description
Sometimes we were getting stuck on Handling DRM. This fixes it by draining the logs.
Recording
Type of Change
Checklist
#code-changes, I have discussed this change there and it has been green-lighted. If I do not have access, I have still provided clear context in this PR. If I skip both, I accept that this change may face delays in review, may not be reviewed at all, or may be closed.CONTRIBUTING.md.Summary by cubic
Fixes an infinite "Handling DRM" hang by draining process output and shutting down Wine cleanly after interface generation. Also reduces log noise to avoid buffer buildup.
ProcessHelper.execWithOutput, then join drainer threads; append stderr only when requested.generate_interfaces_file.exeviawine cmd /cand addwineserver -kto terminate the server after execution inXServerScreen.PerformanceHudViewto lower log volume.Written for commit 832fbd0. Summary will update on new commits.
Summary by CodeRabbit
Bug Fixes
Performance Improvements
Refactor