Skip to content

Instantly share code, notes, and snippets.

@twostraws
Created September 21, 2017 19:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save twostraws/1d154e956ff4bda56b4515a39d37b27b to your computer and use it in GitHub Desktop.
Save twostraws/1d154e956ff4bda56b4515a39d37b27b to your computer and use it in GitHub Desktop.
A Swift 4 port of Joe Groff's type-layout-fuzzer.py
//
// type-layout-fuzzer.swift
// Paul Hudson / @twostraws / www.hackingwithswift.com
//
// This is a Swift 4 port of Joe Groff's type-layout-fuzzer.py.
// I haven't attempted to Swiftify the code – it's pretty
// much a line-by-line port.
//
// License: public domain / CC0 / seriously, do whatever
// you want with it.
import Foundation
let maxDepth = 5
let maxMembers: UInt32 = 5
var typesToDefine: [UInt32] = [0]
var nextName = 1
extension Array {
mutating func shuffle() {
for i in 0 ..< (count - 1) {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
swapAt(i, j)
}
}
}
func randomTypeList(_ depth: Int) -> String {
let count = arc4random_uniform(maxMembers)
var result = "("
for i in 0 ..< count {
if i > 0 {
result += ", "
}
result += randomTypeReference(depth + 1)
}
result += ")"
return result
}
func randomTypeReference(_ depth: Int) -> String {
func nominal() -> String {
let which: UInt32
if depth < maxDepth {
which = arc4random_uniform(UInt32(nextName))
} else {
which = arc4random_uniform(UInt32(nextName - 1))
}
if which == nextName {
typesToDefine.append(which)
nextName += 1
}
return "T" + String(which)
}
func tuple() -> String {
return randomTypeList(depth + 1)
}
func metatype() -> String {
return "(" + randomTypeReference(depth + 1) + ").Type"
}
func leaf() -> String {
var leaves = ["Int", "String", "Int8", "Int16", "Int32", "Int64"]
leaves.shuffle()
return leaves[0]
}
var kinds: [() -> String]
if depth < maxDepth {
kinds = [nominal, tuple, metatype, leaf, leaf, leaf, leaf, leaf]
} else {
kinds = [leaf]
}
kinds.shuffle()
return kinds[0]()
}
func defineRandomProduct(_ kind: String, _ name: String, _ depth: Int) {
print(kind + " " + name + " {")
// Suppress errors about missing initializers
print(" init() { fatalError() }")
let numMembers = arc4random_uniform(maxMembers)
for i in 0 ..< numMembers {
print(" var x" + String(i) + ": " + randomTypeReference(depth + 1))
}
print("}")
}
func defineRandomEnum(_ name: String, _ depth: Int) {
// TODO: indirect cases
print("enum " + name + " {")
let numCases = arc4random_uniform(maxMembers)
for i in 0 ..< numCases {
print(" case x" + String(i) + randomTypeList(depth + 1))
}
print("}")
}
func defineRandomType(_ name: String, _ depth: Int) {
func `struct`() {
defineRandomProduct("struct", name, depth)
}
func `class`() {
defineRandomProduct("class", name, depth)
}
func `enum`() {
defineRandomEnum(name, depth)
}
var kinds: [() -> Void] = [`struct`, `class`, `enum`]
kinds.shuffle()
return kinds[0]()
}
while typesToDefine.count > 0 {
let ty = typesToDefine.removeFirst()
defineRandomType("T" + String(ty), 0)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment