31
ONE DEFINITION RULE HOW TO LIVE WITH IT Alexey Kutumov Software engineer at Kaspersky Lab

One definition rule - что это такое, и как с этим жить

Embed Size (px)

Citation preview

ONE DEFINITION RULE – HOW TO LIVE WITH IT

Alexey Kutumov

Software engineer at Kaspersky Lab

CONTENTS

2

И ЦИЯ

И Е Ы

CLANG/ODR-CHECK

3

2

1

И ЦИЯ

ODR-CHECK

4

Compilation/linking

compile

compile

compile .cpp .obj .exe

.cpp .obj

.cpp .obj ar

.lib

link

И ЦИЯ

5

enumeration

enum Foo {

e1,

e2,

eCount

};

const char* FooToString(Foo x);

int main() {

std::cout << FooToString(e2) << std::endl;

return 0;

}

enum Foo {

e1,

eCount

};

const char xxx [] = «can you see me?!!»

const char* msg [eCount] = {

«e1»

};

const char* canYouSeeMe = xxx;

const char* FooToString(Foo x) {return msg[x];}

И ЦИЯ

6

struct A : private boost::noncopyable {

A() : x(«0») {}

const std::string x;

int y;

};

void Modify(A& a);

int main() {

A a;

Modify(a);

std::cout << a.x << std::endl;

return 0;

}

struct A : private boost::noncopyable {

A();

int x;

const std::string y;

};

void Modify(A& a) {

a.x += 1;

}

И ЦИЯ

7

pragma pack

#pragma pack(push, 1)

struct C {

char c;

uint32_t x;

};

#pragma pack(pop)

void Modify(C* c, size_t pos);

int main() {

std::string x = «0»;

C c[8] = {0};

Modify(c, 6);

std::cout << x << std::endl;

return 0;

}

struct C {

char c;

uint32_t x;

};

void Modify(C* c, size_t pos) {

c[pos].x += 1;

}

И ЦИЯ

8

К

• , ,

• + Х assert, core dump, ,

• - « »

•Code review • - ,

•gcc –Wodr, gold –detect-odr-violations • +

• - , false positive

•Amalgamation (sqlite) • +

• -

• -

И Е Ы

И Е Ы

10

3.2 C++

• , , ,

• non-inline ODR-used

• , , complete.

И Е Ы

11

3.2 C++

• non-inline

ODR-used.

• , , inline external linkage, , . :

• К

• В , TU

И Е Ы

12

3.2 C++

Undefined Behavior

И Е Ы

13

Т

•А

•Т IDE, .

И Е Ы

14

#pragma detect_mismatch

#pragma detect_mismatch(«my_name», «my_value1») /// cpp1.cpp

#pragma detect_mismatch(«my_name», «my_value2») /// cpp2.cpp

cpp2.obj : error LNK2038: mismatch detected for 'my_name': value ‘my_value ' doesn't match value ‘my_value ' in cpp1.obj

dumpbin /ALL cpp1.obj

Linker Directives

-----------------

/FAILIFMISMATCH:"my_name=my_value1"

/DEFAULTLIB:"MSVCRTD"

/DEFAULTLIB:"OLDNAMES"

CLANG/ODR-CHECK

CLANG

16

clang

ODR-CHECK

17

Compilation/linking

compile

compile

compile .cpp .obj .exe

.cpp .obj

.cpp .obj ar

.lib

link

ODR-CHECK

18

Checking for ODR violations

emit-ast

emit-ast

emit-ast .cpp .ast .ast

.cpp .ast

.cpp .ast merge-ast

.ast

merge-ast

ODR-CHECK

19

Compilation

http://clang.llvm.org/docs/IntroductionToTheClangAST.html

http://clang.llvm.org/docs/InternalsManual.html

.cpp token

stream ASTContext

Preprocessor/Lexer Sema LLVM IR

ASTFrontendAction (CodeGenAction)

ODR-CHECK

20

Storing AST to file

.cpp token

stream ASTContext

Preprocessor/Lexer Sema .ast

ASTFrontendAction (GeneratePCHAction)

ODR-CHECK

21

Merging ASTs

cannot import unsupportОН noНО: …

.ast

.ast

.ast

.ast ASTMergeAction

ODR-CHECK

22

Merging ASTs

• :

• ODR,

ODR-CHECK

23

RecursiveASTVisitor

namespace m {

struct X {

int a;

};

}

clang ../main.cpp -Xclang -ast-dump -fsyntax-only

http://clang.llvm.org/docs/RAVFrontendAction.html

ODR-CHECK

24

ASTImporter

TranslationUnitDecl (From) TranslationUnitDecl (To)

|-Node |-Node

`-Node `-Node

`-Node `-Node

ASTNodeImporter

ODR-CHECK

25

ASTNodeImporter

namespace m { /// 4. NamespaceDecl(NamedDecl, DeclContext)

namespace n { /// 3. NamespaceDecl (NamedDecl, DeclContext)

struct X { /// 2. CXXRecordDecl (..., TypeDecl, DeclContext)

struct Y { /// 1. CXXRecordDecl (..., TypeDecl, DeclContext)

int a; /// <- IMPORT

};

};

}

}

ODR-CHECK

26

StructuralEquivalenceContext

namespace m {

struct X {

int a;

long b;

};

struct Y {

X x;

int b;

};

struct Z {

int b;

};

}

namespace m {

struct X {

int a;

long b;

};

struct Y {

X x;

long b;

};

struct Z {

int a;

};

}

ODR-CHECK

27

И cmake

clang++ -DMY_SUPER_DEFINE –Wall –I/my/include –emit-ast source_file.cpp –o source_file.ast

clang++ -cc1 –emit-pch –o lib_file.ast -ast-merge source_file1.ast –ast-merge source_file2.ast

cmake ../src -DCMAKE_TOOLCHAIN_FILE=d:/tools/ClangOdrCheckToolchain.cmake –D...

make

ODR-CHECK

28

Sample output

namespace m {

struct X {

int x;

#if defined (M1)

int z;

#endif /* M1 */

};

}

ODR-CHECK

29

Sample output

In file included from d:\pixel\projects\odr-check\odr-check-test\src\data\src\m1.cpp:3:

d:\pixel\projects\odr-check\odr-check-test\src\data\src/h1.h:11:8: warning: type 'struct m::X' has incompatible definitions in different translation units

struct X

^

d:\pixel\projects\odr-check\odr-check-test\src\data\src/h1.h:16:7: note: field 'z' has type 'int' here

int z;

^

d:\pixel\projects\odr-check\odr-check-test\src\data\src/h1.h:11:8: note: no corresponding field here

struct X

^

ODR-CHECK

30

ИТ

• PoC: https://github.com/prograholic/clang/tree/odr-check

• Production Ready (milestone: check tool on some Boost libraries) • Memory consumption (huge ASTs)

• Minimize import amount (static, unnamed namespaces, templates)

•Merge changes to clang/master

LET'S TALK? mail: [email protected]

twitter: @prograholic

https://github.com/prograholic/odr-check

https://github.com/prograholic/clang/tree/odr-check