Skip to content

Commit d4334c9

Browse files
Copilotunclesp1d3r
andauthored
fix: Address code review feedback for Mach-O load command extraction (#103)
* Initial plan * Apply code review fixes: error handling, integer overflow, formatting Co-authored-by: unclesp1d3r <251112+unclesp1d3r@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: unclesp1d3r <251112+unclesp1d3r@users.noreply.github.com>
1 parent 2cf74de commit d4334c9

4 files changed

Lines changed: 45 additions & 35 deletions

File tree

‎src/extraction/macho_load_commands.rs‎

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,31 @@
66
//!
77
//! # Examples
88
//!
9-
//! ```rust
9+
//! ```rust,no_run
10+
//! use std::error::Error;
1011
//! use stringy::extraction::macho_load_commands::extract_load_command_strings;
1112
//! use stringy::types::{Tag, StringSource};
1213
//!
13-
//! let macho_data = std::fs::read("example.dylib")?;
14-
//! let strings = extract_load_command_strings(&macho_data);
14+
//! fn main() -> Result<(), Box<dyn Error>> {
15+
//! let macho_data = std::fs::read("example.dylib")?;
16+
//! let strings = extract_load_command_strings(&macho_data);
1517
//!
16-
//! // Filter dylib paths
17-
//! let dylib_paths: Vec<_> = strings.iter()
18-
//! .filter(|s| s.tags.contains(&Tag::DylibPath))
19-
//! .collect();
18+
//! // Filter dylib paths
19+
//! let dylib_paths: Vec<_> = strings.iter()
20+
//! .filter(|s| s.tags.contains(&Tag::DylibPath))
21+
//! .collect();
2022
//!
21-
//! // Filter rpaths
22-
//! let rpaths: Vec<_> = strings.iter()
23-
//! .filter(|s| s.tags.contains(&Tag::Rpath))
24-
//! .collect();
23+
//! // Filter rpaths
24+
//! let rpaths: Vec<_> = strings.iter()
25+
//! .filter(|s| s.tags.contains(&Tag::Rpath))
26+
//! .collect();
2527
//!
26-
//! // Filter framework paths
27-
//! let framework_paths: Vec<_> = strings.iter()
28-
//! .filter(|s| s.tags.contains(&Tag::FrameworkPath))
29-
//! .collect();
28+
//! // Filter framework paths
29+
//! let framework_paths: Vec<_> = strings.iter()
30+
//! .filter(|s| s.tags.contains(&Tag::FrameworkPath))
31+
//! .collect();
32+
//! Ok(())
33+
//! }
3034
//! ```
3135
3236
use crate::types::{Encoding, FoundString, StringSource, Tag};
@@ -188,8 +192,12 @@ fn extract_architecture_data<'a>(
188192
let offset = arch.offset as usize;
189193
let size = arch.size as usize;
190194

191-
if offset + size <= data.len() {
192-
Ok(&data[offset..offset + size])
195+
if let Some(end) = offset.checked_add(size) {
196+
if end <= data.len() {
197+
Ok(&data[offset..end])
198+
} else {
199+
Err(())
200+
}
193201
} else {
194202
Err(())
195203
}

‎tests/fixtures/README.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ This directory contains pre-compiled binary test fixtures used for snapshot test
55
## Fixtures
66

77
- `test_binary_elf` - x86-64 ELF binary
8-
- `test_binary_macho` - ARM64 Mach-O binary (contains typical load commands including LC_LOAD_DYLIB for system library dependencies like libSystem.B.dylib, potentially LC_RPATH commands, and framework dependencies if any frameworks are linked)
8+
- `test_binary_macho` - ARM64 Mach-O binary with standard load commands:
9+
- LC_LOAD_DYLIB for system library dependencies (e.g., libSystem.B.dylib)
10+
- May include LC_RPATH commands
11+
- May include framework dependencies
912
- `test_binary_pe.exe` - x86-64 PE binary
1013
- `test_binary_with_resources.exe` - x86-64 PE binary with VERSIONINFO and STRINGTABLE resources
1114

‎tests/integration_macho.rs‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,12 @@ fn test_macho_load_command_extraction_snapshot() {
267267
for (i, string) in dylib_paths.iter().take(20).enumerate() {
268268
let is_framework = string.text.contains(".framework");
269269
output.push_str(&format!(
270-
"Dylib Path {}: {} {}\n",
270+
"Dylib Path {}: {}{}",
271271
i + 1,
272272
string.text,
273-
if is_framework { "(Framework)" } else { "" }
273+
if is_framework { " (Framework)" } else { "" }
274274
));
275+
output.push('\n');
275276
}
276277
if dylib_paths.len() > 20 {
277278
output.push_str(&format!("... and {} more\n", dylib_paths.len() - 20));
@@ -285,15 +286,16 @@ fn test_macho_load_command_extraction_snapshot() {
285286
for (i, string) in rpaths.iter().take(20).enumerate() {
286287
let has_variable = has_rpath_variable(&string.text);
287288
output.push_str(&format!(
288-
"Rpath {}: {} {}\n",
289+
"Rpath {}: {}{}",
289290
i + 1,
290291
string.text,
291292
if has_variable {
292-
"(Contains @-variable)"
293+
" (Contains @-variable)"
293294
} else {
294295
""
295296
}
296297
));
298+
output.push('\n');
297299
}
298300
if rpaths.len() > 20 {
299301
output.push_str(&format!("... and {} more\n", rpaths.len() - 20));
@@ -489,16 +491,14 @@ fn test_macho_rpath_variable_detection() {
489491

490492
for rpath_var in &rpaths_with_vars {
491493
let mut variables_found = Vec::new();
492-
if has_rpath_variable(&rpath_var.text) {
493-
if rpath_var.text.contains("@rpath") {
494-
variables_found.push("@rpath");
495-
}
496-
if rpath_var.text.contains("@executable_path") {
497-
variables_found.push("@executable_path");
498-
}
499-
if rpath_var.text.contains("@loader_path") {
500-
variables_found.push("@loader_path");
501-
}
494+
if rpath_var.text.contains("@rpath") {
495+
variables_found.push("@rpath");
496+
}
497+
if rpath_var.text.contains("@executable_path") {
498+
variables_found.push("@executable_path");
499+
}
500+
if rpath_var.text.contains("@loader_path") {
501+
variables_found.push("@loader_path");
502502
}
503503
println!(
504504
"Rpath variable found: {} (variables: {:?})",

‎tests/snapshots/integration_macho__macho_load_command_strings.snap‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
---
22
source: tests/integration_macho.rs
3-
assertion_line: 314
43
expression: output
54
---
65
=== DYLIB PATHS ===
76
Total: 2
87

9-
Dylib Path 1: /usr/lib/libSystem.B.dylib
10-
Dylib Path 2: self
8+
Dylib Path 1: /usr/lib/libSystem.B.dylib
9+
Dylib Path 2: self
1110

1211
=== RPATHS ===
1312
Total: 0

0 commit comments

Comments
 (0)