Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughIntroduces a new Config dataclass and example JSON; refactors the patch flow to load configuration and build Template-based commands; run_system now accepts a Template; PEData.find_sect raises on missing sections; main forwards argv[1:]; CI/workflow and docs updated for the config-driven flow. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Main as "main.py"
participant Config as "patcher/Config.py"
participant Patcher as "patcher/Patcher.py"
participant FS as "Filesystem"
participant Tool as "Compiler/Linker"
rect rgba(200,200,255,0.5)
User->>Main: run script with config path
Main->>Patcher: call patch(config_path)
end
rect rgba(200,255,200,0.5)
Patcher->>Config: Config.load_from_json(path)
Config-->>Patcher: Config(instance with paths, flags, functions)
end
rect rgba(255,230,200,0.5)
Patcher->>FS: read input binary, hooks, headers
Patcher->>FS: write build artifacts (section.ld, patch.pe, defines)
FS-->>Patcher: artifact paths
end
rect rgba(255,200,200,0.5)
Patcher->>Tool: run_system(template) — compile/link via Template
Tool-->>Patcher: exit status, outputs
end
rect rgba(230,255,255,0.5)
Patcher->>FS: write final output to config.output_path
Patcher-->>User: completion / errors
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 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: 3
🤖 Fix all issues with AI agents
In `@patcher/Config.py`:
- Around line 24-33: In load_from_json (the Config classmethod) resolve the
incoming Path before using it to derive defaults so relative config paths won't
produce a relative target_folder_path that fails __post_init__; i.e.,
convert/resolve the path to an absolute Path at the start of load_from_json,
then open that resolved path and use resolved_path.parent as the default for
target_folder_path while keeping the rest of the keys the same.
In `@patcher/Patcher.py`:
- Around line 331-335: The shell command passed to run_system is building an
unquoted string using config.clang_path, the joined config.clang_flags,
include_folder_path, section_folder_path / "main.cxx", and build_folder_path /
"clangfile.o" which will break on paths containing spaces; update the run_system
invocations (the one shown and the other occurrences noted around the file) to
safely quote or shell-escape each path and each flag before joining (e.g., wrap
config.clang_path, each element from config.clang_flags, include_folder_path,
the section_folder_path/"main.cxx" token, and the
build_folder_path/"clangfile.o" token in quotes or use a function to
shell-escape them) so the command string passed to run_system treats each
path/flag as a single argument.
- Around line 467-468: The format spec in the exception message uses a stray
space in the hex formatter; replace the format expression f"0x{exxt_sect.f_size:
x}" with a proper hex specifier (e.g. f"0x{exxt_sect.f_size:x}") in the raise
Exception call so the output reads like 0x80000 (reference: exxt_sect.f_size in
the raise Exception block).
🧹 Nitpick comments (2)
patcher/Config.py (1)
18-20: Flag type hints don’t match JSON shape.
tuple[str]is a fixed‑length 1‑tuple, while JSON loads lists. Considertuple[str, ...]orSequence[str], and normalize to tuples in__post_init__.♻️ Proposed refactor
-from typing import Self +from typing import Self, Sequence ... - clang_flags: tuple[str] = () - gcc_flags: tuple[str] = () - asm_flags: tuple[str] = () + clang_flags: Sequence[str] = () + gcc_flags: Sequence[str] = () + asm_flags: Sequence[str] = () ... def __post_init__(self): self.target_folder_path = Path(self.target_folder_path) self.build_folder_path = Path(self.build_folder_path)\ if self.build_folder_path \ else self.target_folder_path / "build" self.clang_path = Path(self.clang_path) self.gcc_path = Path(self.gcc_path) self.linker_path = Path(self.linker_path) + + self.clang_flags = tuple(self.clang_flags) + self.gcc_flags = tuple(self.gcc_flags) + self.asm_flags = tuple(self.asm_flags)Also applies to: 42-50
patcher/PEData.py (1)
75-79: Alignfind_sect's contract with its new behavior.The return type
Optional[PESect]is misleading—the method always raisesExceptionand never returnsNone. Call sites inPatcher.py(lines 450, 456) don't check forNoneand directly use the result, relying on exception handling.Consider a dedicated exception (e.g.,
SectionNotFoundError) and a non-optional return type (PESect) to clarify the actual contract.♻️ Proposed refactor
+class SectionNotFoundError(LookupError): + pass + ... -def find_sect(self, name: str) -> Optional[PESect]: +def find_sect(self, name: str) -> PESect: for sect in self.sects: if sect.name == name: return sect - raise Exception(f"Couldn't find section {name}") + raise SectionNotFoundError(f"Couldn't find section {name}")
|
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@patcher/Config.py`:
- Around line 52-62: The build_folder_path value is converted to a Path but not
resolved to an absolute path like target_folder_path, causing the is_absolute()
check to fail for relative inputs; update the Config initialization so after
converting self.build_folder_path to a Path, if it is not absolute then join it
with self.target_folder_path (e.g., self.target_folder_path /
self.build_folder_path) and resolve it to an absolute Path before running the
existing validation; reference the build_folder_path and target_folder_path
attributes in Config to locate where to perform this normalization.
In `@patcher/Patcher.py`:
- Around line 290-306: The run_system function currently only quotes Path values
with spaces and concatenates parts unsafely, so replace the ad-hoc quoting with
proper shell escaping: import shlex and, inside run_system (function name) when
iterating template parts (loop over part and using part.value), call
shlex.quote(str(value)) for non-string parts instead of the current Path/space
check or manual f"\"{value}\"" quoting; also build the final command by joining
the command list with a space (e.g., " ".join(command)) and keep the existing
newline replacement before calling os.system(command.replace("\n", " ")).
- Line 12: The README's Versions section is out of date: the code imports
string.templatelib (which requires Python 3.14/PEP 750), so update the README
Versions entry that currently says "python: 3.12.4" to "python: 3.14" to match
the CI and the import usage; search for the README Versions block and replace
the Python version string accordingly so documentation aligns with the use of
string.templatelib in Patcher.py.
🧹 Nitpick comments (4)
main.py (1)
7-7: Argument unpacking mismatch withpatch()signature.
patch()expects a singleconfig_pathargument, but*sys.argv[1:]unpacks all CLI arguments. If the user provides zero or more than one argument, this raises aTypeErrorwith a confusing message. Consider passing the argument directly and validating input.♻️ Suggested improvement
if __name__ == "__main__": + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} <config_path>") + sys.exit(1) start = time.time() - patcher.patch(*sys.argv[1:]) + patcher.patch(sys.argv[1]) end = time.time() print(f"Patched in {end-start:.2f}s")config_example.json (1)
45-57: Inconsistent hex address formatting.Some addresses have leading zeros (
"0x00A89950","0x00A848E8") while others don't ("0xA8211E"). This inconsistency doesn't affect functionality but could indicate copy-paste errors. Consider normalizing the format.♻️ Suggested normalization
- "__CxxThrowException@8": "0x00A89950", + "__CxxThrowException@8": "0xA89950", "_memset": "0xA89110", - "__invoke_watson": "0x00A848E8" + "__invoke_watson": "0xA848E8"patcher/Config.py (1)
19-21: Type annotations don't match actual values from JSON.The annotations specify
tuple[str]butjson.load()returns lists, and there's no conversion. This works at runtime but may confuse type checkers.♻️ Consider using `list[str]` or converting to tuples
Either change the type hints:
- clang_flags: tuple[str] = () - gcc_flags: tuple[str] = () - asm_flags: tuple[str] = () + clang_flags: list[str] = field(default_factory=list) + gcc_flags: list[str] = field(default_factory=list) + asm_flags: list[str] = field(default_factory=list)Or convert in
load_from_json:- clang_flags=config.get("clang_flags", Config.clang_flags), + clang_flags=tuple(config.get("clang_flags", Config.clang_flags)),patcher/Patcher.py (1)
352-355: Unusual indentation onraisestatements.The
raise Exception(...)statements are indented more deeply than the surrounding code. While syntactically valid, this harms readability and looks like a formatting error.♻️ Consistent indentation
if run_system( t""" cd {build_folder_path} & {config.gcc_path} {" ".join(config.gcc_flags)} -I {include_folder_path} -Wl,-T,section.ld,--image-base,{image_base},-s,-Map,sectmap.txt,-o,section.pe {section_folder_path / "main.cpp"}"""): - raise Exception("Errors occurred during building of patch files") + raise Exception("Errors occurred during building of patch files")Apply similar fix to lines 384 and 444.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @.github/workflows/test.yml:
- Around line 71-72: The workflow fails because the repo is checked out to the
workspace root but the job later runs the command sequence "mkdir
FA-Binary-Patches/build" followed by "cd fa-python-binary-patcher & python
main.py config_example.json" which expects a fa-python-binary-patcher directory;
fix by either updating the checkout step to set path: fa-python-binary-patcher
so that "cd fa-python-binary-patcher" will succeed, or remove the "cd
fa-python-binary-patcher" and run "python main.py config_example.json" from the
workspace root after "mkdir FA-Binary-Patches/build" so the commands run in the
correct location.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@patcher/Patcher.py`:
- Around line 312-314: The command interpolation is joining flag lists into a
single string which becomes one quoted argument; update run_system to detect
list/tuple values and shlex.quote each element individually (joining them with
spaces) so flags are passed as separate arguments, then change the call sites
that currently do " ".join(config.clang_flags) (and other flag joins used around
the build commands in Patcher.py — e.g., the occurrences near the current uses
of config.clang_flags at the compile lines and the other flag interpolations
referenced) to pass the raw list/tuple (config.clang_flags, etc.) instead of a
pre-joined string so run_system can handle proper quoting per-element.
🧹 Nitpick comments (3)
patcher/Patcher.py (3)
6-6: Unusedjsonimport.The
jsonmodule is imported but not used in this file. The JSON loading appears to be handled withinConfig.load_from_json.🧹 Suggested fix
-import json
275-276: Add type hint forconfig_pathparameter.The function signature lacks a type annotation. Since it's passed to
Path(), adding a type hint improves clarity and enables better static analysis.✨ Suggested fix
-def patch(config_path): +def patch(config_path: str | Path):
318-321: Excessive whitespace in command template.The multi-line template string preserves indentation spaces, resulting in commands like
gcc -c -I ...in logs. While not functionally broken, it makes debugging harder.✨ Suggested fix - use line continuation or dedicated formatting
if run_system( - t""" cd {build_folder_path} & - {config.gcc_path} {" ".join(config.gcc_flags)} -I {include_folder_path} -Wl,-T,section.ld,--image-base,{image_base},-s,-Map,sectmap.txt,-o,section.pe {section_folder_path / "main.cpp"}"""): + t"""cd {build_folder_path} & {config.gcc_path} {config.gcc_flags} -I {include_folder_path} -Wl,-T,section.ld,--image-base,{image_base},-s,-Map,sectmap.txt,-o,section.pe {section_folder_path / "main.cpp"}"""): raise Exception("Errors occurred during building of patch files")
|
Can we remove this code rabbit thing completely? It is annoying and doesn't provide any useful tips... |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@patcher/Patcher.py`:
- Around line 258-273: In run_system, non-Path interpolated template parts
(variable value from `part.value`) may be integers and are appended directly to
`command`, causing `"".join(command)` to raise a TypeError; convert any
non-Path, non-str values to strings before appending. Locate the loop over
`template` in `run_system` (inspect `part`, `value`, and `command`) and ensure
branches: if `isinstance(value, Path)` use shlex.quote(str(value)); elif
`isinstance(value, str)` append as-is; else append `str(value)` so all entries
in `command` are strings before joining.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@patcher/Patcher.py`:
- Around line 322-325: The shell command passed to run_system in Patcher.py uses
the single-ampersand operator which runs the next command unconditionally;
update the command strings used in the run_system calls (the multi-line t"""...
cd {build_folder_path} & {config.gcc_path} ...""" occurrences tied to the build
steps) to use '&&' instead of '&' so that cd failure prevents running the
compiler/linker; apply the same replacement for the other two occurrences of the
same pattern found later in the file (the other run_system invocations around
the build steps).
🧹 Nitpick comments (1)
SETUP.md (1)
4-4: Use descriptive link text instead of "here".Static analysis (MD059) flags the link text "here" as non-descriptive. Screen readers and scanners benefit from self-explanatory anchor text.
Suggested fix
-Install newest version [here](https://www.python.org/downloads/) (At least 3.14). +Install the newest version from the [Python downloads page](https://www.python.org/downloads/) (at least 3.14).
| if run_system( | ||
| f"""cd {build_folder_path} & | ||
| {gcc_compiler_path} {GCC_FLAGS} | ||
| -I ../include/ {includes} | ||
| -Wl,-T,../section.ld,--image-base,{base_pe.imgbase + new_v_offset - 0x1000},-s,-Map,sectmap.txt,-o,section.pe | ||
| ../section/main.cpp"""): | ||
| raise Exception("Errors occurred during building of patch files") | ||
| t""" cd {build_folder_path} & | ||
| {config.gcc_path} {" ".join(config.gcc_flags)} -I {include_folder_path} -Wl,-T,section.ld,--image-base,{image_base},-s,-Map,sectmap.txt,-o,section.pe {section_folder_path / "main.cpp"}"""): | ||
| raise Exception("Errors occurred during building of patch files") |
There was a problem hiding this comment.
Use && instead of & to fail fast if cd fails.
Windows cmd.exe & runs the next command unconditionally. If cd {build_folder_path} fails (directory missing or mistyped), the gcc/linker commands execute in the wrong directory, producing misleading errors about missing files. The same pattern appears at lines 352 and 412.
Suggested fix (apply to all three occurrences)
- t""" cd {build_folder_path} &
+ t""" cd {build_folder_path} &&🧰 Tools
🪛 Ruff (0.14.14)
[warning] 325-325: Create your own exception
(TRY002)
[warning] 325-325: Avoid specifying long messages outside the exception class
(TRY003)
🤖 Prompt for AI Agents
In `@patcher/Patcher.py` around lines 322 - 325, The shell command passed to
run_system in Patcher.py uses the single-ampersand operator which runs the next
command unconditionally; update the command strings used in the run_system calls
(the multi-line t"""... cd {build_folder_path} & {config.gcc_path} ..."""
occurrences tied to the build steps) to use '&&' instead of '&' so that cd
failure prevents running the compiler/linker; apply the same replacement for the
other two occurrences of the same pattern found later in the file (the other
run_system invocations around the build steps).
Summary by CodeRabbit
New Features
Refactor
Bug Fixes
Chores