Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ struct AssetCatalogEntry: Encodable {
let height: Int?
let filename: String?
let type: AssetType?
let idiom: String?
let colorspace: String?
}

enum Error: Swift.Error {
Expand All @@ -49,6 +51,31 @@ typealias objectiveCMethodImp = @convention(c) (AnyObject, Selector, UnsafeRawPo
>?

enum AssetUtil {
private static func idiomToString(_ idiom: UInt?) -> String? {
guard let idiom = idiom else { return nil }
switch idiom {
case 0: return "universal"
case 1: return "phone"
case 2: return "pad"
case 3: return "tv"
case 4: return "carplay"
case 5: return "watch"
case 6: return "marketing"
default: return nil
}
}

private static func colorSpaceIDToString(_ colorSpaceID: UInt?) -> String? {
guard let colorSpaceID = colorSpaceID else { return nil }
switch colorSpaceID {
case 1: return "srgb"
case 2: return "gray gamma 22"
case 3: return "displayP3"
case 4: return "extended srgb"
default: return nil
}
}

private static func createResultsPath(assetURL: URL, outputURL: URL) throws -> URL {
var archiveURL = assetURL
var tailComponents: [String] = []
Expand Down Expand Up @@ -136,6 +163,9 @@ enum AssetUtil {
if !fileExtension.isEmpty && fileExtension != "svg", let unslicedImage = unslicedImage {
images[imageId] = (cgImage: unslicedImage, format: fileExtension)
}

let idiomValue = key.getUInt(forKey: "themeIdiom")
let colorSpaceID = rendition.getUInt(forKey: "colorSpaceID")
Comment on lines +167 to +168
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The getUInt extension uses perform(Selector(...)) without exception handling, which can cause a crash if the selector does not exist on the target object.
(Severity: Critical 0.85 | Confidence: 0.95)

🔍 Detailed Analysis

The getUInt(forKey:) extension method is called on lines 167 and 168 to retrieve themeIdiom and colorSpaceID. This method uses perform(Selector(key)) without a try-catch block. If the key or rendition objects, which are from Apple's private frameworks, do not implement methods corresponding to these selectors, the application will crash with an "Unrecognized Selector" exception. This can happen with different asset types or macOS versions. The codebase already contains a safeValueForKey function that handles this exact scenario, but it is not used for these new calls.

💡 Suggested Fix

Modify the getUInt extension to handle cases where the selector does not exist. Either wrap the perform(Selector(key)) call in a try-catch block or check responds(to:) before making the call to prevent a crash.

🤖 Prompt for AI Agent
Fix this bug. In
apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/AssetCatalogParser/AssetCatalogReader.swift
at lines 167-168: The `getUInt(forKey:)` extension method is called on lines 167 and 168
to retrieve `themeIdiom` and `colorSpaceID`. This method uses `perform(Selector(key))`
without a `try-catch` block. If the `key` or `rendition` objects, which are from Apple's
private frameworks, do not implement methods corresponding to these selectors, the
application will crash with an "Unrecognized Selector" exception. This can happen with
different asset types or macOS versions. The codebase already contains a
`safeValueForKey` function that handles this exact scenario, but it is not used for
these new calls.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The crash risk would only be if the selector itself didn't exist, but these are standard CoreUI selectors that do exist on these objects


let asset = AssetCatalogEntry(
imageId: imageId,
Expand All @@ -145,7 +175,9 @@ enum AssetUtil {
width: width,
height: height,
filename: renditionTypeName,
type: assetType
type: assetType,
idiom: idiomToString(idiomValue),
colorspace: colorSpaceIDToString(colorSpaceID)
)
assets.append(asset)
}
Expand All @@ -158,7 +190,9 @@ enum AssetUtil {
width: nil,
height: nil,
filename: nil,
type: nil
type: nil,
idiom: nil,
colorspace: nil
))

let data = try! JSONEncoder().encode(assets)
Expand Down