Skip to content

[SR-6468] inheriting from class with synthesized Codable implementation creates invalid code #49018

@swift-ci

Description

@swift-ci
Previous ID SR-6468
Radar rdar://problem/35699277
Original Reporter derammo (JIRA User)
Type Bug
Status Resolved
Resolution Done

Attachment: Download

Environment

swift-4.1-DEVELOPMENT-SNAPSHOT-2017-11-23-a.xctoolchain

also happens in Xcode 9.1 as released by Apple:

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, Codable
Assignee @slavapestov
Priority Medium

md5: 44a3722f047bd288f0a7c1c8573bee7e

is duplicated by:

  • SR-6507 Encodable in combination with class inheritance and computed properties generates unexpected behaviour
  • SR-7090 Crashing with EXC_BAD_ACCESS after decoding Codable subclass
  • SR-7156 Synthesized instance methods result in vtable-related crashes

Issue Description:

Inheriting from a class that has some of its "Codable" protocol implementation synthesized automatically can lead to invalid code. Specifically, the derived class ends up with code that accesses out of the bounds of the table of methods when trying to invoke a method on an instance of the derived class.

I verified this by disassembly. Instead of fetching the address of the first getter, it fetches a small number (which seems to be the table size) that is located 8 bytes to the left of the correct information. Then it calls this address, which obviously faults.

In this example, you see if it fetching the 0x18 (presumably table size) instead of the valid address of the getter 0x0106bdf460, which is stored right after it.

(lldb) dis -l

-> 10      func testInheritedGeneratedInitializerFromCodableSynthesizer() {
-> 11          let instance = TestPartiallySynthesizedDerivedClass(arg1: 1, arg2: 2)
-> 12          let getting = instance.derivedMember

testUnit`testCompiler.testInheritedGeneratedInitializerFromCodableSynthesizer():
->  0x106bb6af9 <+41>: movq   (%rax), %rsi
    0x106bb6afc <+44>: movq   0xb0(%rsi), %rsi
    0x106bb6b03 <+51>: movq   %rax, %r13
    0x106bb6b06 <+54>: movq   %rax, -0x18(%rbp)
    0x106bb6b0a <+58>: callq  *%rsi
(lldb) nexti
(lldb) register read rsi
     rsi = 0x0000000106c46550  type metadata for testUnit.TestPartiallySynthesizedDerivedClass
(lldb) memory read 0x106C46600
0x106c46600: 18 00 00 00 00 00 00 00 60 f4 bd 06 01 00 00 00  ........`.......
0x106c46610: b0 f4 bd 06 01 00 00 00 30 f5 bd 06 01 00 00 00  ........0.......
(lldb) dis -a 0106bdf460
testUnit`_T08testUnit36TestPartiallySynthesizedDerivedClassC13derivedMemberSbvg:
    0x106bdf460 <+0>:  pushq  %rbp
    0x106bdf461 <+1>:  movq   %rsp, %rbp
    0x106bdf464 <+4>:  subq   $0x40, %rsp
    0x106bdf468 <+8>:  movq   %r13, -0x8(%rbp)
    0x106bdf46c <+12>: movq   %r13, %rax
    0x106bdf46f <+15>: addq   $0x20, %rax
    0x106bdf473 <+19>: xorl   %ecx, %ecx
    0x106bdf475 <+21>: movl   %ecx, %edx
    0x106bdf477 <+23>: leaq   -0x20(%rbp), %rsi
    0x106bdf47b <+27>: movq   %rax, %rdi
    0x106bdf47e <+30>: movq   %rsi, -0x28(%rbp)
    0x106bdf482 <+34>: movq   %rdx, -0x30(%rbp)
    0x106bdf486 <+38>: movq   -0x30(%rbp), %rcx
    0x106bdf48a <+42>: movq   %r13, -0x38(%rbp)
    0x106bdf48e <+46>: callq  0x106c278de               ; symbol stub for: swift_beginAccess
    0x106bdf493 <+51>: movq   -0x38(%rbp), %rax
    0x106bdf497 <+55>: movb   0x20(%rax), %al
    0x106bdf49a <+58>: movq   -0x28(%rbp), %rdi
    0x106bdf49e <+62>: movb   %al, -0x39(%rbp)
    0x106bdf4a1 <+65>: callq  0x106c2790e               ; symbol stub for: swift_endAccess
    0x106bdf4a6 <+70>: movb   -0x39(%rbp), %al
    0x106bdf4a9 <+73>: addq   $0x40, %rsp
    0x106bdf4ad <+77>: popq   %rbp
    0x106bdf4ae <+78>: retq   

The problem is reliably reproduced but extremely specific. Adding explicit support for Codable in the base class makes it go away. Adding explicit support for Codable in the derived class (by adding decode(from) also) also makes it go away. The classes must be in a separate file from the caller for this to fail.

The attached files reproduce the problem 100% of the time as a unit test.

Metadata

Metadata

Assignees

Labels

CodableArea → standard library: `Codable` and co.bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler itself

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions