Skip to content

Instantly share code, notes, and snippets.

@yebblies
Created June 8, 2014 10:11
Show Gist options
  • Save yebblies/c44a197c514b2f19f888 to your computer and use it in GitHub Desktop.
Save yebblies/c44a197c514b2f19f888 to your computer and use it in GitHub Desktop.
Fuzz testers to find struct field alignment mismatch between D and C++
import std.stdio;
import std.process;
import std.random;
import std.exception;
import std.uuid;
import std.range;
abstract
class Value
{
void writeCheckCpp(ref File f, string prefix, size_t i);
void writeCheckD(ref File f, string prefix, size_t i);
void writeStructCpp(ref File f);
void writeStructD(ref File f);
void writeMemberCpp(ref File f, size_t i);
void writeMemberD(ref File f, size_t i);
}
class Struct : Value
{
string name;
Value[] members;
this(string name)
{
this.name = name;
}
override void writeCheckCpp(ref File f, string prefix, size_t i)
{
auto m = "val_%d".format(i);
f.writefln("\tprintf(\"%s: %%p\\n\", (char*)&%s.%s - (char*)&%s);", m, prefix, m, prefix);
}
override void writeCheckD(ref File f, string prefix, size_t i)
{
auto m = "val_%d".format(i);
f.writefln("\tprintf(\"%s: %%p\\n\", cast(char*)&%s.%s - cast(char*)&%s);", m, prefix, m, prefix);
}
override void writeStructCpp(ref File f)
{
foreach(i, m; members)
m.writeStructCpp(f);
f.writefln("struct %s {", name);
foreach(i, m; members)
m.writeMemberCpp(f, i);
f.writefln("};");
f.writefln("");
}
override void writeStructD(ref File f)
{
foreach(i, m; members)
m.writeStructD(f);
f.writefln("struct %s {", name);
foreach(i, m; members)
m.writeMemberD(f, i);
f.writefln("}");
f.writefln("");
}
override void writeMemberCpp(ref File f, size_t i)
{
auto mname = "val_%d".format(i);
f.writefln("\t%s %s;", name, mname);
}
override void writeMemberD(ref File f, size_t i)
{
auto mname = "val_%d".format(i);
f.writefln("\t%s %s;", name, mname);
}
}
class Basic : Value
{
string dname;
string cname;
this(string dname, string cname)
{
this.dname = dname;
this.cname = cname;
}
override void writeCheckCpp(ref File f, string prefix, size_t i)
{
auto m = "val_%d".format(i);
f.writefln("\tprintf(\"%s: %%p\\n\", (char*)&%s.%s - (char*)&%s);", m, prefix, m, prefix);
}
override void writeCheckD(ref File f, string prefix, size_t i)
{
auto m = "val_%d".format(i);
f.writefln("\tprintf(\"%s: %%p\\n\", cast(char*)&%s.%s - cast(char*)&%s);", m, prefix, m, prefix);
}
override void writeStructCpp(ref File f)
{
}
override void writeStructD(ref File f)
{
}
override void writeMemberCpp(ref File f, size_t i)
{
auto mname = "val_%d".format(i);
f.writefln("\t%s %s;", cname, mname);
}
override void writeMemberD(ref File f, size_t i)
{
auto mname = "val_%d".format(i);
f.writefln("\t%s %s;", dname, mname);
}
}
static immutable string[2][] basics =
[
["byte", "signed char"],
["ubyte", "unsigned char"],
["char", "char"],
["int", "int"],
["uint", "unsigned"],
["long", "long long"],
["ulong", "unsigned long long"],
["float", "float"],
["double", "double"],
["real", "long double"],
["bool", "bool"],
["void*", "void*"],
];
Value genValue()
{
auto p = uniform(0, basics.length + 1);
if (p == basics.length)
{
return genStruct("S" ~ randomUUID().toString().replace("-", "_"));
}
else
{
return new Basic(basics[p][0], basics[p][1]);
}
}
Struct genStruct(string name)
{
auto s = new Struct(name);
foreach(i; 0..uniform(0, 20))
{
s.members ~= genValue();
}
return s;
}
void main()
{
Lrestart:
auto testname = "test_struct_" ~ randomUUID().toString().replace("-", "_");
while(true)
{
auto s = genStruct("Test");
auto cf = File(testname ~ ".cpp", "wb");
auto df = File(testname ~ ".d", "wb");
cf.writeln("#include <stdio.h>");
df.writeln("import core.stdc.stdio;");
s.writeStructCpp(cf);
s.writeStructD(df);
cf.writeln("int main(void) {");
cf.writeln("\tTest s;");
foreach(i, m; s.members)
m.writeCheckCpp(cf, "s", i);
cf.writeln("\treturn 0;");
cf.writeln("}");
df.writeln("void main() {");
df.writeln("\tTest s;");
foreach(i, m; s.members)
m.writeCheckD(df, "s", i);
df.writeln("}");
cf.close();
df.close();
enforce(executeShell("g++ %s.cpp -o %s_cpp".format(testname, testname)).status == 0);
enforce(executeShell("./dmd %s.d -of%s_d".format(testname, testname)).status == 0);
auto cout = executeShell("./%s_cpp".format(testname));
auto dout = executeShell("./%s_d".format(testname));
enforce(cout.status == 0);
enforce(dout.status == 0);
if (cout.output != dout.output)
{
writeln("Output mismatch in ", testname);
goto Lrestart;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment