Skip to content
Merged
Show file tree
Hide file tree
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
16 changes: 8 additions & 8 deletions Example/Example.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,6 @@
/* End PBXFileReference section */

/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
27240CFE2E8FFBC900E9DABD /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
kdebug_interpose.c,
);
target = 27CD0B482AFC8D37003665EB /* Example */;
};
275751CC2DEE136C003E467C /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Expand All @@ -93,6 +86,13 @@
};
target = 27D49DF72BA604FB00F6E2E2 /* HostingExample */;
};
275C29E52F389AE8008676C3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
interpose.c,
);
target = 275751E22DEE1441003E467C /* TestingHost */;
Copy link

Choose a reason for hiding this comment

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

This exception set marks interpose.c as a membershipException for the TestingHost target, even though OpenSwiftUIUITests uses TestingHost.app as TEST_HOST. Please verify the interposer is actually present in the host process where the shape rendering/casts occur.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
Expand All @@ -102,7 +102,7 @@
275751F62DEE1456003E467C /* OpenSwiftUIUITests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = OpenSwiftUIUITests; sourceTree = "<group>"; };
279FEC572DF450D200320390 /* ReferenceImages */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = ReferenceImages; sourceTree = "<group>"; };
27E6C4F62D2842D80010502F /* Configurations */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); name = Configurations; path = ../Configurations; sourceTree = "<group>"; };
27FFF0422E08850C0060A4DA /* SharedExample */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (27240CFE2E8FFBC900E9DABD /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = SharedExample; sourceTree = "<group>"; };
27FFF0422E08850C0060A4DA /* SharedExample */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (275C29E52F389AE8008676C3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = SharedExample; sourceTree = "<group>"; };
/* End PBXFileSystemSynchronizedRootGroup section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down
6 changes: 2 additions & 4 deletions Example/OpenSwiftUIUITests/Shape/ShapeUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ struct ShapeUITests {
.frame(width: 100, height: 100, alignment: .center)
}
}
// FIXME
openSwiftUIAssertSnapshot(of: ContentView(), perceptualPrecision: 0.8)
openSwiftUIAssertSnapshot(of: ContentView())
}

@Test
Expand All @@ -42,7 +41,6 @@ struct ShapeUITests {
.frame(width: 100, height: 100, alignment: .center)
}
}
// FIXME
openSwiftUIAssertSnapshot(of: ContentView(), perceptualPrecision: 0.8)
openSwiftUIAssertSnapshot(of: ContentView())
}
}
58 changes: 58 additions & 0 deletions Example/SharedExample/interpose.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// interpose.c
// SharedExample
//
// Created by Kyle on 2025/10/3.
//

#include <stdbool.h>
#include <stdint.h>
#include <dlfcn.h>
#include <AttributeGraph/AttributeGraph-umbrella.h>

// Forward declare the original
extern bool kdebug_is_enabled(uint32_t debugid);

// Our replacement
static bool my_kdebug_is_enabled(uint32_t debugid) {
return true;
}

extern const void *$s15OpenSwiftUICore5ColorV8ResolvedVN;

const void *_OpenSwiftUI_ColorResolvedNTD(void) {
return &$s15OpenSwiftUICore5ColorV8ResolvedVN;
}

extern bool swift_dynamicCast(void *dest, void *src,
const void *srcType,
const void *targetType,
uint64_t flags);

static bool my_swift_dynamicCast(void *dest, void *src, const void *srcType, const void *targetType, uint64_t flags) {
CFStringRef target_description = AGTypeDescription((AGTypeID)targetType);
// Check if target_description contains "Color.Resolved"
if (target_description != NULL) {
CFRange range = CFStringFind(target_description, CFSTR("Color.Resolved"), 0);
if (range.location != kCFNotFound) {
// First try the original cast, if it fails try with OpenSwiftUI's Color.Resolved
return swift_dynamicCast(dest, src, srcType, targetType, flags) ||
Copy link

Choose a reason for hiding this comment

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

Because swift_dynamicCast is being interposed, calling swift_dynamicCast(...) from inside my_swift_dynamicCast may resolve back to the interposer and recurse. Can you confirm this call path reliably reaches the original Swift runtime implementation in all build/linking modes?

Severity: high

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

swift_dynamicCast(dest, src, srcType, _OpenSwiftUI_ColorResolvedNTD(), flags);
}
}
return swift_dynamicCast(dest, src, srcType, targetType, flags);
}

// Interpose using Mach-O section
typedef struct interpose_s {
const void *replacement;
const void *original;
} interpose_t;

__attribute__((used)) static const interpose_t interposers[]
__attribute__((section("__DATA, __interpose"))) = {
// Interpose kdebug_is_enabled to always return true to perform Signpost testing with Instruments
{ (const void *)my_kdebug_is_enabled, (const void *)kdebug_is_enabled },
// Interpose swift_dynamicCast to handle casts to SwiftUI's internal Color.Resolved type to fix SwiftUI.ShapeLayerHelper visit check for Shape.fill API
{ (const void *)my_swift_dynamicCast, (const void *)swift_dynamicCast },
Copy link

Choose a reason for hiding this comment

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

Interposing swift_dynamicCast affects every dynamic cast in the process, so any unexpected behavior here can have a wide blast radius beyond Shape.fill. Please double-check this file is only linked into the intended debug/test host (and not shipped in normal Example/production builds).

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

};
31 changes: 0 additions & 31 deletions Example/SharedExample/kdebug_interpose.c

This file was deleted.

2 changes: 1 addition & 1 deletion Sources/OpenSwiftUICore/Graphic/Color/Paint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ final package class _AnyResolvedPaint<P>: AnyResolvedPaint where P: ResolvedPain
return paint == other.paint
}

override package func visit<V>(_ visitor: inout V) where V : ResolvedPaintVisitor {
override package func visit<V>(_ visitor: inout V) where V: ResolvedPaintVisitor {
visitor.visitPaint(paint)
}

Expand Down
Loading