File: type-layout-fuzzer.py

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (157 lines) | stat: -rw-r--r-- 4,189 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/env python3

# This script outputs a Swift source with randomly-generated type definitions,
# which can be used for ABI or layout algorithm fuzzing.

# TODO: generate types with generics, existentials, compositions

import random
import sys

maxDepth = 5
maxMembers = 5
typesDefined = []
classesDefined = []
nextToDefine = 0
objcInterop = False

if len(sys.argv) >= 2:
    if sys.argv[1] == "--objc":
        objcInterop = True
    if sys.argv[1] == "--help":
        print("Usage: " + sys.argv[0] + " [--objc]", file=sys.stderr)
        print("", file=sys.stderr)
        print("  --objc          Include ObjC-interop types", file=sys.stderr)
        sys.exit(2)

random.seed()
if objcInterop:
    print("import Foundation")
    print()


def randomTypeList(depth):
    count = random.randint(0, maxMembers)
    result = "("
    for i in range(count):
        if i > 0:
            result += ", "
        result += randomTypeReference(depth + 1)
    result += ")"
    return result


def randomTypeReference(depth):
    def nominal():
        global typesDefined
        allowNew = depth < maxDepth
        bound = len(classesDefined) if allowNew else len(classesDefined) - 1
        which = random.randint(0, bound)
        if which < len(classesDefined):
            return classesDefined[which]
        newName = "T" + str(len(typesDefined))

        def defineRandomRelatedType(name):
            defineRandomNominalType(name, depth)

        typesDefined.append((newName, defineRandomRelatedType))
        return newName

    def tuple():
        return randomTypeList(depth + 1)

    def metatype():
        return "(" + randomTypeReference(depth + 1) + ").Type"

    def leaf():
        leaves = ["Int", "String", "Int8", "Int16", "Int32", "Int64",
                  "(() -> ())", "(@convention(c) () -> ())", "AnyObject"]
        if objcInterop:
            leaves += ["NSObject", "(@convention(block) () -> ())"]
        return random.choice(leaves)

    if depth < maxDepth:
        kinds = [nominal, tuple, metatype, leaf, leaf, leaf, leaf, leaf]
    else:
        kinds = [leaf]
    return random.choice(kinds)()


def defineRandomFields(depth, basename):
    numMembers = random.randint(0, maxMembers)
    for i in range(numMembers):
        print("  var " + basename + str(i) + ": " +
              randomTypeReference(depth + 1))


def defineRandomClass(name, depth):
    global classesDefined
    classesDefined.append(name)
    print("class " + name, end="")

    def inheritNSObject():
        print(": NSObject", end="")

    def inheritsOtherClass():
        print(": ", end="")
        name = "T" + str(len(typesDefined))

        def defineRandomBaseClass(name):
            defineRandomClass(name, depth)

        typesDefined.append((name, defineRandomBaseClass))
        print(name, end="")

    def inheritsNothing():
        pass

    inheritances = [inheritsNothing]
    if depth == 0:
        # The contents of classes are interesting only for top-level type
        inheritances += [inheritsOtherClass]

    if objcInterop:
        inheritances += [inheritNSObject]
    random.choice(inheritances)()

    print(" {")
    # Prevent errors about lack of initializers
    print("  init(" + name + ": ()) { fatalError() }")
    # The contents of classes are interesting only for top-level type
    if depth == 0:
        defineRandomFields(depth, "x" + name)
    print("}")
    print()


def defineRandomNominalType(name, depth=0):
    def struct():
        print("struct " + name + " {")
        defineRandomFields(depth, "x")
        print("}")
        print()

    def clazz():
        defineRandomClass(name, depth)

    def enum():
        # TODO: indirect cases
        print("enum " + name + " {")

        numCases = random.randint(0, maxMembers)
        for i in range(numCases):
            print("  case x" + str(i) + randomTypeList(depth + 1))

        print("}")
        print()

    kinds = [struct, clazz, enum]
    return random.choice(kinds)()


typesDefined.append(("Generated", defineRandomNominalType))

while nextToDefine < len(typesDefined):
    name, definer = typesDefined[nextToDefine]
    definer(name)
    nextToDefine += 1