So turns out we don't use shadowOffset in any demo code. So examining CAAnimation was pointless.
However I managed to get a backtrace using lldb, and this happens when the code sets the default shadowOffset value. So you pointed to the right place; shadowOffset is the problem. This is the place of the exception, in -[CALayer init] which calls +[CALayer defaultValueForKey:]:
if ([key isEqualToString: @"shadowOffset"])
{
CGSize offset = CGSizeMake(0.0, -3.0);
return [NSValue valueWithBytes: &offset objCType: @encode(CGSize)];
}
What is strange is that this happens deep inside base, when I am setting valueWithBytes, with a CGSize type.
So I looked closer at the backtrace and it's happening in base/Source/Additions/GSObjCRuntime.m. Relevant chunk:
frame #2: 0x00007ffff59e9d7d libgnustep-base.so.1.25`+[NSException raise:format:](self=0x00007ffff5f69878
, _cmd="S", name=0x00007ffff5f69438, format=0x00007ffff6003828) + 365 at NSException.m:1376
frame #3: 0x00007ffff5b9ca2f libgnustep-base.so.1.25`-[NSObject(self=0x000000000148f568, _cmd="\xffffffa9
\x02", aSel="\x0e\x01") subclassResponsibility:] + 255 at NSObject+GNUstepBase.m:134
frame #4: 0x00007ffff5b1d32b libgnustep-base.so.1.25`-[NSValue pointValue](self=0x000000000148f568, _cmd=
"\x0e\x01") + 43 at NSValue.m:394
frame #5: 0x00007ffff5b58649 libgnustep-base.so.1.25`GSObjCSetVal(self=0x00000000014591c8, key="shadowOff
set", val=0x000000000148f568, sel="\xffffffda\e", type="{_NSSize=dd}", size=12, offset=0) + 3497 at GSObjCRun
time.m:1794
frame #6: 0x00007ffff5a25857 libgnustep-base.so.1.25`SetValueForKey(self=0x00000000014591c8, anObject=0x0
00000000148f568, key="shadowOffset", size=12) + 1079 at NSKeyValueCoding.m:150
frame #7: 0x00007ffff5a253ee libgnustep-base.so.1.25`-[NSObject(self=0x00000000014591c8, _cmd="P\x04", an
Object=0x000000000148f568, aKey=0x00007ffff62cc560) setValue:forKey:] + 382 at NSKeyValueCoding.m:370
frame #8: 0x00007ffff5a2881d libgnustep-base.so.1.25`-[GSKVOBase setValue:forKey:](self=0x00000000014591c
8, _cmd="P\x04", anObject=0x000000000148f568, aKey=0x00007ffff62cc560) + 221 at NSKeyValueObserving.m:238
frame #9: 0x00007ffff60a22ac libQuartzCore.so.0`-[CALayer init](self=0x00000000014591c8, _cmd="\xffffffa1
I added a debug statement to GSObjCSetVal:
case _C_STRUCT_B:
if (GSSelectorTypesMatch(@encode(NSPoint), type))
{
NSLog(@"match! point is %s, type is %s", @encode(NSPoint), type);
NSPoint v = [val pointValue];
This is the output:
2018-05-27 17:58:46.980 hello_carenderer[10274:10274] match! point is {_NSPoint=dd}, type is {_NSPoint=dd}
2018-05-27 17:58:46.981 hello_carenderer[10274:10274] match! point is {_NSPoint=dd}, type is {_NSSize=dd}
Therefore, it's a bug in -base that makes it interpret sizes as points!
I'm still coming up with a minimum repro case.
(n.b. some of the confusion on why CGSize and CGPoint get understood as their NS equivalents is this chunk from opal:
typedef NSPoint CGPoint;
typedef NSSize CGSize;
typedef NSRect CGRect;
I do not believe this to be correct, but I will not be addressing it at this time.
Separately: are typedefs of structs meant to be encoded as the original struct name? Probably yes?)