aonez / aonez/Keka

[BUG] Crash in moveExtractionContents: — URLByAppendingPathComponent: with nil lastPathComponent (v1.6.7, macOS 27)

未关闭
#1,771 1 条评论 0 个 reaction 已指派 1 人 已被 @aonez 认领 在 GitHub 查看
bug core more info needed works for me
主要语言
PHP
星标
7.3k
派生
294
平均合并
14 天 16 小时
30 天内合并 PR
1

描述

### Brief description

Keka **crashes (SIGABRT)** when finishing an extraction. The uncaught exception is raised inside `-[NSURL URLByAppendingPathComponent:]` because the path component argument is **nil**.

This happens after extraction, while moving/finalizing extraction contents — not during the archive tool process itself.

### Keka version

- **Keka 1.6.7 (5729)** — latest GitHub release as of 2026-06-30
- Distribution: notarized Developer ID build from keka.io (`TeamIdentifier=4FG648TM2A`)
- Universal binary, crash on **arm64** slice

### macOS version

- **macOS 27.0 (26A5406e)** (Apple Silicon, Mac17,8)
- Hardened Runtime enabled

### Steps to reproduce

1. Install Keka 1.6.7 (fresh / sandboxed install with little or no File Access bookmarks configured).
2. Double-click an archive (or open with Keka) so extraction starts immediately.
3. Keka aborts shortly after launch / during finalize (seen within ~9s of process start).

Observed 4 identical crashes in a few minutes (`Keka-2026-08-12-182916` … `183033.ips`).

### Expected behaviour

Extraction completes (or fails with a recoverable error / access prompt). Keka should not abort.

### Actual behaviour

Process terminates:

- `EXC_CRASH` / `SIGABRT`
- `asi: abort() called` (uncaught Objective-C exception)
- Exception originates from:
`-[NSURL(NSURLPathUtilities) URLByAppendingPathComponent:]`

Apple raises when the **component argument is nil**:
`*** -[NSURL URLByAppendingPathComponent:]: component, components, or pathExtension cannot be nil.`

### Evidence (crash stack)

`lastExceptionBacktrace` / faulting main thread (summarized):

```
objc_exception_throw
-[NSURL URLByAppendingPathComponent:]
Keka moveExtractionContents: (+0xc8 / imageOffset 123752)
Keka finalizeTask (+0x1b0 / imageOffset 259608)
Keka (caller around applyQuarantine path / finalize, imageOffset 245828)
_dispatch_client_callout / main queue
```

Four consecutive reports share the **same** exception site and offsets.

### Binary analysis (v1.6.7 arm64)

ObjC method mapping from the binary:

| Image offset | Method |
|---|---|
| `0x10001e2a0` | `-moveExtractionContents:` |
| `0x10003f468` | `-finalizeTask` |
| Crash return addr `0x10001e368` | inside `moveExtractionContents:` right after the throwing call |

Reconstructed call sequence at the throw site in `-moveExtractionContents:` (selectors resolved from `__objc_stubs` / selrefs):

```objc
// package = [task package] (or equivalent receiver chain)
NSURL *destinationPath = package.destinationPath; // base (non-nil in crash path)
// ...
NSString *component =
package.sourcePath
.URLByDeletingPathExtension
.lastPathComponent; // can be nil

NSURL *url = [destinationPath URLByAppendingPathComponent:component]; // THROWS if component == nil
```

Relevant selectors confirmed on the path:

- `package`
- `packageTemporaryPath`
- `destinationPath`
- `sourcePath`
- `URLByDeletingPathExtension`
- `lastPathComponent`
- `URLByAppendingPathComponent:` ← throw
- also nearby: `useInputNameAsIntermediateFolder`, `tarballWithTwoExtensions`

So the crash is **not** a random memory corruption; it is a missing nil-check on the intermediate folder / output name derived from `sourcePath`.

### Likely conditions for `component == nil`

From Foundation behavior / sandbox setup on this machine:

1. **`sourcePath` is nil** (bookmark / security-scoped access failed; then the whole chain returns nil, and `URLByAppendingPathComponent:` throws).
2. Or `sourcePath` is an `NSURL` with **no path**, so `lastPathComponent` is nil after `URLByDeletingPathExtension`.

On the crashing system:

- Keka is sandboxed (`com.apple.security.app-sandbox`).
- App Group container `4FG648TM2A.group.com.aone.keka` was effectively **empty** (no persisted File Access bookmarks).
- Preferences only had Sparkle keys — no saved extract destination.

That matches “open archive with little file access → finalize still calls `moveExtractionContents:` with a bad/missing `sourcePath`”.

### Suggested fix (for maintainers)

In `-moveExtractionContents:` (and any similar builders):

```objc
NSURL *source = package.sourcePath;
NSString *component = source.URLByDeletingPathExtension.lastPathComponent;
if (component.length == 0) {
// fallback: temporary package name, UUID, or skip rename and surface a file-access error
return; // or handle error without throwing
}
NSURL *url = [destinationPath URLByAppendingPathComponent:component];
```

Also guard:

- `destinationPath == nil`
- failed security-scoped bookmark resolve

Optional: prefer `URLByAppendingPathComponent:isDirectory:` and avoid building paths when File Access / source URL is unavailable — ask for access instead of finalizing.

### Workaround for users

1. Open Keka first → **Preferences → File Access** → grant Home / Full Disk access.
2. Prefer drag-and-drop into the Keka window over double-click until fixed.
3. Or extract with Archive Utility / `ditto` as a temporary bypass.

### Notes

- Latest release notes for 1.6.x fix other macOS 26 issues (default uncompressor, BSDTAR, ISO, etc.) but **do not** mention this finalize / `moveExtractionContents:` crash.
- This repository does not contain the app sources, so a code PR is not possible from the community side; filing here for maintainers.

### Attachments

Happy to attach full `.ips` reports (`Keka-2026-08-12-*.ips`) if useful. Key fields:

- `app_version`: 1.6.7 / `build_version`: 5729
- `exception`: `EXC_CRASH (SIGABRT)`
- `termination`: Abort trap: 6 by Keka
- `cpuType`: ARM-64

Thanks!

贡献指南

这个仓库没有索引到贡献指南

调研方向

The repository does not contain app sources, so start with the supplied crash reports and the binary entry point moveExtractionContents:, then trace finalizeTask and the sourcePath/destinationPath inputs. Done means extraction no longer aborts when access or source-path data is missing and instead completes or surfaces a recoverable error.

由索引模型根据 Issue 内容生成。

评估

技术栈
macos, objective-c
领域
desktop
Issue 类型
缺陷
难度
5/5
预计耗时
一周以上
活跃度
冷清
描述清晰度
基本清楚
新手友好度
35/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。