├── DocOfSTA ├── readme.md ├── 工作日志.pdf ├── 系统构成和文件解释说明.pdf └── 面向软件安全的污点数据检测系统安装与使用说明.pdf ├── Documents ├── 131220097 │ └── 20160508实验进度 ├── 131220109 │ ├── 20160515实验进展.docx │ ├── 20160602周进展 │ ├── 20160510周例会报告 │ ├── 20160520实验进展 │ ├── 20160508实验进展.docx │ ├── 20160508实验进展.doc │ └── README ├── 131220110 │ ├── 20160508实验进展 │ └── 20150515周进展 ├── 131220113 │ ├── 7_12_计划 │ ├── 20160510实验进展.txt │ ├── 20160602实验进展 │ └── 2016518实验进展 ├── 第四组第一周项目进展报告.pptx ├── 20160602周例会报告 └── 20160518周例会报告 ├── ASTReader ├── CMakeLists.txt ├── TCI.h ├── TaintedStmtAnalysis.h ├── Tout.h ├── CFGtattr.h ├── tinyxmlerror.cpp ├── tinystr.cpp ├── callgraph.h ├── AST.cpp ├── AST.h ├── tmap.h ├── Tout.cpp ├── tinystr.h ├── CFGtattr.cpp ├── callgraph.cpp ├── ASTReader.cpp ├── tmap.cpp ├── TaintedStmtAnalysis.cpp └── tinyxmlparser.cpp ├── README.md └── 软件需求说明 /DocOfSTA/readme.md: -------------------------------------------------------------------------------- 1 | 本文件夹下的文件均为STA(StaticTaintedAnalysis)系统相关的文件 2 | 文件类型包括:需求、设计、分析测试、用户手册等文件 3 | -------------------------------------------------------------------------------- /DocOfSTA/工作日志.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobuer/StaticTaintAnalysis/HEAD/DocOfSTA/工作日志.pdf -------------------------------------------------------------------------------- /DocOfSTA/系统构成和文件解释说明.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobuer/StaticTaintAnalysis/HEAD/DocOfSTA/系统构成和文件解释说明.pdf -------------------------------------------------------------------------------- /Documents/131220113/7_12_计划: -------------------------------------------------------------------------------- 1 | 1. 完成对classTmap的修改 2 | 2. Tmap的初始化功能完善,对类变量进行classTmap的初始化(可能存在迭代) 3 | 3. 完成对函数迭代调用的调研 4 | -------------------------------------------------------------------------------- /Documents/第四组第一周项目进展报告.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobuer/StaticTaintAnalysis/HEAD/Documents/第四组第一周项目进展报告.pptx -------------------------------------------------------------------------------- /Documents/131220109/20160515实验进展.docx: -------------------------------------------------------------------------------- 1 | 初步完成了污点池头文件以及cpp文件中类定义和成员函数的定义。 2 | 对数组元素的污染情况提出了存储方案,并对此的实现进行了探讨。 3 | 完成了clang编译环境的搭建 4 | -------------------------------------------------------------------------------- /DocOfSTA/面向软件安全的污点数据检测系统安装与使用说明.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobuer/StaticTaintAnalysis/HEAD/DocOfSTA/面向软件安全的污点数据检测系统安装与使用说明.pdf -------------------------------------------------------------------------------- /Documents/131220113/20160510实验进展.txt: -------------------------------------------------------------------------------- 1 | 在Ubuntu 14.04 LTS环境下配置了实验环境 2 | 软件版本 Clang 3.7.0 3 | CMake 3.5.2 4 | 尝试进行AST的获取和分析 5 | -------------------------------------------------------------------------------- /Documents/131220097/20160508实验进度: -------------------------------------------------------------------------------- 1 | 本周主要做的事情是将本组讨论的代码总体框架进行了更精确的细化,并且做了会议记录,然后为了更好地支持本项目的完善,将本项目的相关论文进行了阅读,并且给出了综述文档,然后还调研了软件工程标准的其中一个。 2 | -------------------------------------------------------------------------------- /Documents/131220113/20160602实验进展: -------------------------------------------------------------------------------- 1 | 1. 进行了项目的报告 2 | 2. 已经完成了Callgraph的编写,可以被调用。 3 | 3. 需要的新的节点类型待小组成员需要使用时提出添加进ASTReader.h 4 | 4. 接下来进行函数间调用分析 5 | -------------------------------------------------------------------------------- /Documents/131220109/20160602周进展: -------------------------------------------------------------------------------- 1 | 一、项目进展 2 | 1.完成了污点池以及污染表的设计 3 | 2.能够扫描AST中的变量定义节点,并添加到map结构中 4 | 5 | 二、下周计划 6 | 1.实现控制流图的基本分析 7 | 2.实现与框架代码的交互 8 | -------------------------------------------------------------------------------- /Documents/20160602周例会报告: -------------------------------------------------------------------------------- 1 | 1. 目前完成了框架,可以调用的节点类型有:FunctionDecl,CallExpr,Variable 2 | 2. 更新任务分工: 3 | 徐有健:函数间调用 4 | 欧锦荣:控制流 5 | 胡雄博:赋值语句 6 | 李珺:控制流(某类型语句,李欧协调) 7 | 3. 下周前任务: 8 | 提出新的需求,各模块间,编码进行 9 | -------------------------------------------------------------------------------- /ASTReader/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_LINK_COMPONENTS support) 2 | 3 | add_clang_executable(astreader 4 | ASTReader.cpp 5 | ) 6 | target_link_libraries(astreader 7 | clangTooling 8 | clangBasic 9 | clangASTMatchers 10 | ) 11 | -------------------------------------------------------------------------------- /Documents/131220113/2016518实验进展: -------------------------------------------------------------------------------- 1 | 由于Ubuntu下代码补全不够好,该为在windows下进行实验 2 | 重新造Windows7 下配置了实验环境 3 | 版本 Clang3.7.0 4 | CMake 3.5.2 5 | VisualStudio 2013 update4 6 | Python 2.7.11 7 | 8 | 测试编写了ASTReader的Tool,功能是对执行clang -emit-ast xxx.cpp后得到的.ast文件进行读取,输出文件名以测试其正确性。 9 | 成功获取了ast的top decl。 10 | -------------------------------------------------------------------------------- /Documents/131220109/20160510周例会报告: -------------------------------------------------------------------------------- 1 | 一、当前进展回报 2 | 胡雄博:把c++程序中所有的错误类型以及解决方案进行了研究 3 | 徐有健:完成对工程环境的搭建,组织组员搭建了项目环境 4 | 李珺: 5 | 欧锦荣:初步设计了污染池数据结构,对其中存在的污点池存储大小问题以及改进方案向组员提出并展开了讨论 6 | 7 | 二、本周分工 8 | 徐有健:测试调用clang提供的API接口 9 | 欧锦荣:完成污点池头文件和cpp文件编写,协同徐有健研究clang代码及API接口 10 | 李珺:xml输出方式研究 11 | 胡雄博:具体到内存操作函数的源代码进行解读,并进行汇总,分析其中可能产生的错误 12 | 13 | 三、进展总结 14 | 项目进展缓慢,但渐渐步入正轨,代码编写工作开始落实。 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StaticTaintAnalysis 2 | 面向软件安全的污点数据检测系统 3 | 4 | 许多重要软件,如系统软件(如操作系统、编译器)、支撑软件(如开发环境、数据库管理工具、中间件)、应用软件(如文字处理软件、面向领域的应用软件、嵌入式软件),很大部分是用C/C++语言实现的,C/C++语言为了提高效率,为程序员提供了多种机制和API(应用程序接口),当C/C++程序使用外部数据来源,包括文件、网络、环境变量、命令行参数,通过任务的入口函数入参、任意API函数返回值、任意API函数的出参等途径形成污染源,程序中使用这些来自污染源的数据时,需要程序员做出关键决定,如输入合法性检查。程序员的失误或能导致程序的关键部分存在缺陷,在互联网运行场景下,这样的缺陷成为安全漏洞,容易为黑客利用并攻击。 5 | 6 | 本项目的目标是,针对任意C/C++程序,通过静态分析,能够自动检查、识别出工程中的污染源、污点数据,并对使用污点数据作为输入的函数形成污染池,检查程序是否已对这些输入的合法性进行长度、范围的检查。 7 | -------------------------------------------------------------------------------- /Documents/131220109/20160520实验进展: -------------------------------------------------------------------------------- 1 | 存储结构的基本设计 2 | 3 | 一、污点池 4 | 基本设计如上一份报告中所设计的。存储被污染的数据,并允许用户进行查询变量的污染情况或删除特定的元素等操作。 5 | 6 | 二、错误信息表 7 | 用于存储程序运行过程中所识别出的错误信息,最终程序的输出会按照错误信息表中存储的错误信息进行输出。该类中初步构思只需要进行添加信息和打印信息两种操作。计划使用链表结构存储,表为空时头指针为空。 8 | 9 | 三、函数映射表 10 | 通过对call graph的分析后确定的函数间调用关系后,将调用函数时实参的污染情况对返回值的污染对应用一系列的函数表示出来,并用类进行存储,当以后再调用了该函数时无需重复分析,对于递归函数等较难一步一步进行分析的函数用此方法也较为合理。 11 | 12 | 四、约束栈 13 | 在函数中遇到数组操作或除法操作等操作的时候,需要在函数中寻找是否有对除数,或数组下表中的表达式进行过判断。约束栈则用于存储在该操作前进行过的所有的条件判断(if语句,for语句,while语句的判断等),在检测到需要检测是否进行过对应的条件判断。 14 | -------------------------------------------------------------------------------- /Documents/131220110/20160508实验进展: -------------------------------------------------------------------------------- 1 | 5月第1周 污点数据传播的几种方式以及预计解决办法 2 | 3 | 1. 污点数据作除模操作 4 | a) 从程序入口开始,遍历CFG的每一个基本块,分析污染性质,如果除数可能=0,则警告 5 | 2. 污点数据作数组下标 6 | a) 采用数据流操作,检测所有到达数组表达式A[condition_1][condition_2]···是否进行了数组越界检查 7 | 3. 野指针检测,假设存在内存函数,参数为p 8 | a) 如果p为局部变量且非参数,则检查函数内是否置空 9 | b) 如果p为全局变量,检查限定函数内p是否置空 10 | c) 如果p为函数参数,则p所在的函数在被调用时视为内存释放函数 11 | d) 检测p的别名 12 | e) 隐式释放(p=&a,a被释放) 13 | 4. 污点数据作内存操作length或offset 14 | a) 判断内存操作方式(枚举所有C++语言提供的内存操作函数) 15 | 5. 过程内污点数据传播(主要为赋值操作) 16 | 6. 过程间污点数据传播(参数调用以及返回值) 17 | -------------------------------------------------------------------------------- /ASTReader/TCI.h: -------------------------------------------------------------------------------- 1 | #ifndef TCI_H 2 | #define TCI_H 3 | 4 | #include "AST.h" 5 | #include "tmap.h" 6 | 7 | using namespace clang; 8 | using namespace std; 9 | using namespace llvm; 10 | 11 | //敏感信息类型 12 | #define TTYPE_ARRAY 1 13 | #define TTYPE_DIV_MOD 2 14 | #define TTYPE_LOOP_BOUND 3 15 | #define TTYPE_MEM 4 16 | #define TTYPE_POINTER_NULL_SET 5 17 | #define TTYPE_RECURSIVE_CALL 6 18 | 19 | typedef struct 20 | { 21 | ASTContext* astcontext; 22 | int type; 23 | const VarDecl* vd; 24 | const Expr* expr; 25 | Tainted_Attr* re; 26 | FunctionDecl* fd; 27 | }TCI; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /Documents/20160518周例会报告: -------------------------------------------------------------------------------- 1 | 一、提出问题 2 | 1) 就数组中某个元素的污染情况该如何存储提出了建议 3 | 解决方案:暂时不考虑此情况,归结到更深粒度的检测,在完成了基础功能后再进行考虑 4 | 2) 如何在识别到某类型语句时找到在该语句之前的条件判断 5 | 解决方案:添加一个名为约束栈的类来存储到该语句前进行过的所有有效的条件判断,当需要判断某一表达式使用前是否经过条件判断时,在栈中进行一定深度的查找 6 | 3) 在不清楚传递小组成员所编写到每个模块(函数)中的参数的类型是什么的情况下无法完成小组成员对应模块的工作 7 | 解决方案:小组成员各自对clang生成的语法树必须要有一定程度的理解,传递到小组成员模块中的变量将是语法树中的一个节点 8 | 9 | 二、上周实验进展 10 | 徐有健:在windows下重新配置了环境,并且成功运行了ASTReader,读取.ast文件获取语法树信息 11 | 欧锦荣:完成了污点池结构的初步编写,发现了其中可能存在的问题以及可以改善的部分,初步对错误信息表的实现进行了构思 12 | 胡雄博:具体分析了污染的传播方案,对C++语言中可能造成的不安全使用现象进行了分析汇总 13 | 李珺:对xml输出结构进行了研究,并向项目组成员提出实现方案 14 | 15 | 三、本周目标 16 | 小组:完成小组成员的项目环境搭建,统一框架代码设计,确定重要的类的名称等概念 17 | 徐有健:给小组成员配置环境,继续给ASTReader添加功能 18 | 欧锦荣:对新提出的数据结构(错误信息表、约束栈、函数污染表)进行设计 19 | 胡雄博:获取AST树节点的结构 20 | 李珺:对xml输出模块进行设计 21 | -------------------------------------------------------------------------------- /Documents/131220109/20160508实验进展.docx: -------------------------------------------------------------------------------- 1 | 完成完成了污点池类结构初步设计 2 | 3 | 一、 链表节点结构TaintedNode 4 | char name[20]; //用于存储变量名 5 | int lineno; //用于存储该变量被污染时所在的行号 6 | int field; //用于存储变量作用域,变量类型有待商讨 7 | TaintedNode *next; //指向下一个节点的指针 8 | 作为污点池中存储的元素的最小单位,计划使用开散列的形式存储被污染变量。 9 | 10 | 二、 污点池类TaintedPool 11 | 类成员 12 | TaintedNode *table[HASHSIZE]; //private类型变量,用于存储被污染变量的开散列表,大小待定 13 | 成员函数 14 | TaintedNode *checkid(char str[]); //查找名字为str的变量是否在污染池中,如果存在则返回//该变量在污染池中的指针,否则返回空,成员属性为public 15 | TaintedNode *insertnode(char str[]); //将名字为str的变量插入到污染池中,插入成功后返回指//向该新节点的指针,否则返回NULL,成员属性为public 16 | //调用该函数时会自动调用checkid()函数 17 | void deletenode(char str[]); //将名字为str的节点从污染池中删除,成员属性为public 18 | void printtable( ); //打印污染池中的内容,成员属性为public 19 | 污点池类,该类为程序中存储被污染的变量的数据结构,考虑到某个变量被污染后再被未被污染的变量赋值的情况,除了查找插入打印操作外,引入了删除操作。 20 | -------------------------------------------------------------------------------- /Documents/131220109/20160508实验进展.doc: -------------------------------------------------------------------------------- 1 | 完成了污点池类结构初步设计 2 | 3 | 一、 链表节点结构TaintedNode 4 | char name[20]; //用于存储变量名 5 | int lineno; //用于存储该变量被污染时所在的行号 6 | int field; //用于存储变量作用域,变量类型有待商讨 7 | TaintedNode *next; //指向下一个节点的指针 8 | 作为污点池中存储的元素的最小单位,计划使用开散列的形式存储被污染变量。 9 | 10 | 二、 污点池类TaintedPool 11 | 类成员 12 | TaintedNode *table[HASHSIZE]; //private类型变量,用于存储被污染变量的开散列表,大小待定 13 | 成员函数 14 | TaintedNode *checkid(char str[]); //查找名字为str的变量是否在污染池中,如果存在则返回//该变量在污染池中的指针,否则返回空,成员属性为public 15 | TaintedNode *insertnode(char str[]); //将名字为str的变量插入到污染池中,插入成功后返回指//向该新节点的指针,否则返回NULL,成员属性为public 16 | //调用该函数时会自动调用checkid()函数 17 | void deletenode(char str[]); //将名字为str的节点从污染池中删除,成员属性为public 18 | void printtable( ); //打印污染池中的内容,成员属性为public 19 | 污点池类,该类为程序中存储被污染的变量的数据结构,考虑到某个变量被污染后再被未被污染的变量赋值的情况,除了查找插入打印操作外,引入了删除操作。 20 | 21 | -------------------------------------------------------------------------------- /Documents/131220109/README: -------------------------------------------------------------------------------- 1 | 指针的不同情况操作如下,还有其他情况的话再说 2 | void f() 3 | { 4 | Tainted_Attr *ptr_p, *ptr_a;//分别存了p和a的污染状况 5 | 6 | //p = &a;(p为指针,a为一般变量) 7 | 8 | ptr_p->~Tainted_Attr(); 9 | ptr_p->setType(TYPE_POINTER); 10 | ptr_p->setPointer(ptr_a); //会自动将p的污染属性设置为与a相同,且指针会指向a的条目 11 | 12 | 13 | //p = p + 1;(指针指向了下一个位置) 14 | if (ptr_p->getistemp() == false)//不是动态创建的变量 15 | ptr_p->setPointer(NULL);//将指针从本来指向的内存移开 16 | else 17 | ptr_p->settemp(false); 18 | 19 | 20 | //a = (*p) + b;(a,b为变量,p为指针) 21 | ptr_p->getPointerAttr(); //取得指向的变量的污染条目,之后用这个条目与b的取并 22 | 23 | //*p = a + b; 24 | ptr_p->getPointerAttr(); //取得指向的变量的污染条目,之后操作与一般变量相同 25 | 26 | //p = new int;(例如p指向了动态变量) 27 | Tainted_Attr *temp = new Tainted_Attr(); 28 | ptr_p->~Tainted_Attr(); 29 | ptr_p->setType(TYPE_POINTER); 30 | ptr_p->settemp(true); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Documents/131220110/20150515周进展: -------------------------------------------------------------------------------- 1 | 污点数据检测方案 2 | 1. 污点数据作除模操作 3 | a) 对所有exp添加两种属性,分别是类型属性和是否可能 == 0的属性,在做(/)和(%)操作时对该属性进行检测并报错。 4 | b) 若右值被污染或未被污染但是除模数可能为0则左值记为污染。 5 | 2. 污点数据作数组下标 6 | a) 采用数据流操作,检测所有到达数组表达式A[condition_1][condition_2]···是否进行了数组越界检查 7 | 3. 野指针检测,假设存在内存函数,参数为p 8 | a) 如果p为局部变量且非参数,则检查函数内是否置空 9 | b) 如果p为全局变量,检查限定函数内p是否置空 10 | c) 如果p为函数参数,则p所在的函数在被调用时视为内存释放函数 11 | d) 检测p的别名 12 | e) 隐式释放(p=&a,a被释放) 13 | 4. 污点数据作内存操作length或offset 14 | a) 判断内存操作方式,遇到内存操作函数即进行检验 15 | b) C++内存操作函数如下 16 | i. void * memcpy ( void * destination, const void * source, size_t num ) 17 | ii. void * memmove ( void * destination, const void * source, size_t num ) 18 | iii. void * memset ( void * ptr, int value, size_t num ); 19 | iv. void * memchr ( void * ptr, int value, size_t num ); 20 | v. int memcmp ( const void * ptr1, const void * ptr2, size_t num ); 21 | 5. 过程内污点数据传播(主要为赋值操作) 22 | 6. 过程间污点数据传播(参数调用以及返回值) 23 | a) 通过CFG将函数之间的调用关系整理成函数关系表,通过查表获取参数与返回值之间的污染关系 24 | -------------------------------------------------------------------------------- /ASTReader/TaintedStmtAnalysis.h: -------------------------------------------------------------------------------- 1 | #ifndef _TAINTED_STMT_ANALYSIS_ 2 | #define _TAINTED_STMT_ANALYSIS_ 3 | #include 4 | #include 5 | #include 6 | 7 | #include "clang/Frontend/ASTUnit.h" 8 | #include "clang/Frontend/CompilerInstance.h" 9 | #include "clang/Basic/FileSystemOptions.h" 10 | #include "clang/AST/RecursiveASTVisitor.h" 11 | #include "clang\Analysis\CFG.h" 12 | #include "callgraph.h" 13 | 14 | using namespace clang; 15 | using namespace llvm; 16 | 17 | 18 | bool checkblock(CFGBlock* cfgb, CTmap &out, callgraph* cg); 19 | bool checkCond(const Stmt* stmt, CTmap &out, callgraph* cg); 20 | int Stmt_analysis(const Stmt* stmt, CTmap &out, callgraph* cg); 21 | Tainted_Attr* Expr_analysis(const Expr* expr, CTmap &out, callgraph* cg); 22 | Tainted_Attr* BinaryOperator_Expr_analysis(const Expr* expr, CTmap &out, callgraph* cg); 23 | Tainted_Attr* CompoundAssignOperator_Expr_analysis(const Expr* expr, CTmap &out, callgraph* cg); 24 | Tainted_Attr* CallExpr_analysis(const Expr* expr, CTmap &out, callgraph* cg); 25 | Tainted_Attr* ArrayExpr_analysis(const Expr* expr, CTmap &out, callgraph* cg); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /ASTReader/Tout.h: -------------------------------------------------------------------------------- 1 | #ifndef TOUT_H 2 | #define TOUT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include"AST.h" 8 | #include"tinyxml.h" 9 | #include"tinystr.h" 10 | using namespace std; 11 | #define TTYPE_ARRAY 1 12 | #define TTYPE_DIV_MOD 2 13 | #define TTYPE_LOOP_BOUND 3 14 | #define TTYPE_MEM 4 15 | #define TTYPE_POINTER_NULL_SET 5 16 | #define TTYPE_RECURSIVE_CALL 6 17 | 18 | class XYJ_table 19 | { 20 | public: 21 | FunctionDecl* fd; 22 | ASTContext* astc; 23 | XYJ_table(){} 24 | XYJ_table(FunctionDecl* f, ASTContext* as) 25 | { 26 | fd = f; 27 | astc = as; 28 | } 29 | }; 30 | 31 | 32 | class Ttable 33 | { 34 | public: 35 | struct Node 36 | { 37 | //char*Tname; 38 | char*Tfile; 39 | char*Tfunction; 40 | char*line; 41 | char*TYPE; 42 | Node * next; 43 | }node; 44 | Ttable(); 45 | ~Ttable(); 46 | void make_node(const VarDecl *p); 47 | // bool insert(const VarDecl *p, int line,string function); 48 | // bool insert(const VarDecl *p,string line,string function,int TYPE); 49 | void insert(string line, string function, int TYPE); 50 | void outTtable(); 51 | bool CreateXmlFile(char*file); 52 | VarDecl * serach(const VarDecl * p); 53 | void listout(); 54 | bool XMLout(string file_addr); 55 | Node * head = NULL; 56 | private: 57 | 58 | 59 | 60 | Node* makeTnode(string& line, string& function, int TYPE); 61 | 62 | Node* exchange(string& line, string& function, int TYPE); 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /ASTReader/CFGtattr.h: -------------------------------------------------------------------------------- 1 | #ifndef _CFGTATTR_H_ 2 | #define _CFGTATTR_H_ 3 | 4 | class callgraph; 5 | class CTmap; 6 | 7 | #include "tmap.h" 8 | #include "AST.h" 9 | #include "callgraph.h" 10 | #include "clang\Analysis\CFG.h" 11 | #include "TaintedStmtAnalysis.h" 12 | #include "Tout.h" 13 | 14 | using namespace std; 15 | using namespace clang; 16 | using namespace llvm; 17 | 18 | //CFG的输入输出类 19 | class CFGInOut{ 20 | private: 21 | //CFG的输入输出 22 | CTmap IN, OUT; 23 | public: 24 | //拷贝构造函数 25 | CFGInOut() 26 | { 27 | } 28 | CFGInOut(CTmap& b) 29 | { 30 | IN.CopyMap(b); 31 | OUT.CopyMap(b); 32 | } 33 | CTmap* GetIN() 34 | { 35 | return &IN; 36 | } 37 | CTmap* GetOUT() 38 | { 39 | return &OUT; 40 | } 41 | void setIO(CTmap &tm) 42 | { 43 | IN.CopyMap(tm); 44 | OUT.CopyMap(tm); 45 | } 46 | }; 47 | 48 | void checkCFG(clang::CFG &cfg, CTmap &tm, callgraph *cg); 49 | void checkTerminator(CFGBlock &cfgb, CTmap &out, callgraph *cg); 50 | 51 | void BuildSecondList(callgraph *caller, callgraph *callee, Tainted_Attr ta[], const int n); 52 | void MsgOutput2Xml(callgraph *cg, Ttable &tt); 53 | 54 | void BuildBlockIoTable(map &block_io_map, clang::CFGBlock *CFGexit, clang::CFGBlock *block, CTmap &tm); 55 | void printBlockMsg(map &block_io_map, clang::CFGBlock *block); 56 | void printiotable(map &block_io_map); 57 | void output2xml(callgraph *cg, CTmap &tm); 58 | #endif 59 | -------------------------------------------------------------------------------- /软件需求说明: -------------------------------------------------------------------------------- 1 | 需求分析 说明书 2 | 项目名称:面向软件安全的污点数据检测系统 3 | 功能点:分析过程间的污点数据传播 4 | 项目成员:徐有健 欧锦荣 胡雄博 李珺 5 | 单位 : 南京大学计算机科学与技术系 6 | 7 | 1 引言 8 | 1.1 编写目的 9 | 本说明书用于污点数据在过程中是通哪些方式传播的 ,预计跟踪规则以及 预计跟踪规则以及 在运行过程中可能遇到的故障和处理方法 。具体内容包括软件结构 ,基本规则 , 协议约定 ,为软件设计和测试提供统一标准 。 10 | 本说明书面向对象为 软件设计人员 以及 软件测试人员 。 11 | 使用对象:面向软件安全的污点数据检测研究整体项目组的其他项目成员。 12 | 1.2 背景 13 | 系统名称:面向软件安全的污点数据检测系统 14 | 项目任务提出者:华为公司 15 | 项目开发者:南京大学计算机系徐有健 欧锦荣 胡雄博 李珺 16 | 用户:软件开发者,维护者 17 | 单位:南京大学计算机系 18 | 背景介绍: 19 | 随着互联网和计算机软件的不断发展,软件的安全性问题得到了多方面的关注。攻击者会针对软件的漏洞进行恶意攻击,破坏软件的正确运行或获取非法的软件授权。因此,开发者们急需一种对软件进行漏洞检测(脆弱性测试)的高效准确的工具,根据检测修改代码,使软件在受到恶意攻击的情形下依然能够继续正确运行及确保软件被在授权范围内合法使用。所以该系统也要从污点数据检测研究开始做起,使得软件开发者和维护者能够高效的使用该系统来检测软件代码中的脆弱部分,以便进行优化。 20 | 1.3 参考资料 21 | a.《软件工程:实践者的研究方法》Roger S. Pressman 著 22 | b.软件文档规范及资料 23 | 2 任务概述 24 | 2.1 目标 25 | 1.根据上一模块,即判定污染源数据模块的结果,标记污染源 26 | 2.跟踪污染数据的传播路径,并检测出所有被传染得数据以及相关语句 27 | 3.对于跟踪污染源,编写系统调用的跟踪分析污点数据在过程间传播的模块代码 28 | 4.将检测结果汇总并提交至下一模块 29 | 2.2 用户的特点 30 | 规模较大的工程师团队,团队成员对于负责的设计有相应的水平,拥有较强的专业技术知识,但总体水平存在参差不齐的问题。 31 | 使用软件频度估计在1次/周到1次/月左右,每次使用允许软件运行5-6个小时。 32 | 2.3 假定和约束 33 | 假定:用户使用的开发语言稳定且代码规模不出现大的波动 34 | 约束:1. 污点数据传播的全面性约束 35 | 2. 项目的开发期限 36 | 3. 经费约束 37 | 3 用户描述 38 | 3.1 用户分类 39 | 软件开发者 40 | 软件维护者 41 | 软件测试者 42 | 3.2 用户说明 43 | 1. 软件测试者根据软件需求说明书对工程进行检测,根据运行结果进行汇总,评估测试结果并提供专业意见。 44 | 2. 软件开发者和软件维护者根据汇总结果检查代码段,参考测试意见对代码的薄弱处进行有效的代码改进,并对改进过的代码再次进行污点数据检测。 45 | 4 需求规定 46 | 4.1 对功能的规定 47 | 1. 要求对过程间的污点数据传播进行全面的分析,完成的模块代码能够正确的跟踪污点数据的过程间传播。允许使用者规定检测的粒度大小,以控制运行时间。 48 | 2. 对于给定的污染源能够判别出所有被该污染源污染的数据,并且判定语句是否具有污染检测的功能。若语句不具有污染检测的功能,则返回所在语句的位置 49 | 4.2对性能的规定 50 | 1. 时间特性要求:运行时间<12小时(基于通讯公司的情况) 51 | 2. 精确度:应精确到所在函数的行数 52 | 4.3输入输出要求 53 | 1. 输入:抽象的语法树,函数调用关系图,所有的过程信息,包括各个过程的参数以及返回参数 54 | 2. 输出:修改污染池中的内容,污染位置对应的代码行数,生成XML信息 55 | 4.4数据管理能力要求 56 | 要求有读取和存储过万行代码的能力。要求系统运行的硬件要求在合理范围内,系统维护污染池,必须控制污染池的大小。 57 | 4.5故障处理要求 58 | 1. 应对不同故障类型,自动选择跳过继续执行或者中止执行 59 | 2. 向用户发送错误报告,其中需要包含故障的种类,处理方法等信息。 60 | 5 运行环境规定 61 | 5.1 设备 62 | 应对不同的工程规模,设备要求不同,一般为普通PC 63 | 5.2 系统与软件要求 64 | a.操作系统:各版本Linux系统 65 | b.编译器及其他:Clang 66 | -------------------------------------------------------------------------------- /ASTReader/tinyxmlerror.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | www.sourceforge.net/projects/tinyxml 3 | Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any 7 | damages arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any 10 | purpose, including commercial applications, and to alter it and 11 | redistribute it freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must 14 | not claim that you wrote the original software. If you use this 15 | software in a product, an acknowledgment in the product documentation 16 | would be appreciated but is not required. 17 | 18 | 2. Altered source versions must be plainly marked as such, and 19 | must not be misrepresented as being the original software. 20 | 21 | 3. This notice may not be removed or altered from any source 22 | distribution. 23 | */ 24 | 25 | #include "tinyxml.h" 26 | 27 | // The goal of the seperate error file is to make the first 28 | // step towards localization. tinyxml (currently) only supports 29 | // english error messages, but the could now be translated. 30 | // 31 | // It also cleans up the code a bit. 32 | // 33 | 34 | const char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] = 35 | { 36 | "No error", 37 | "Error", 38 | "Failed to open file", 39 | "Error parsing Element.", 40 | "Failed to read Element name", 41 | "Error reading Element value.", 42 | "Error reading Attributes.", 43 | "Error: empty tag.", 44 | "Error reading end tag.", 45 | "Error parsing Unknown.", 46 | "Error parsing Comment.", 47 | "Error parsing Declaration.", 48 | "Error document empty.", 49 | "Error null (0) or unexpected EOF found in input stream.", 50 | "Error parsing CDATA.", 51 | "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.", 52 | }; 53 | -------------------------------------------------------------------------------- /ASTReader/tinystr.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | www.sourceforge.net/projects/tinyxml 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any 6 | damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any 9 | purpose, including commercial applications, and to alter it and 10 | redistribute it freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must 13 | not claim that you wrote the original software. If you use this 14 | software in a product, an acknowledgment in the product documentation 15 | would be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, and 18 | must not be misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source 21 | distribution. 22 | */ 23 | 24 | 25 | #ifndef TIXML_USE_STL 26 | 27 | #include "tinystr.h" 28 | 29 | // Error value for find primitive 30 | const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); 31 | 32 | 33 | // Null rep. 34 | TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; 35 | 36 | 37 | void TiXmlString::reserve (size_type cap) 38 | { 39 | if (cap > capacity()) 40 | { 41 | TiXmlString tmp; 42 | tmp.init(length(), cap); 43 | memcpy(tmp.start(), data(), length()); 44 | swap(tmp); 45 | } 46 | } 47 | 48 | 49 | TiXmlString& TiXmlString::assign(const char* str, size_type len) 50 | { 51 | size_type cap = capacity(); 52 | if (len > cap || cap > 3*(len + 8)) 53 | { 54 | TiXmlString tmp; 55 | tmp.init(len); 56 | memcpy(tmp.start(), str, len); 57 | swap(tmp); 58 | } 59 | else 60 | { 61 | memmove(start(), str, len); 62 | set_size(len); 63 | } 64 | return *this; 65 | } 66 | 67 | 68 | TiXmlString& TiXmlString::append(const char* str, size_type len) 69 | { 70 | size_type newsize = length() + len; 71 | if (newsize > capacity()) 72 | { 73 | reserve (newsize + capacity()); 74 | } 75 | memmove(finish(), str, len); 76 | set_size(newsize); 77 | return *this; 78 | } 79 | 80 | 81 | TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) 82 | { 83 | TiXmlString tmp; 84 | tmp.reserve(a.length() + b.length()); 85 | tmp += a; 86 | tmp += b; 87 | return tmp; 88 | } 89 | 90 | TiXmlString operator + (const TiXmlString & a, const char* b) 91 | { 92 | TiXmlString tmp; 93 | TiXmlString::size_type b_len = static_cast( strlen(b) ); 94 | tmp.reserve(a.length() + b_len); 95 | tmp += a; 96 | tmp.append(b, b_len); 97 | return tmp; 98 | } 99 | 100 | TiXmlString operator + (const char* a, const TiXmlString & b) 101 | { 102 | TiXmlString tmp; 103 | TiXmlString::size_type a_len = static_cast( strlen(a) ); 104 | tmp.reserve(a_len + b.length()); 105 | tmp.append(a, a_len); 106 | tmp += b; 107 | return tmp; 108 | } 109 | 110 | 111 | #endif // TIXML_USE_STL 112 | -------------------------------------------------------------------------------- /ASTReader/callgraph.h: -------------------------------------------------------------------------------- 1 | #ifndef CALLGRAPH_H 2 | #define CALLGRAPH_H 3 | 4 | class CFGInOut; 5 | 6 | #include 7 | #include "AST.h" 8 | #include "CFGtattr.h" 9 | #include "TCI.h" 10 | #include "Tout.h" 11 | 12 | using namespace std; 13 | using namespace clang; 14 | 15 | extern vector Callgraph; 16 | extern Ttable t_table; 17 | extern std::vector*> xyj_table; 18 | 19 | typedef enum 20 | { 21 | common, inclass 22 | }methodType; 23 | 24 | //函数调用关系图 25 | class callgraph{ 26 | public: 27 | callgraph(FunctionDecl* f1); 28 | callgraph(FunctionDecl* f1, FunctionDecl* f2); 29 | ~callgraph(); 30 | //调用cur的函数 31 | std::vector& getCaller(); 32 | //被cur调用的函数 33 | std::vector& getCallee(); 34 | FunctionDecl* getCur(); 35 | int getCallerNum(); 36 | int getCalleeNum(); 37 | void addCaller(FunctionDecl* otherFD); 38 | void addCallee(FunctionDecl* otherFD,CallExpr* expr); 39 | void delCallee(FunctionDecl* otherFD); 40 | void delCaller(FunctionDecl* otherFD); 41 | void changeMethodType(); 42 | void setRoot(VarDecl* r); 43 | void setClass(CXXRecordDecl* rd); 44 | CXXRecordDecl* getClass(); 45 | VarDecl* getRoot(); 46 | methodType getMethodType(); 47 | bool is_caller(const FunctionDecl* fd); 48 | bool is_callee(const FunctionDecl* fd); 49 | 50 | public: 51 | std::unique_ptr& get_cfg(); 52 | void print_cfg(); 53 | CTmap& getCTmap(); 54 | void addParam(VarDecl* vd); 55 | void addVar(VarDecl* vd); 56 | int getParamNum(); 57 | int getVarNum(); 58 | Tainted_Attr* get_return(); 59 | void set_return(Tainted_Attr* temp); 60 | void set_if_check_cfg(); 61 | bool get_if_check_cfg(); 62 | unsigned get_return_relation(); 63 | bool set_return_relation(int i); 64 | int get_param_no(const VarDecl* vd); 65 | void set_ASTContext(ASTContext* astcontext); 66 | SourceManager& getSourceManager(); 67 | ASTContext* getASTContext(); 68 | std::map& get_call_map(); 69 | 70 | public: 71 | std::map block_io_map; 72 | vector TCI_list; 73 | vector TCI_list_call; 74 | int ifCheck; 75 | 76 | private: 77 | //方法的类型 78 | methodType type; 79 | //类方法所属的实例 80 | VarDecl* root; 81 | CXXRecordDecl* classDecl; 82 | std::vector caller; 83 | FunctionDecl* cur; 84 | std::vector callee; 85 | std::map call_map; 86 | std::unique_ptr cfg; 87 | int callerNum, calleeNum; 88 | vector map_param; 89 | CTmap* map; 90 | int paramNum; 91 | int varNum; 92 | Tainted_Attr* return_tattr; 93 | unsigned return_relation; 94 | bool if_check_cfg; 95 | ASTContext* astcontext; 96 | }; 97 | 98 | callgraph* findById(std::vector Callgraph, std::string id); 99 | void ringCheck(std::vector cg, callgraph* t); 100 | void resetIfCheck(std::vectorCallgraph); 101 | void getRing(std::vector& Callgraph, int n, std::vector& ringVector); 102 | void printCallGraph(); 103 | 104 | bool if_find_function(std::vector Callgraph,FunctionDecl* fd); 105 | #endif 106 | -------------------------------------------------------------------------------- /ASTReader/AST.cpp: -------------------------------------------------------------------------------- 1 | #include "AST.h" 2 | //ASTFunctionLoad 3 | void ASTFunctionLoad::HandleTranslationUnit(ASTContext &Context){ 4 | TranslationUnitDecl *D = Context.getTranslationUnitDecl(); 5 | TraverseDecl(D); 6 | } 7 | 8 | bool ASTFunctionLoad::VisitFunctionDecl(FunctionDecl *FD) { 9 | if (FD && FD->isThisDeclarationADefinition()) { 10 | 11 | if (dyn_cast(FD) != nullptr) 12 | { 13 | functions.push_back(FD); 14 | } 15 | // Add C non-inline function 16 | if (!FD->isInlined()){ 17 | functions.push_back(FD); 18 | } 19 | } 20 | return true; 21 | } 22 | 23 | const std::vector &ASTFunctionLoad::getFunctions() const 24 | { 25 | return functions; 26 | } 27 | 28 | //ASTGlobalVarDeclLoad 29 | void ASTGlobalVarDeclLoad::HandleTranslationUnit(ASTContext &Context) 30 | { 31 | TranslationUnitDecl *D = Context.getTranslationUnitDecl(); 32 | TraverseDecl(D); 33 | } 34 | 35 | bool ASTGlobalVarDeclLoad::VisitGlobalVarDecl(VarDecl *VD) 36 | { 37 | globalVars.push_back(VD); 38 | return true; 39 | } 40 | 41 | const std::vector& ASTGlobalVarDeclLoad::getGlobalVarDecls() const 42 | { 43 | return globalVars; 44 | } 45 | 46 | 47 | //ASTCalledFunctionLoad 48 | bool ASTCalledFunctionLoad::VisitCallExpr(CallExpr *E) { 49 | if (FunctionDecl *FD = E->getDirectCallee()) { 50 | functions.push_back(FD); 51 | } 52 | return true; 53 | } 54 | 55 | const std::vector& ASTCalledFunctionLoad::getFunctions() { 56 | return functions; 57 | } 58 | 59 | //ASTCallExprLoad 60 | bool ASTCallExprLoad::VisitCallExpr(CallExpr *E) { 61 | call_exprs.push_back(E); 62 | return true; 63 | } 64 | 65 | const std::vector& ASTCallExprLoad::getCallExprs() { 66 | return call_exprs; 67 | } 68 | 69 | //ASTVarDeclLoad 70 | bool ASTVarDeclLoad::VisitDeclStmt(DeclStmt *S) { 71 | for (auto D : S->decls()) { 72 | if (VarDecl *VD = dyn_cast(D)) { 73 | variables.push_back(VD); 74 | } 75 | } 76 | return true; 77 | } 78 | const std::vector& ASTVarDeclLoad::getVariables() { 79 | return variables; 80 | } 81 | 82 | //ASTCXXRecordLoad 83 | void ASTCXXRecordLoad::HandleTranslationUnit(ASTContext &Context){ 84 | TranslationUnitDecl *D = Context.getTranslationUnitDecl(); 85 | TraverseDecl(D); 86 | } 87 | 88 | bool ASTCXXRecordLoad::VisitCXXRecordDecl(CXXRecordDecl *rd) { 89 | if (rd && rd->isThisDeclarationADefinition()) 90 | { 91 | cxxrds.push_back(rd); 92 | } 93 | return true; 94 | } 95 | 96 | const std::vector& ASTCXXRecordLoad::getClassDecl() { 97 | return cxxrds; 98 | } 99 | 100 | //ASTCXXMethodDecl 101 | bool ASTCXXMethodDeclLoad::VisitCXXMethodDecl(CXXMethodDecl *cxxmd) { 102 | if (cxxmd && cxxmd->isThisDeclarationADefinition()) 103 | { 104 | cxxmds.push_back(cxxmd); 105 | } 106 | return true; 107 | } 108 | 109 | const std::vector& ASTCXXMethodDeclLoad::getCXXMethodDecl() { 110 | return cxxmds; 111 | } 112 | 113 | //ASTFieldDeclLoad 114 | bool ASTFieldDeclLoad::VisitFieldDecl(FieldDecl *fd) 115 | { 116 | fds.push_back(fd); 117 | return true; 118 | } 119 | const std::vector& ASTFieldDeclLoad::getFieldDecl() 120 | { 121 | return fds; 122 | } 123 | -------------------------------------------------------------------------------- /ASTReader/AST.h: -------------------------------------------------------------------------------- 1 | #ifndef AST_H 2 | #define AST_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "clang/Frontend/ASTUnit.h" 9 | #include "clang/Frontend/CompilerInstance.h" 10 | #include "clang/Basic/FileSystemOptions.h" 11 | #include "clang/AST/RecursiveASTVisitor.h" 12 | #include "clang/Analysis/CFG.h" 13 | 14 | #include"tmap.h" 15 | using namespace clang; 16 | using namespace llvm; 17 | //using namespace std; 18 | 19 | //获取Funtion相关语句 20 | class ASTFunctionLoad : public ASTConsumer, public RecursiveASTVisitor < ASTFunctionLoad > { //get functions 21 | 22 | public: 23 | void HandleTranslationUnit(ASTContext &Context) override; 24 | bool VisitFunctionDecl(FunctionDecl *FD); 25 | const std::vector &getFunctions() const; 26 | private: 27 | std::vector functions; 28 | }; 29 | 30 | //获取Funtion相关语句 31 | class ASTGlobalVarDeclLoad : public ASTConsumer, public RecursiveASTVisitor < ASTGlobalVarDeclLoad > { //get functions 32 | 33 | public: 34 | void HandleTranslationUnit(ASTContext &Context) override; 35 | bool VisitGlobalVarDecl(VarDecl *FD); 36 | const std::vector &getGlobalVarDecls() const; 37 | private: 38 | std::vector globalVars; 39 | }; 40 | 41 | //被调用函数 42 | class ASTCalledFunctionLoad : public RecursiveASTVisitor { 43 | public: 44 | bool VisitCallExpr(CallExpr *E); 45 | const std::vector& getFunctions(); 46 | private: 47 | std::vector functions; 48 | }; 49 | 50 | //调用函数语句 51 | class ASTCallExprLoad : public RecursiveASTVisitor { 52 | 53 | public: 54 | bool VisitCallExpr(CallExpr *E); 55 | const std::vector& getCallExprs(); 56 | private: 57 | std::vector call_exprs; 58 | }; 59 | 60 | //变量定义 61 | class ASTVarDeclLoad : public RecursiveASTVisitor { 62 | 63 | public: 64 | bool VisitDeclStmt(DeclStmt *S); 65 | const std::vector& getVariables(); 66 | private: 67 | std::vector variables; 68 | }; 69 | 70 | //获取类decl 71 | class ASTCXXRecordLoad : public ASTConsumer, public RecursiveASTVisitor { 72 | public: 73 | void HandleTranslationUnit(ASTContext &Context) override; 74 | bool VisitCXXRecordDecl(CXXRecordDecl *rd); 75 | const std::vector& getClassDecl(); 76 | 77 | private: 78 | std::vector cxxrds; 79 | }; 80 | 81 | //获取类方法decl 82 | class ASTCXXMethodDeclLoad :public RecursiveASTVisitor { 83 | public: 84 | bool VisitCXXMethodDecl(CXXMethodDecl *rd); 85 | const std::vector& getCXXMethodDecl(); 86 | 87 | private: 88 | std::vector cxxmds; 89 | }; 90 | 91 | //获取类变量decl 92 | class ASTFieldDeclLoad :public RecursiveASTVisitor { 93 | public: 94 | bool VisitFieldDecl(FieldDecl *fd); 95 | const std::vector& getFieldDecl(); 96 | 97 | private: 98 | std::vector fds; 99 | }; 100 | 101 | //获取类构造函数decl 102 | /*class ASTCXXConstructorDeclLoad : public ASTConsumer, public RecursiveASTVisitor { 103 | public: 104 | void HandleTranslationUnit(ASTContext &Context) override { 105 | TranslationUnitDecl *D = Context.getTranslationUnitDecl(); 106 | TraverseDecl(D); 107 | } 108 | 109 | bool VisitClassDecl(CXXConstructorDecl *rd) { 110 | cxxcds.insert(rd); 111 | return true; 112 | } 113 | 114 | const std::vector getClassConstructorDecl() { 115 | return std::vector(cxxcds.begin(), cxxcds.end()); 116 | } 117 | 118 | private: 119 | std::set cxxcds; 120 | };*/ 121 | 122 | 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /ASTReader/tmap.h: -------------------------------------------------------------------------------- 1 | #ifndef _TMAP_H_ 2 | #define _TMAP_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "clang/Frontend/ASTUnit.h" 9 | #include "clang/Frontend/CompilerInstance.h" 10 | #include "clang/Basic/FileSystemOptions.h" 11 | #include "clang/AST/RecursiveASTVisitor.h" 12 | 13 | //#include "Tout.h" 14 | 15 | using namespace std; 16 | using namespace clang; 17 | using namespace llvm; 18 | 19 | class callgraph; 20 | class CTmap; 21 | class classTmap; 22 | extern std::vector ClassTmap; 23 | 24 | //污染情况 25 | typedef enum{ 26 | TAINTED, 27 | UNTAINTED, 28 | RELATED 29 | }e_tattr; 30 | 31 | //变量的类型,供tmap使用 32 | typedef enum{ 33 | TYPE_VARIABLE, //变量 34 | TYPE_CLASS, //类 35 | TYPE_POINTER, //指针 36 | TYPE_UNKNOWN //未知 37 | }VarDeclType; 38 | 39 | typedef enum{ 40 | U2T, 41 | T2U, 42 | OTHER 43 | }MessageType; 44 | 45 | void printClassTmap(std::vector CT); 46 | bool if_find_class(std::vectorClassTmap, CXXRecordDecl* rd); 47 | classTmap* getClassTmap(CXXRecordDecl* rd); 48 | 49 | //变量的污染属性 50 | class Tainted_Attr 51 | { 52 | private: 53 | VarDeclType type; 54 | 55 | //污染属性 56 | e_tattr attr; 57 | //污染与哪些变量相关 58 | set relation; 59 | 60 | //指向该指针指向的位置的污染状态 61 | Tainted_Attr *ptrAttr; 62 | bool is_temp; 63 | //指向该类的实例的map 64 | classTmap *ptrClassDecl; 65 | 66 | public: 67 | Tainted_Attr(); 68 | Tainted_Attr(VarDeclType mytype, classTmap *ct); 69 | Tainted_Attr(Tainted_Attr& b); 70 | ~Tainted_Attr(); 71 | 72 | /*获取相关的函数*/ 73 | 74 | VarDeclType getType(); 75 | e_tattr getVariableAttr(); 76 | set *getVariableRelation(); 77 | classTmap *getClassDecl(); 78 | Tainted_Attr *getPointerAttr(); 79 | bool getistemp(); 80 | 81 | /*调试相关的函数*/ 82 | void output(); 83 | void copy(Tainted_Attr *p); 84 | 85 | /*属性设置相关的函数*/ 86 | 87 | void settemp(bool b); 88 | void var_attr_set(e_tattr a, const VarDecl *r); 89 | void var_attr_set(e_tattr a, set r); 90 | void class_attr_set(e_tattr a, const VarDecl *r, Expr *ptrExp); 91 | void classmember_set(classTmap *ct); 92 | void pointer_attr_set(e_tattr a, const VarDecl *r); 93 | void setPointer(Tainted_Attr *pt); 94 | void setType(VarDeclType tp); 95 | void unionAttr(Tainted_Attr &a, Tainted_Attr &b); 96 | void unionAttr(Tainted_Attr &a); 97 | bool compareAttr(Tainted_Attr &ta); 98 | }; 99 | 100 | //封装了C++ map模板的污染表类 101 | class CTmap 102 | { 103 | private: 104 | map tmap; 105 | public: 106 | CTmap(); 107 | CTmap(CTmap& b); 108 | ~CTmap(); 109 | void output(); 110 | //void output2xml(callgraph *cg); 111 | void CopyMap(CTmap& b); 112 | void insert(const VarDecl *p); 113 | void del(const VarDecl *p); 114 | Tainted_Attr *getAttr(const VarDecl *vd); 115 | Tainted_Attr *getPointerAttr(const VarDecl *vd); 116 | map::iterator getmap(); 117 | map::iterator getend(); 118 | 119 | classTmap *getClassTmap(const VarDecl *p); 120 | void setType(const VarDecl *p, VarDeclType tp); 121 | void var_attr_set(const VarDecl *p, e_tattr e, const VarDecl *r); 122 | void var_attr_set(const VarDecl *vd, Tainted_Attr *ta); 123 | void ptr_set(const VarDecl *p, Tainted_Attr *tp); 124 | void ptr_attr_set(const VarDecl *p, e_tattr e, const VarDecl *r); 125 | void classmember_attr_set(const VarDecl *p, classTmap *ct); 126 | void classmember_attr_set(const VarDecl *p, e_tattr e, const VarDecl *r, Expr *ptrExpr); 127 | void unionMap(CTmap &b); 128 | void clear(); 129 | const VarDecl *get_VarDecl(int n); 130 | bool compareMap(CTmap &tm); 131 | }; 132 | 133 | //classTmap 134 | class classTmap 135 | { 136 | public: 137 | classTmap(); 138 | void setCXXRecordDecl(CXXRecordDecl* cxxrd); 139 | void addMethod(CXXMethodDecl* md); 140 | void addVar(FieldDecl* fd, VarDeclType evt); 141 | const std::vector& get_cxxmds(); 142 | const std::vector& get_fds(); 143 | CXXRecordDecl* get_cxxrd()const; 144 | int getMethodNum(); 145 | int getVarNum(); 146 | CTmap* getMap(); 147 | 148 | void classCopy(classTmap* temp); 149 | void classUnion(classTmap* m, classTmap* a, classTmap* b); 150 | void classClear(); 151 | 152 | private: 153 | CXXRecordDecl* rd; 154 | std::vector cxxmds; 155 | std::vector fds; 156 | CTmap map; 157 | int methodNum; 158 | int varNum; 159 | //int publicVarNum; 160 | //int privateVarNum; 161 | //int protectedVarNum; 162 | }; 163 | 164 | 165 | 166 | #endif 167 | -------------------------------------------------------------------------------- /ASTReader/Tout.cpp: -------------------------------------------------------------------------------- 1 | #include"Tout.h" 2 | Ttable::Ttable() 3 | { 4 | head = NULL; 5 | 6 | } 7 | Ttable::~Ttable() 8 | { 9 | Node*p = NULL; 10 | while (p == head) 11 | { 12 | p = head; 13 | while (p != NULL) 14 | { 15 | 16 | p = p->next; 17 | } 18 | delete p; 19 | } 20 | } 21 | 22 | bool Ttable::CreateXmlFile(char*file) 23 | { 24 | 25 | 26 | 27 | 28 | //创建一个XML的文档对象。 29 | TiXmlDocument *myDocument = new TiXmlDocument(); 30 | //创建一个根元素并连接。 31 | TiXmlElement *RootElement = new TiXmlElement("Taints"); 32 | myDocument->LinkEndChild(RootElement); 33 | //创建一个Person元素并连接。 34 | Node * p = head; 35 | while(p!=NULL) 36 | { 37 | TiXmlElement *PersonElement = new TiXmlElement("Taint"); 38 | RootElement->LinkEndChild(PersonElement); 39 | //设置Person元素的属性。 40 | //PersonElement->SetAttribute("type", p->Type); 41 | //创建name元素、age元素并连接。 42 | TiXmlElement *NameElement = new TiXmlElement("ID"); 43 | TiXmlElement *AgeElement = new TiXmlElement("line"); 44 | TiXmlElement *functionname = new TiXmlElement("function"); 45 | TiXmlElement *file_name = new TiXmlElement("file"); 46 | PersonElement->LinkEndChild(NameElement); 47 | PersonElement->LinkEndChild(AgeElement); 48 | PersonElement->LinkEndChild(functionname); 49 | PersonElement->LinkEndChild(file_name); 50 | //设置name元素和age元素的内容并连接。 51 | TiXmlText *NameContent = new TiXmlText(p->TYPE); 52 | TiXmlText *AgeContent = new TiXmlText(p->line); 53 | TiXmlText *functname = new TiXmlText(p->Tfunction); 54 | TiXmlText *file_name_1 = new TiXmlText(p->Tfile); 55 | NameElement->LinkEndChild(NameContent); 56 | AgeElement->LinkEndChild(AgeContent); 57 | functionname->LinkEndChild(functname); 58 | file_name->LinkEndChild(file_name_1); 59 | p = p->next; 60 | } 61 | //保存到文件 62 | 63 | 64 | myDocument->SaveFile(file); 65 | return 1; 66 | } 67 | /*输出污染表*/ 68 | void Ttable::outTtable() 69 | { 70 | 71 | } 72 | /*插入节点,对外函数*/ 73 | void Ttable::insert(string line, string function, int TYPE) 74 | { 75 | 76 | 77 | Node *t = makeTnode(line, function, TYPE); 78 | if (head == NULL) 79 | { 80 | 81 | head = t; 82 | head->next = NULL; 83 | } 84 | else 85 | { 86 | 87 | t->next = head; 88 | head = t; 89 | } 90 | return ; 91 | } 92 | Ttable::Node* Ttable::makeTnode(string& line, string& function, int TYPE) 93 | { 94 | 95 | /*--------------------------------*/ 96 | int num = line.find(':', 2); 97 | string test_line; 98 | int num2 = line.find(':', num+1); 99 | test_line.insert(0, line, num + 1, num2); 100 | // cout << test_line << endl; 101 | string test_file; 102 | test_file.insert(0, line, 0, num); 103 | // cout << test_file << endl; 104 | /*以上部分就是将参数line进行解析,得到了代表行号的参数,和文件路径*/ 105 | /*-------------------------------*/ 106 | 107 | //测试 108 | // Node * t = NULL; 109 | // t = exchange(p, line, function); 110 | //将行号转换为char类型 111 | 112 | Node * t = new Node; 113 | /*--------------------------------*/ 114 | t->line = new char[50]; 115 | // sprintf(t->line, "%d", line); 116 | string str_line = test_line; 117 | str_line.copy(t->line, str_line.length(), 0); 118 | *(t->line + str_line.length()) = '\0'; 119 | // cout << t->line << "t->line" << endl; 120 | /*将第一部分解释的行号进行转换,存入节点数据域中*/ 121 | /*-----------------------------------*/ 122 | 123 | //将名字转换为char类型 124 | //cout << p->getQualifiedNameAsString().data()<<" 23333" << endl; 125 | //cout <<(char*) p->getQualifiedNameAsString().data() << " 1111" << endl; 126 | /* 127 | t->Tname = new char[50]; 128 | t->Tname = NULL; 129 | */ 130 | // string test = (char*)p->getQualifiedNameAsString().data(); 131 | //t->Tname = (char*)test.data(); 132 | // test.copy(t->Tname, test.length(), 0); 133 | // *(t->Tname + test.length()) = '\0'; 134 | // cout << t->Tname << " t->Tname" << endl; 135 | //t->Tname = (char*)p->getQualifiedNameAsString().data(); 136 | //cout <Tname <<" 344444" << endl; 137 | /*为什么不用getDeclName函数获取变量的名字呢,huozhe shi p->getNameAsString*/ 138 | //将函数名字转换为char 139 | 140 | //cout << funtion_name << 111212313 << endl; 141 | //t->Tfunction = (char*)funtion_name.data(); 142 | 143 | /*---------------------------------*/ 144 | t->Tfunction = new char[100]; 145 | string funtion_name = function; 146 | funtion_name.copy(t->Tfunction, funtion_name.length(), 0); 147 | *(t->Tfunction + funtion_name.length()) = '\0'; 148 | // cout << t->Tfunction << " Tfunction" << endl; 149 | /*将输入的字符串参数存入节点*/ 150 | /*------------------------------------*/ 151 | 152 | 153 | //通过clang得到了该变量所在的文件名。 154 | // t->Tfile = (char*)p->getASTContext().getSourceManager().getFilename(p->getSourceRange().getBegin()).data(); 155 | 156 | /*----------------------------------------*/ 157 | t->Tfile = new char[500]; 158 | string Tfile_name = test_file; 159 | Tfile_name.copy(t->Tfile, Tfile_name.length(), 0); 160 | *(t->Tfile + Tfile_name.length()) = '\0'; 161 | // cout << t->Tfile << " Tfile" << endl; 162 | /*将文件名存入节点*/ 163 | /*-------------------------------------*/ 164 | 165 | t->TYPE = new char[100]; 166 | if (TYPE == 1) 167 | { 168 | string Type = "TTYPE_ARRAY"; 169 | Type.copy(t->TYPE, Type.length(), 0); 170 | *(t->TYPE + Type.length()) = '\0'; 171 | } 172 | else if (TYPE == 2) 173 | { 174 | string Type = "TTYPE_DIV_MOD"; 175 | Type.copy(t->TYPE, Type.length(), 0); 176 | *(t->TYPE + Type.length()) = '\0'; 177 | } 178 | else if (TYPE == 3) 179 | { 180 | string Type = "TTYPE_LOOP_BOUND"; 181 | Type.copy(t->TYPE, Type.length(), 0); 182 | *(t->TYPE + Type.length()) = '\0'; 183 | } 184 | else if (TYPE == 4) 185 | { 186 | string Type = "TTYPE_MEM"; 187 | Type.copy(t->TYPE, Type.length(), 0); 188 | *(t->TYPE + Type.length()) = '\0'; 189 | } 190 | else if (TYPE == 5) 191 | { 192 | string Type = "TTYPE_POINTER_NULL_SET"; 193 | Type.copy(t->TYPE, Type.length(), 0); 194 | *(t->TYPE + Type.length()) = '\0'; 195 | } 196 | else if (TYPE == 6) 197 | { 198 | string Type = "TTYPE_RECURSIVE_CALL"; 199 | Type.copy(t->TYPE, Type.length(), 0); 200 | *(t->TYPE + Type.length()) = '\0'; 201 | } 202 | 203 | return t; 204 | 205 | } 206 | Ttable::Node* Ttable::exchange(string& line, string& function, int TYPE) 207 | { 208 | //将行号转换为char类型 209 | Node * t = new Node; 210 | t->line = new char[50]; 211 | sprintf(t->line, "%d", line); 212 | //将名字转换为char类型 213 | // t->Tname = (char*)p->getQualifiedNameAsString().data(); 214 | /*为什么不用getDeclName函数获取变量的名字呢,huozhe shi p->getNameAsString*/ 215 | //将函数名字转换为char 216 | t->Tfunction = (char*)function.data(); 217 | //通过clang得到了该变量所在的文件名。 218 | // t->Tfile = (char*)p->getASTContext().getSourceManager().getFilename(p->getSourceRange().getBegin()).data(); 219 | return t; 220 | 221 | } 222 | void Ttable::listout() 223 | { 224 | 225 | Node * t = NULL; 226 | t = head; 227 | while (t != NULL) 228 | { 229 | 230 | //cout << t->Tname << endl; 231 | cout << t->line << endl; 232 | cout << t->Tfunction << endl; 233 | cout << t->Tfile << endl; 234 | cout << endl; 235 | t = t->next; 236 | } 237 | } 238 | bool Ttable::XMLout(string file_addr) 239 | { 240 | 241 | if (head == NULL) 242 | { 243 | cout << "Ttable is null!" << endl; 244 | 245 | return 0; 246 | } 247 | else 248 | { 249 | char * file = (char*)file_addr.data(); 250 | //char *file = "C:/Users/dell/Desktop/111/Warning%d.XML"; 251 | char * f = NULL; 252 | int i = 1; 253 | Node*p = head; 254 | CreateXmlFile(file); 255 | /* 256 | while (p != NULL) 257 | { 258 | //cout << i << endl; 259 | f = new char[50]; 260 | sprintf(f, file, i); 261 | CreateXmlFile(p, f); 262 | i++; 263 | p = p->next; 264 | } 265 | */ 266 | return 1; 267 | } 268 | 269 | } 270 | -------------------------------------------------------------------------------- /ASTReader/tinystr.h: -------------------------------------------------------------------------------- 1 | /* 2 | www.sourceforge.net/projects/tinyxml 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any 6 | damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any 9 | purpose, including commercial applications, and to alter it and 10 | redistribute it freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must 13 | not claim that you wrote the original software. If you use this 14 | software in a product, an acknowledgment in the product documentation 15 | would be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, and 18 | must not be misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source 21 | distribution. 22 | */ 23 | 24 | 25 | #ifndef TIXML_USE_STL 26 | 27 | #ifndef TIXML_STRING_INCLUDED 28 | #define TIXML_STRING_INCLUDED 29 | 30 | #include 31 | #include 32 | 33 | /* The support for explicit isn't that universal, and it isn't really 34 | required - it is used to check that the TiXmlString class isn't incorrectly 35 | used. Be nice to old compilers and macro it here: 36 | */ 37 | #if defined(_MSC_VER) && (_MSC_VER >= 1200 ) 38 | // Microsoft visual studio, version 6 and higher. 39 | #define TIXML_EXPLICIT explicit 40 | #elif defined(__GNUC__) && (__GNUC__ >= 3 ) 41 | // GCC version 3 and higher.s 42 | #define TIXML_EXPLICIT explicit 43 | #else 44 | #define TIXML_EXPLICIT 45 | #endif 46 | 47 | 48 | /* 49 | TiXmlString is an emulation of a subset of the std::string template. 50 | Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. 51 | Only the member functions relevant to the TinyXML project have been implemented. 52 | The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase 53 | a string and there's no more room, we allocate a buffer twice as big as we need. 54 | */ 55 | class TiXmlString 56 | { 57 | public : 58 | // The size type used 59 | typedef size_t size_type; 60 | 61 | // Error value for find primitive 62 | static const size_type npos; // = -1; 63 | 64 | 65 | // TiXmlString empty constructor 66 | TiXmlString () : rep_(&nullrep_) 67 | { 68 | } 69 | 70 | // TiXmlString copy constructor 71 | TiXmlString ( const TiXmlString & copy) : rep_(0) 72 | { 73 | init(copy.length()); 74 | memcpy(start(), copy.data(), length()); 75 | } 76 | 77 | // TiXmlString constructor, based on a string 78 | TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) 79 | { 80 | init( static_cast( strlen(copy) )); 81 | memcpy(start(), copy, length()); 82 | } 83 | 84 | // TiXmlString constructor, based on a string 85 | TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) 86 | { 87 | init(len); 88 | memcpy(start(), str, len); 89 | } 90 | 91 | // TiXmlString destructor 92 | ~TiXmlString () 93 | { 94 | quit(); 95 | } 96 | 97 | TiXmlString& operator = (const char * copy) 98 | { 99 | return assign( copy, (size_type)strlen(copy)); 100 | } 101 | 102 | TiXmlString& operator = (const TiXmlString & copy) 103 | { 104 | return assign(copy.start(), copy.length()); 105 | } 106 | 107 | 108 | // += operator. Maps to append 109 | TiXmlString& operator += (const char * suffix) 110 | { 111 | return append(suffix, static_cast( strlen(suffix) )); 112 | } 113 | 114 | // += operator. Maps to append 115 | TiXmlString& operator += (char single) 116 | { 117 | return append(&single, 1); 118 | } 119 | 120 | // += operator. Maps to append 121 | TiXmlString& operator += (const TiXmlString & suffix) 122 | { 123 | return append(suffix.data(), suffix.length()); 124 | } 125 | 126 | 127 | // Convert a TiXmlString into a null-terminated char * 128 | const char * c_str () const { return rep_->str; } 129 | 130 | // Convert a TiXmlString into a char * (need not be null terminated). 131 | const char * data () const { return rep_->str; } 132 | 133 | // Return the length of a TiXmlString 134 | size_type length () const { return rep_->size; } 135 | 136 | // Alias for length() 137 | size_type size () const { return rep_->size; } 138 | 139 | // Checks if a TiXmlString is empty 140 | bool empty () const { return rep_->size == 0; } 141 | 142 | // Return capacity of string 143 | size_type capacity () const { return rep_->capacity; } 144 | 145 | 146 | // single char extraction 147 | const char& at (size_type index) const 148 | { 149 | assert( index < length() ); 150 | return rep_->str[ index ]; 151 | } 152 | 153 | // [] operator 154 | char& operator [] (size_type index) const 155 | { 156 | assert( index < length() ); 157 | return rep_->str[ index ]; 158 | } 159 | 160 | // find a char in a string. Return TiXmlString::npos if not found 161 | size_type find (char lookup) const 162 | { 163 | return find(lookup, 0); 164 | } 165 | 166 | // find a char in a string from an offset. Return TiXmlString::npos if not found 167 | size_type find (char tofind, size_type offset) const 168 | { 169 | if (offset >= length()) return npos; 170 | 171 | for (const char* p = c_str() + offset; *p != '\0'; ++p) 172 | { 173 | if (*p == tofind) return static_cast< size_type >( p - c_str() ); 174 | } 175 | return npos; 176 | } 177 | 178 | void clear () 179 | { 180 | //Lee: 181 | //The original was just too strange, though correct: 182 | // TiXmlString().swap(*this); 183 | //Instead use the quit & re-init: 184 | quit(); 185 | init(0,0); 186 | } 187 | 188 | /* Function to reserve a big amount of data when we know we'll need it. Be aware that this 189 | function DOES NOT clear the content of the TiXmlString if any exists. 190 | */ 191 | void reserve (size_type cap); 192 | 193 | TiXmlString& assign (const char* str, size_type len); 194 | 195 | TiXmlString& append (const char* str, size_type len); 196 | 197 | void swap (TiXmlString& other) 198 | { 199 | Rep* r = rep_; 200 | rep_ = other.rep_; 201 | other.rep_ = r; 202 | } 203 | 204 | private: 205 | 206 | void init(size_type sz) { init(sz, sz); } 207 | void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } 208 | char* start() const { return rep_->str; } 209 | char* finish() const { return rep_->str + rep_->size; } 210 | 211 | struct Rep 212 | { 213 | size_type size, capacity; 214 | char str[1]; 215 | }; 216 | 217 | void init(size_type sz, size_type cap) 218 | { 219 | if (cap) 220 | { 221 | // Lee: the original form: 222 | // rep_ = static_cast(operator new(sizeof(Rep) + cap)); 223 | // doesn't work in some cases of new being overloaded. Switching 224 | // to the normal allocation, although use an 'int' for systems 225 | // that are overly picky about structure alignment. 226 | const size_type bytesNeeded = sizeof(Rep) + cap; 227 | const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); 228 | rep_ = reinterpret_cast( new int[ intsNeeded ] ); 229 | 230 | rep_->str[ rep_->size = sz ] = '\0'; 231 | rep_->capacity = cap; 232 | } 233 | else 234 | { 235 | rep_ = &nullrep_; 236 | } 237 | } 238 | 239 | void quit() 240 | { 241 | if (rep_ != &nullrep_) 242 | { 243 | // The rep_ is really an array of ints. (see the allocator, above). 244 | // Cast it back before delete, so the compiler won't incorrectly call destructors. 245 | delete [] ( reinterpret_cast( rep_ ) ); 246 | } 247 | } 248 | 249 | Rep * rep_; 250 | static Rep nullrep_; 251 | 252 | } ; 253 | 254 | 255 | inline bool operator == (const TiXmlString & a, const TiXmlString & b) 256 | { 257 | return ( a.length() == b.length() ) // optimization on some platforms 258 | && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare 259 | } 260 | inline bool operator < (const TiXmlString & a, const TiXmlString & b) 261 | { 262 | return strcmp(a.c_str(), b.c_str()) < 0; 263 | } 264 | 265 | inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } 266 | inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } 267 | inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } 268 | inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } 269 | 270 | inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } 271 | inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } 272 | inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } 273 | inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } 274 | 275 | TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); 276 | TiXmlString operator + (const TiXmlString & a, const char* b); 277 | TiXmlString operator + (const char* a, const TiXmlString & b); 278 | 279 | 280 | /* 281 | TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. 282 | Only the operators that we need for TinyXML have been developped. 283 | */ 284 | class TiXmlOutStream : public TiXmlString 285 | { 286 | public : 287 | 288 | // TiXmlOutStream << operator. 289 | TiXmlOutStream & operator << (const TiXmlString & in) 290 | { 291 | *this += in; 292 | return *this; 293 | } 294 | 295 | // TiXmlOutStream << operator. 296 | TiXmlOutStream & operator << (const char * in) 297 | { 298 | *this += in; 299 | return *this; 300 | } 301 | 302 | } ; 303 | 304 | #endif // TIXML_STRING_INCLUDED 305 | #endif // TIXML_USE_STL 306 | -------------------------------------------------------------------------------- /ASTReader/CFGtattr.cpp: -------------------------------------------------------------------------------- 1 | #include"CFGtattr.h" 2 | #include"AST.h" 3 | 4 | //对函数的CFG进行迭代分析 5 | void checkCFG(clang::CFG &cfg, CTmap &tm, callgraph *cg) 6 | { 7 | cg->set_if_check_cfg(); 8 | clang::CFGBlock* CFGentry = &(cfg.getEntry()), *CFGexit = &(cfg.getExit()); 9 | clang::CFGBlock::pred_iterator pred_it, pred_end; 10 | 11 | CTmap *outm = NULL, *inm = NULL, preout; 12 | 13 | 14 | BuildBlockIoTable(cg->block_io_map, CFGexit, CFGentry, tm); 15 | cg->print_cfg(); 16 | //printiotable(block_io_map); 17 | 18 | //主循环,当无OUT发生改变时跳出循环 19 | int i = 1; 20 | while (1) 21 | { 22 | bool changed = false; 23 | 24 | //为每个block计算其新的out 25 | cout << "******************************" << endl; 26 | cout << cg->getCur()->getQualifiedNameAsString() << ": CFG check " << i << " start........." << endl; 27 | for (map::reverse_iterator r_iter = cg->block_io_map.rbegin(), r_end = cg->block_io_map.rend(); r_iter != r_end; r_iter++) 28 | { 29 | //计算新的in,即对block的前驱的out求并,作为该block的in 30 | pred_it = r_iter->first->pred_begin(), pred_end = r_iter->first->pred_end(); 31 | clang::CFGBlock* temp = NULL; 32 | if (r_iter->first != &cfg.getEntry()) 33 | { 34 | inm = r_iter->second.GetIN(); 35 | inm->clear(); 36 | inm->CopyMap(tm); 37 | while (pred_it != pred_end) 38 | { 39 | temp = pred_it->getReachableBlock(); 40 | //cout << "is B" << temp->getBlockID() << endl;; 41 | outm = cg->block_io_map[temp].GetOUT(); 42 | inm->unionMap(*outm); 43 | pred_it++; 44 | } 45 | } 46 | else 47 | { 48 | continue; 49 | } 50 | outm = r_iter->second.GetOUT(); 51 | preout.CopyMap(*outm); 52 | outm->CopyMap(*inm); 53 | 54 | //checkblock, modify changed 55 | checkblock(r_iter->first, *outm,cg); 56 | checkTerminator(*r_iter->first, *outm, cg); 57 | 58 | //if ((*r_iter).first->getTerminatorCondition() == NULL) 59 | //{ 60 | // cout << "B" << (*r_iter).first->getBlockID() << " is NULL" << endl; 61 | //} 62 | 63 | if (outm->compareMap(preout) == false) 64 | { 65 | changed = true; 66 | //printBlockMsg(cg->block_io_map,r_iter->first); 67 | } 68 | 69 | } 70 | 71 | //迭代至所有block的OUT都不发生改变,跳出循环 72 | cout<getCur()->getQualifiedNameAsString() << ": CFG check " << i << " end." << endl; 73 | cout << "******************************" << endl; 74 | if (changed == false) 75 | break; 76 | cg->TCI_list.clear(); 77 | cg->TCI_list_call.clear(); 78 | i++; 79 | } 80 | //here to add output 81 | //printiotable(cg->block_io_map); 82 | 83 | //将函数出口处的tmap填写到callgraph中 84 | cg->getCTmap().CopyMap(*cg->block_io_map[&cfg.getExit()].GetOUT()); 85 | 86 | outm = cg->block_io_map[&cfg.getExit()].GetOUT(); 87 | cout << "check " << cg->getCur()->getQualifiedNameAsString() << " end" << endl<getReachableBlock()->getBlockID()) <= n) 102 | { 103 | const Stmt *stmt = cfgb.getTerminatorCondition(); 104 | checkCond(stmt, out, cg); 105 | } 106 | pred_it++; 107 | } 108 | 109 | } 110 | 111 | Stmt *checkBeforeCond(CFGBlock &cfgb) 112 | { 113 | clang::CFGBlock::pred_iterator pred_it, pred_end; 114 | pred_it = cfgb.pred_begin(); 115 | pred_end = cfgb.pred_end(); 116 | 117 | Stmt *stmt; 118 | 119 | while (pred_it != pred_end) 120 | { 121 | stmt = (*pred_it).getReachableBlock()->getTerminatorCondition(); 122 | if (stmt != NULL) 123 | return stmt; 124 | pred_it++; 125 | } 126 | return NULL; 127 | } 128 | 129 | //ta为参数的污染情况,n为ta数组中元素的个数,该函数用于修改第二个TCI表 130 | void BuildSecondList(callgraph *caller, callgraph *callee, Tainted_Attr ta[], const int n) 131 | { 132 | TCI *temp; 133 | Tainted_Attr *p; 134 | Tainted_Attr *q; 135 | vector::iterator it, it_end; 136 | set::iterator var_it, var_end; 137 | set::iterator var_it2, var_end2; 138 | 139 | int k; 140 | 141 | //g自身的TCI表添加到f中 142 | it = callee->TCI_list.begin(); 143 | it_end = callee->TCI_list.end(); 144 | //cout << 4444 << endl; 145 | while (it != it_end) 146 | { 147 | //cout << 33333 << endl; 148 | temp = new TCI; 149 | temp->astcontext = (*it)->astcontext; 150 | temp->type = (*it)->type; 151 | temp->vd = (*it)->vd; 152 | temp->expr = (*it)->expr; 153 | temp->re = new Tainted_Attr; 154 | temp->re->copy((*it)->re); 155 | temp->fd = (*it)->fd; 156 | 157 | // temp->re->output(); 158 | //int b; 159 | //cin >> b; 160 | 161 | caller->TCI_list_call.insert(caller->TCI_list_call.end(),temp); 162 | 163 | it++; 164 | } 165 | 166 | //g的调用TCI表添加到f中 167 | it = callee->TCI_list_call.begin(); 168 | it_end = callee->TCI_list_call.end(); 169 | 170 | while (it != it_end) 171 | { 172 | temp = new TCI; 173 | temp->astcontext = (*it)->astcontext; 174 | temp->type = (*it)->type; 175 | temp->vd = (*it)->vd; 176 | temp->expr = (*it)->expr; 177 | temp->re = new Tainted_Attr; 178 | temp->re->copy((*it)->re); 179 | temp->fd = (*it)->fd; 180 | 181 | caller->TCI_list_call.insert(caller->TCI_list_call.end(), temp); 182 | 183 | it++; 184 | } 185 | 186 | //修改f的TCI_list_call中的内容 187 | it = caller->TCI_list_call.begin(); 188 | it_end = caller->TCI_list_call.end(); 189 | 190 | while (it != it_end) 191 | { 192 | temp = (*it); 193 | p = temp->re; 194 | if (p != NULL) 195 | { 196 | var_it = p->getVariableRelation()->begin(); 197 | var_end = p->getVariableRelation()->end(); 198 | while (var_it != var_end) 199 | { 200 | k = callee->get_param_no((*var_it)); 201 | //cout<<"testing: " << (*var_it)->getQualifiedNameAsString() << endl; 202 | if (k >= 0 && k < n) 203 | { 204 | q = &ta[k]; 205 | if (q->getVariableAttr() == UNTAINTED) 206 | { 207 | 208 | } 209 | //RELATED 210 | else 211 | { 212 | var_it2 = q->getVariableRelation()->begin(); 213 | var_end2 = q->getVariableRelation()->end(); 214 | while (var_it2 != var_end2) 215 | { 216 | //将与当今函数的相关信息插入到表中 217 | p->getVariableRelation()->insert(p->getVariableRelation()->end(), (*var_it2)); 218 | var_it2++; 219 | } 220 | } 221 | } 222 | var_it++; 223 | } 224 | } 225 | it++; 226 | } 227 | } 228 | 229 | //将需要输出的信息从callgraph放入Ttable供李珺输出 230 | void MsgOutput2Xml(callgraph *cg, Ttable &tt) 231 | { 232 | SourceManager* sm = NULL; 233 | Tainted_Attr* ta; 234 | 235 | vector::iterator it, it_end; 236 | it = cg->TCI_list.begin(); 237 | it_end = cg->TCI_list.end(); 238 | 239 | set::iterator var_it, var_end; 240 | while (it != it_end) 241 | { 242 | ta = (*it)->re; 243 | var_it = ta->getVariableRelation()->begin(); 244 | var_end = ta->getVariableRelation()->end(); 245 | while (var_it != var_end) 246 | { 247 | //和main的一个参数相关 248 | if (cg->get_param_no(*var_it) >= 0) 249 | { 250 | sm = &(*it)->astcontext->getSourceManager(); 251 | //cout << (*it)->expr->getLocStart().printToString(*sm) << endl; 252 | cout << 1 << endl; 253 | tt.insert((*it)->expr->getLocStart().printToString(*sm), (*it)->fd->getQualifiedNameAsString(), (*it)->type); 254 | break; 255 | } 256 | var_it++; 257 | } 258 | it++; 259 | } 260 | 261 | it = cg->TCI_list_call.begin(); 262 | it_end = cg->TCI_list_call.end(); 263 | 264 | while (it != it_end) 265 | { 266 | ta = (*it)->re; 267 | var_it = ta->getVariableRelation()->begin(); 268 | var_end = ta->getVariableRelation()->end(); 269 | while (var_it != var_end) 270 | { 271 | //和main的一个参数相关 272 | if (cg->get_param_no(*var_it) >= 0) 273 | { 274 | sm = &(*it)->astcontext->getSourceManager(); 275 | //cout << (*it)->expr->getLocStart().printToString(*sm) << endl; 276 | cout << 1 << endl; 277 | tt.insert((*it)->expr->getLocStart().printToString(*sm), (*it)->fd->getQualifiedNameAsString(), (*it)->type); 278 | break; 279 | } 280 | var_it++; 281 | } 282 | it++; 283 | } 284 | } 285 | 286 | //为每个语句块创建INOUT污染表 287 | void BuildBlockIoTable(map &block_io_map, clang::CFGBlock *CFGexit, clang::CFGBlock *block, CTmap &tm) 288 | { 289 | map::iterator t = block_io_map.find(block); 290 | 291 | //判断该块是否已添加过 292 | if (t != block_io_map.end()) 293 | return; 294 | block_io_map[block].setIO(tm); 295 | 296 | //判断该块是否为出口 297 | if (block == CFGexit) 298 | return; 299 | 300 | clang::CFGBlock::succ_iterator it = block->succ_begin(), end = block->succ_end(); 301 | 302 | while (it != end) 303 | { 304 | //递归创建表 305 | BuildBlockIoTable(block_io_map, CFGexit, (*it).getReachableBlock(), tm); 306 | it++; 307 | } 308 | } 309 | 310 | //打印一个block的污染信息 311 | void printBlockMsg(map &block_io_map, clang::CFGBlock *block) 312 | { 313 | cout << endl << "------------------------------" << endl; 314 | cout << "B" << block->getBlockID() << ":" << endl << "IN" << endl; 315 | block_io_map[block].GetIN()->output(); 316 | cout << endl << "OUT"<output(); 318 | cout << "------------------------------" << endl << endl; 319 | } 320 | 321 | //打印当前函数中每个block的污染信息 322 | void printiotable(map &block_io_map) 323 | { 324 | cout << endl << "==============================" << endl; 325 | cout << "Block message print starts...." << endl; 326 | map::iterator it = block_io_map.begin(), it_end = block_io_map.end(); 327 | while (it != it_end) 328 | { 329 | printBlockMsg(block_io_map, it->first); 330 | it++; 331 | } 332 | cout << "==============================" << endl << endl; 333 | } 334 | 335 | //测试用 输出到李珺的表中 336 | void output2xml(callgraph *cg, CTmap &tm) 337 | { 338 | Ttable tt; 339 | map::iterator it = tm.getmap(), it_end = tm.getend(); 340 | cout << 111 << endl; 341 | while (it != it_end) 342 | { 343 | //tt.insert(it->first, 1, cg->getCur()->getQualifiedNameAsString()); 344 | it++; 345 | } 346 | cout << 333 << endl; 347 | //tt.listout(); 348 | } 349 | -------------------------------------------------------------------------------- /ASTReader/callgraph.cpp: -------------------------------------------------------------------------------- 1 | #include "callgraph.h" 2 | //callgraph构造函数 3 | callgraph::callgraph(FunctionDecl* f1) 4 | { 5 | cur = f1; 6 | callerNum = 0; 7 | calleeNum = 0; 8 | ifCheck = 0; 9 | type = common; 10 | classDecl = NULL; 11 | map = new CTmap(); 12 | paramNum = 0; 13 | varNum = 0; 14 | return_tattr = new Tainted_Attr(); 15 | if_check_cfg = false; 16 | return_relation=0; 17 | } 18 | 19 | //calllgraph构造函数(带有一个callee) 20 | callgraph::callgraph(FunctionDecl* f1, FunctionDecl* f2) 21 | { 22 | cur = f1; 23 | callee.push_back(f2); 24 | callerNum = 0; 25 | calleeNum = 1; 26 | ifCheck = 0; 27 | type = common; 28 | classDecl = NULL; 29 | map = new CTmap(); 30 | paramNum = 0; 31 | varNum = 0; 32 | return_tattr = new Tainted_Attr(); 33 | if_check_cfg = false; 34 | return_relation=0; 35 | } 36 | 37 | callgraph::~callgraph() 38 | { 39 | block_io_map.clear(); 40 | TCI_list.clear(); 41 | TCI_list_call.clear(); 42 | caller.clear(); 43 | callee.clear(); 44 | delete(cfg.get()); 45 | map->~CTmap(); 46 | } 47 | 48 | std::vector& callgraph::getCaller() 49 | { 50 | return caller; 51 | } 52 | 53 | std::vector& callgraph::getCallee() 54 | { 55 | return callee; 56 | } 57 | 58 | //获得callgraph的所属函数的functiondecl 59 | FunctionDecl* callgraph::getCur() 60 | { 61 | return cur; 62 | } 63 | 64 | int callgraph::getCallerNum() 65 | { 66 | return callerNum; 67 | } 68 | 69 | int callgraph::getCalleeNum() 70 | { 71 | return calleeNum; 72 | } 73 | 74 | void callgraph::addCaller(FunctionDecl* otherFD){ 75 | caller.push_back(otherFD); 76 | callerNum++; 77 | } 78 | 79 | void callgraph::addCallee(FunctionDecl* otherFD,CallExpr* expr){ 80 | callee.push_back(otherFD); 81 | call_map.insert(std::pair(otherFD,expr)); 82 | calleeNum++; 83 | } 84 | 85 | 86 | void callgraph::delCallee(FunctionDecl* otherFD) 87 | { 88 | std::vector::iterator it_caller; 89 | std::vector::iterator it_callee; 90 | for (it_callee = callee.begin(); it_callee != callee.end(); it_callee++) 91 | { 92 | if ((*it_callee) == otherFD) 93 | { 94 | callee.erase(it_callee); 95 | break; 96 | } 97 | } 98 | std::map::iterator it_call_map=call_map.begin(); 99 | while (it_call_map != call_map.end()) 100 | { 101 | if ((*it_call_map).first == otherFD) 102 | { 103 | call_map.erase(it_call_map); 104 | return; 105 | } 106 | else 107 | { 108 | it_call_map++; 109 | } 110 | } 111 | } 112 | 113 | void callgraph::delCaller(FunctionDecl* otherFD) 114 | { 115 | std::vector::iterator it_caller; 116 | std::vector::iterator it_callee; 117 | for (it_caller = caller.begin(); it_caller != caller.end(); it_caller++) 118 | if ((*it_caller) == otherFD) 119 | { 120 | caller.erase(it_caller); 121 | return; 122 | } 123 | } 124 | 125 | //根据函数名查找callgraph 126 | callgraph* findById(std::vector Callgraph, std::string id) 127 | { 128 | std::vector::iterator it; 129 | for (it = Callgraph.begin(); it != Callgraph.end(); it++) 130 | { 131 | if ((*it)->getCur()->getQualifiedNameAsString().compare(id)==0) 132 | return *it; 133 | } 134 | return NULL; 135 | } 136 | 137 | //查找callgraph中的环,对其进行除环操作 138 | void ringCheck(std::vector cg, callgraph* t) 139 | { 140 | t->ifCheck = -1; 141 | //ring.push_back(t); 142 | std::vector::iterator it_callee; 143 | std::vector callee = t->getCallee(); 144 | int size = callee.size(); 145 | //for (it_callee = callee.begin(); it_callee != callee.end(); it_callee++) 146 | for (int i = 0; i < size;i++) 147 | { 148 | //FunctionDecl* tempt = *it_callee; 149 | FunctionDecl* tempt = callee[i]; 150 | callgraph* tempc = findById(cg, tempt->getQualifiedNameAsString()); 151 | if (tempc != NULL) 152 | { 153 | if (tempc->ifCheck == -1) 154 | { 155 | //输出环信息到xml 156 | 157 | t->delCallee(tempt); 158 | tempc->delCaller(tempt); 159 | //it_callee--;//================= 160 | std::map temp_call_map= t->get_call_map(); 161 | CallExpr* expr = temp_call_map[tempt]; 162 | if (expr==NULL) 163 | { 164 | cout << "call_map_error!" << endl; 165 | return; 166 | } 167 | else 168 | { 169 | t_table.insert( expr->getLocStart().printToString(tempc->getSourceManager()), tempt->getQualifiedNameAsString(), 6); 170 | } 171 | i--; 172 | size--; 173 | } 174 | else 175 | ringCheck(cg, tempc); 176 | } 177 | } 178 | t->ifCheck = 1; 179 | //ring.pop_back(); 180 | } 181 | 182 | //重置ifcheck 183 | void resetIfCheck(std::vectorCallgraph) 184 | { 185 | std::vector::iterator it; 186 | for (it = Callgraph.begin(); it < Callgraph.end(); it++) 187 | (*it)->ifCheck = 0; 188 | } 189 | 190 | //打印callgraph中存在的环的信息 191 | void getRing(std::vector&Callgraph, int n, std::vector& ringVector) 192 | { 193 | std::stack ring; 194 | std::vector::iterator it, it4; 195 | std::vector::iterator it2, it3; 196 | std::vector::iterator it_callee; 197 | 198 | //FunctionDecl* temp; 199 | it = Callgraph.begin() + n; 200 | if ((*it)->ifCheck == 0)//new node 201 | { 202 | std::vector callee = (*it)->getCallee(); 203 | ringVector.push_back((*it)->getCur()); 204 | (*it)->ifCheck = -1; 205 | for (it_callee = callee.begin(); it_callee != callee.end(); it_callee++) 206 | { 207 | for (it4 = Callgraph.begin(); it4 < Callgraph.end(); it4++) 208 | if ((*it4)->getCur() == *it_callee) 209 | { 210 | getRing(Callgraph, it4 - Callgraph.begin(), ringVector); 211 | break; 212 | } 213 | } 214 | (*it)->ifCheck = 1; 215 | ringVector.pop_back(); 216 | } 217 | else if ((*it)->ifCheck == -1) 218 | { 219 | for (it2 = ringVector.begin(); it2 < ringVector.end(); it2++) 220 | { 221 | if ((*it2) == (*it)->getCur()) 222 | break; 223 | } 224 | //print 225 | for (it3 = it2; it3 < ringVector.end(); it3++) 226 | { 227 | std::cout << (*it3)->getQualifiedNameAsString() << " "; 228 | } 229 | std::cout << std::endl; 230 | } 231 | else//ifCheck==1 232 | { 233 | return; 234 | } 235 | } 236 | 237 | //打印callgraph相关信息 238 | void printCallGraph() 239 | { 240 | std::vector::iterator it3; 241 | std::vector::iterator it_call; 242 | std::vector caller; 243 | std::vector callee; 244 | for (it3 = Callgraph.begin(); it3 != Callgraph.end(); it3++) 245 | { 246 | caller = (*it3)->getCaller(); 247 | callee = (*it3)->getCallee(); 248 | std::cout << (*it3)->getCur()->getQualifiedNameAsString() << "\n"; 249 | int paramNum = (*it3)->getCur()->getNumParams(); 250 | int varNum = (*it3)->getVarNum(); 251 | CTmap* map = &(*it3)->getCTmap(); 252 | 253 | std::cout << "\tParamNum: " << paramNum << "\n"; 254 | if (paramNum > 0) 255 | { 256 | for (unsigned i = 0; i < (*it3)->getCur()->getNumParams(); i++) 257 | { 258 | const VarDecl* tt = map->get_VarDecl(i); 259 | std::cout << "\t\t" << tt->getQualifiedNameAsString() << " "; 260 | map->getAttr(tt)->output(); 261 | std::cout << "\n"; 262 | } 263 | } 264 | 265 | std::cout << "\tVarNum: " << varNum << "\n"; 266 | if (varNum > 0) 267 | { 268 | for (int i = 0; i < varNum; i++) 269 | { 270 | const VarDecl* tt = map->get_VarDecl(i + paramNum); 271 | std::cout << "\t\t" << tt->getQualifiedNameAsString() << " "; 272 | map->getAttr(tt)->output(); 273 | std::cout << "\n"; 274 | } 275 | } 276 | 277 | int j = (*it3)->getCallerNum(); 278 | std::cout << "\tcaller:" << j << "\n"; 279 | for (it_call = caller.begin(); it_call != caller.end(); it_call++) 280 | std::cout << "\t\t" << (*it_call)->getQualifiedNameAsString() << "\n"; 281 | j = (*it3)->getCalleeNum(); 282 | std::cout << "\tcallee:" << j << "\n"; 283 | for (it_call = callee.begin(); it_call != callee.end(); it_call++) 284 | std::cout << "\t\t" << (*it_call)->getQualifiedNameAsString() << "\n"; 285 | } 286 | 287 | } 288 | 289 | //改变方法的类型(普通,类方法) 290 | void callgraph::changeMethodType() 291 | { 292 | if (type == common) 293 | type = inclass; 294 | else 295 | type = common; 296 | } 297 | 298 | //设置方法的实例指针 299 | void callgraph::setRoot(VarDecl* r) 300 | { 301 | root = r; 302 | } 303 | 304 | //获取实例指针 305 | VarDecl* callgraph::getRoot() 306 | { 307 | return root; 308 | } 309 | 310 | //获取方法类型 311 | methodType callgraph::getMethodType() 312 | { 313 | return type; 314 | } 315 | 316 | //设置类定义的指针 317 | void callgraph::setClass(CXXRecordDecl* rd) 318 | { 319 | classDecl = rd; 320 | } 321 | CXXRecordDecl* callgraph::getClass() 322 | { 323 | return classDecl; 324 | } 325 | 326 | //获取当前函数语句块信息指针 327 | std::unique_ptr& callgraph::get_cfg() 328 | { 329 | cfg = CFG::buildCFG(cur, cur->getBody(), &cur->getASTContext(), CFG::BuildOptions()); 330 | return cfg; 331 | } 332 | 333 | //打印cfg信息,使用dump() 334 | void callgraph::print_cfg() 335 | { 336 | (*cfg).dump(LangOptions(), true); 337 | } 338 | 339 | //获取当前函数Tmap指针 340 | CTmap& callgraph::getCTmap() 341 | { 342 | return *map; 343 | } 344 | 345 | //添加参数 346 | void callgraph::addParam(VarDecl* vd) 347 | { 348 | map->insert(vd); 349 | map_param.push_back(vd); 350 | paramNum++; 351 | } 352 | 353 | //添加变量 354 | void callgraph::addVar(VarDecl* vd) 355 | { 356 | map->insert(vd); 357 | varNum++; 358 | } 359 | 360 | int callgraph::getParamNum() 361 | { 362 | return paramNum; 363 | } 364 | 365 | int callgraph::getVarNum() 366 | { 367 | return varNum; 368 | } 369 | 370 | //检测某函数是否已经是本函数所调用的函数 371 | bool callgraph::is_caller(const FunctionDecl* fd) 372 | { 373 | int size = caller.size(); 374 | if (size == 0) 375 | return false; 376 | for (int i = 0; i < size; i++) 377 | { 378 | if (caller[i] == fd) 379 | return true; 380 | } 381 | return false; 382 | } 383 | 384 | //检测某函数是否已经是调用本函数的函数 385 | bool callgraph::is_callee(const FunctionDecl* fd) 386 | { 387 | int size = callee.size(); 388 | if (size == 0) 389 | return false; 390 | for (int i = 0; i < size; i++) 391 | { 392 | if (callee[i] == fd) 393 | return true; 394 | } 395 | return false; 396 | } 397 | 398 | //检测某函数是否已经生成了他的callgraph 399 | bool if_find_function(std::vector Callgraph, FunctionDecl* fd) 400 | { 401 | if (Callgraph.size() == 0) 402 | return false; 403 | std::vector::iterator it=Callgraph.begin(),it_end=Callgraph.end(); 404 | for (; it != it_end; it++) 405 | { 406 | if ((*it)->getCur() == fd) 407 | return true; 408 | } 409 | return false; 410 | } 411 | 412 | 413 | Tainted_Attr* callgraph::get_return() 414 | { 415 | return return_tattr; 416 | } 417 | 418 | void callgraph::set_return(Tainted_Attr* temp) 419 | { 420 | return_tattr->copy(temp); 421 | } 422 | 423 | //将if_check_cfg设为已经检查true 424 | void callgraph::set_if_check_cfg() 425 | { 426 | if_check_cfg = true; 427 | } 428 | 429 | bool callgraph::get_if_check_cfg() 430 | { 431 | return if_check_cfg; 432 | } 433 | 434 | unsigned callgraph::get_return_relation() 435 | { 436 | return return_relation; 437 | } 438 | 439 | //设置返回值与某一位相关 440 | bool callgraph::set_return_relation(int i) 441 | { 442 | if (i > 32) 443 | { 444 | cout << "参数数目不超过32" << endl; 445 | return false; 446 | } 447 | return_relation += 1 << i; 448 | return true; 449 | } 450 | 451 | //获取某个参数变量的参数编号 452 | int callgraph::get_param_no(const VarDecl* vd) 453 | { 454 | int i = 0; 455 | while (1) 456 | { 457 | if (map_param[i] == vd) 458 | return i; 459 | i++; 460 | if (i >= paramNum) 461 | return -1; 462 | } 463 | } 464 | 465 | //设置该函数所在ast文件的astcontext 466 | void callgraph::set_ASTContext(ASTContext* astcontext_temp) 467 | { 468 | astcontext = astcontext_temp; 469 | } 470 | 471 | //获取该函数所在文件的sourceManager 472 | SourceManager& callgraph::getSourceManager() 473 | { 474 | return astcontext->getSourceManager(); 475 | } 476 | 477 | //获取该函数所在文件的ASTContext 478 | ASTContext* callgraph::getASTContext() 479 | { 480 | return astcontext; 481 | } 482 | 483 | std::map& callgraph::get_call_map() 484 | { 485 | return call_map; 486 | } 487 | -------------------------------------------------------------------------------- /ASTReader/ASTReader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "AST.h" 9 | #include "callgraph.h" 10 | //#include "classTmap.h" 11 | #include"tmap.h" 12 | #include "CFGtattr.h" 13 | #include "Tout.h" 14 | 15 | using namespace std; 16 | 17 | std::vector Callgraph; 18 | std::vector ClassTmap; 19 | std::vector> astUnit; 20 | std::vector files; 21 | Ttable t_table; 22 | std::vector*> xyj_table; 23 | string folder_path = "NULL"; 24 | 25 | void get_file(string path, std::vector& all_file); 26 | void print_file(const std::vector files); 27 | bool is_syslib(string rd); 28 | 29 | int main(int argc, char *argv[]) { 30 | //获取目录下所有.cpp、.c文件所生成的.ast文件 31 | get_file(argv[1], files); 32 | 33 | int func_num = 0; 34 | int class_num = 0; 35 | 36 | std::vector::iterator it_callgraph, it_call_last = Callgraph.end(); 37 | int file_size = files.size(); 38 | for (int i = 0; i < file_size; i++) 39 | { 40 | //获取ASTUnit 41 | FileSystemOptions opts; 42 | IntrusiveRefCntPtr Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions()); 43 | CompilerInstance compiler; 44 | unique_ptr AU = ASTUnit::LoadFromASTFile(files[i], compiler.getPCHContainerReader(), Diags, opts); 45 | //保存ASTUnit 46 | astUnit.insert(astUnit.end(), move(AU)); 47 | int astUnit_size = astUnit.size(); 48 | ASTContext &context = (astUnit[astUnit_size - 1])->getASTContext(); 49 | 50 | //扫描AST获取全局变量定义 51 | //ASTCXXRecordLoad loadClass; 52 | //loadClass.HandleTranslationUnit(context); 53 | //std::vector cxxrds = loadClass.getClassDecl(); 54 | 55 | //扫描AST获取类定义 56 | ASTCXXRecordLoad loadClass; 57 | loadClass.HandleTranslationUnit(context); 58 | std::vector cxxrds = loadClass.getClassDecl(); 59 | 60 | if (cxxrds.size() > 0)//类的数目判断 61 | { 62 | std::vector::iterator rd_it, rd_it_end = cxxrds.end(); 63 | for (rd_it = cxxrds.begin(); rd_it != rd_it_end; rd_it++) 64 | { 65 | //是否为库类 66 | if (is_syslib((*rd_it)->getQualifiedNameAsString()) == true) 67 | continue; 68 | 69 | //在ClassTmap中加入新发现的class 70 | if (if_find_class(ClassTmap, *rd_it)) 71 | { 72 | continue;//已经有了,不再分析 73 | } 74 | classTmap* curClass = new classTmap(); 75 | curClass->setCXXRecordDecl(*rd_it); 76 | ClassTmap.push_back(curClass); 77 | class_num++; 78 | 79 | //添加类方法decl(仅仅为其创建callgraph函数,添加caller等操作之后统一进行) 80 | ASTCXXMethodDeclLoad loadClassMethod; 81 | std::vector cxxmds; 82 | std::vector::iterator it_cxxmds; 83 | //std::cout << (*rd_it)->getQualifiedNameAsString() << "\n"; 84 | loadClassMethod.TraverseDecl(*rd_it); 85 | cxxmds = loadClassMethod.getCXXMethodDecl(); 86 | 87 | if (cxxmds.size() > 0)//类方法数目 88 | { 89 | for (it_cxxmds = cxxmds.begin(); it_cxxmds != cxxmds.end(); it_cxxmds++) 90 | { 91 | curClass->addMethod(*it_cxxmds); 92 | callgraph* tempClassMethodNode = new callgraph(*it_cxxmds); 93 | Callgraph.insert(Callgraph.end(), tempClassMethodNode); 94 | tempClassMethodNode->set_ASTContext(&context); 95 | func_num++; 96 | //std::cout << (*it_cxxmds)->getQualifiedNameAsString() << "\n"; 97 | 98 | } 99 | } 100 | 101 | //添加类变量decl(类型为fieldDecl*) 102 | ASTFieldDeclLoad loadClassVar; 103 | std::vector fds; 104 | std::vector::iterator it_fds; 105 | loadClassVar.TraverseDecl(*rd_it); 106 | fds = loadClassVar.getFieldDecl(); 107 | if (fds.size() > 0) 108 | { 109 | for (it_fds = fds.begin(); it_fds != fds.end(); it_fds++) 110 | { 111 | FieldDecl* fd_temp = *it_fds; 112 | if (fd_temp->getType()->isPointerType()) 113 | { 114 | curClass->addVar(fd_temp, TYPE_POINTER); 115 | //curClass->getMap()->insert(); TYPE_POINTER; 116 | } 117 | else if (fd_temp->getType()->isStructureOrClassType()) 118 | { 119 | curClass->addVar(fd_temp, TYPE_CLASS); 120 | } 121 | else 122 | { 123 | curClass->addVar(fd_temp, TYPE_VARIABLE); 124 | } 125 | //std::cout << (*it_fds)->getQualifiedNameAsString() << "\n"; 126 | } 127 | } 128 | } 129 | }//cxxrds finished 130 | 131 | //扫描AST获取vector:: 132 | ASTFunctionLoad load; 133 | load.HandleTranslationUnit(context); 134 | std::vector func = load.getFunctions(); 135 | 136 | std::vector::iterator it_func_decl; 137 | 138 | //add cur->callee 139 | if (func.size() > 0) 140 | { 141 | //为functionDecl添加callgraph 142 | callgraph* tempCallNode; 143 | for (it_func_decl = func.begin(); it_func_decl != func.end(); it_func_decl++) 144 | { 145 | //是否为库函数 146 | if (is_syslib((*it_func_decl)->getQualifiedNameAsString()) == true) 147 | continue; 148 | 149 | //重复的functiondecl 150 | if (if_find_function(Callgraph, (*it_func_decl)) == true) 151 | continue; 152 | tempCallNode = new callgraph(*it_func_decl); 153 | Callgraph.push_back(tempCallNode); 154 | tempCallNode->set_ASTContext(&context); 155 | func_num++; 156 | } 157 | } 158 | } 159 | //astUnit over 160 | 161 | //std::vector::iterator 162 | it_callgraph = Callgraph.begin(); 163 | it_call_last = Callgraph.end(); 164 | std::vector callExpr; 165 | std::vector::iterator it_call_expr; 166 | callgraph* tempCallgraph; 167 | //为所有方法添加函数调用关系 168 | 169 | FunctionDecl* cur; 170 | for (; it_callgraph != it_call_last; it_callgraph++) 171 | { 172 | cur = (*it_callgraph)->getCur(); 173 | 174 | //设置函数返回值类型 175 | if (cur->getReturnType()->isPointerType()) 176 | (*it_callgraph)->get_return()->setType(TYPE_POINTER); 177 | // else if (cur->getReturnType()->isStructureOrClassType()) 178 | // (*it_callgraph)->getReturn()->setType(TYPE_CLASS); 179 | else 180 | (*it_callgraph)->get_return()->setType(TYPE_VARIABLE); 181 | 182 | ASTCallExprLoad load2; 183 | load2.TraverseStmt(cur->getBody()); 184 | callExpr = load2.getCallExprs(); 185 | if (callExpr.size() > 0) 186 | { 187 | //添加调用的函数callee 188 | for (it_call_expr = callExpr.begin(); it_call_expr != callExpr.end(); it_call_expr++) 189 | { 190 | FunctionDecl* callee = (*it_call_expr)->getDirectCallee(); 191 | if (callee == NULL || (*it_callgraph)->is_callee(callee) == true) 192 | { 193 | continue; 194 | } 195 | (*it_callgraph)->addCallee(callee, *it_call_expr); 196 | //std::cout << (*it_callgraph)->getCur()->getQualifiedNameAsString() << " -> " << (*it_call_expr)->getDirectCallee()->getQualifiedNameAsString() << std::endl; 197 | tempCallgraph = findById(Callgraph, callee->getQualifiedNameAsString()); 198 | if (tempCallgraph == NULL || tempCallgraph->is_caller((*it_callgraph)->getCur())) 199 | { 200 | continue; 201 | } 202 | else 203 | { 204 | tempCallgraph->addCaller((*it_callgraph)->getCur()); 205 | } 206 | } 207 | //添加调用本函数的函数caller 208 | } 209 | //把参数加入Tmap 210 | int paramNum = cur->getNumParams(); 211 | //VarDecl* parmTemp; 212 | if (paramNum > 0) 213 | { 214 | for (int i = 0; i < paramNum; i++) 215 | { 216 | ParmVarDecl* parm_temp = cur->getParamDecl(i); 217 | (*it_callgraph)->addParam(parm_temp); 218 | CTmap* map = &(*it_callgraph)->getCTmap(); 219 | 220 | //设置参数的污染信息相关的初始化 221 | if (parm_temp->getType()->isPointerType()) 222 | { 223 | map->setType(parm_temp, TYPE_POINTER); 224 | //map->ptr_attr_set(parm_temp, UNTAINTED, NULL); 225 | } 226 | else if (parm_temp->getType()->isStructureOrClassType()) 227 | { 228 | map->setType(parm_temp, TYPE_CLASS); 229 | CXXRecordDecl* t = parm_temp->getType()->getAsCXXRecordDecl(); 230 | classTmap* ct = getClassTmap(t); 231 | classTmap* new_ct = new classTmap(); 232 | new_ct->classCopy(ct); 233 | map->classmember_attr_set(parm_temp, new_ct); 234 | } 235 | else 236 | { 237 | map->setType(parm_temp, TYPE_VARIABLE); 238 | map->var_attr_set(parm_temp, RELATED, parm_temp); 239 | } 240 | } 241 | } 242 | 243 | //把中间变量加入Tmap 244 | ASTVarDeclLoad loadVar; 245 | loadVar.TraverseStmt(cur->getBody()); 246 | std::vector varList = loadVar.getVariables(); 247 | for (std::vector::iterator var_it = varList.begin(); var_it != varList.end(); var_it++) 248 | { 249 | //std::cout << (*varIt)->getQualifiedNameAsString() << "\n"; 250 | VarDecl* var_temp = *var_it; 251 | (*it_callgraph)->addVar(var_temp); 252 | CTmap* map = &(*it_callgraph)->getCTmap(); 253 | 254 | //设置变量的污染信息相关的初始化 255 | if (var_temp->getType()->isPointerType()) 256 | { 257 | map->setType(var_temp, TYPE_POINTER); 258 | // map->ptr_attr_set(var_temp, UNTAINTED, NULL); 259 | } 260 | else if (var_temp->getType()->isStructureOrClassType()) 261 | { 262 | map->setType(var_temp, TYPE_CLASS); 263 | CXXRecordDecl* t = var_temp->getType()->getAsCXXRecordDecl(); 264 | classTmap* ct = getClassTmap(t); 265 | classTmap* new_ct = new classTmap(); 266 | new_ct->classCopy(ct); 267 | map->classmember_attr_set(var_temp, new_ct); 268 | } 269 | else 270 | { 271 | map->setType(var_temp, TYPE_VARIABLE); 272 | map->var_attr_set(var_temp, UNTAINTED, NULL); 273 | } 274 | } 275 | } 276 | 277 | //std::vector ringVector; 278 | //getRing(Callgraph, 0, ringVector); 279 | 280 | //resetIfCheck(Callgraph); 281 | //ifcheck(Callgraph, *Callgraph.begin()); 282 | 283 | printCallGraph(); 284 | 285 | //printClassTmap(ClassTmap); 286 | 287 | cout << "class num:\t" << class_num << "\n"; 288 | cout << "function num:\t" << func_num << "\n"; 289 | std::vector::iterator it3; 290 | 291 | it3 = Callgraph.begin(); 292 | for (; it3 != Callgraph.end(); it3++) 293 | { 294 | if ((*it3)->getCur()->getQualifiedNameAsString().compare(string("main")) == 0) 295 | { 296 | resetIfCheck(Callgraph); 297 | ringCheck(Callgraph, *it3); 298 | break; 299 | } 300 | } 301 | 302 | printCallGraph(); 303 | 304 | it3 = Callgraph.begin(); 305 | for (; it3 != Callgraph.end(); it3++) 306 | { 307 | if ((*it3)->getCur()->getQualifiedNameAsString().compare(string("main")) == 0) 308 | { 309 | checkCFG(*(*it3)->get_cfg(), (*it3)->getCTmap(), *it3); 310 | MsgOutput2Xml(*it3, t_table); 311 | t_table.XMLout(folder_path+string("\\warning.xml")); 312 | break; 313 | } 314 | } 315 | 316 | //FunctionDecl* ddd=Callgraph[0]->getCur(); 317 | //Stmt* sss=ddd->getBody(); 318 | //ASTContext &aaaa=astUnit[1]->getASTContext(); 319 | 320 | //string s(sss->getLocStart().printToString(aaaa.getSourceManager())); 321 | return 0; 322 | } 323 | 324 | void get_file(string path, std::vector& all_files) 325 | { 326 | //文件句柄 327 | long hFile = 0; 328 | //文件信息 329 | struct _finddata_t fileinfo; 330 | //基础空串 331 | string p; 332 | hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo); 333 | if (folder_path.compare(string("NULL")) == 0) 334 | { 335 | folder_path = p.assign(path); 336 | } 337 | if (hFile == -1) 338 | { 339 | cout << "文件夹不存在" << endl; 340 | } 341 | else 342 | { 343 | do 344 | { 345 | if ((fileinfo.attrib & _A_SUBDIR)) //比较文件类型是否是文件夹 346 | { 347 | if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0) 348 | { 349 | get_file(p.assign(path).append("\\").append(fileinfo.name), all_files); 350 | } 351 | } 352 | else if (regex_match(fileinfo.name, regex("(.*)(.ast)"))) 353 | { 354 | all_files.push_back(p.assign(path).append("\\").append(fileinfo.name)); 355 | cout << p << endl; 356 | } 357 | else 358 | { 359 | ; 360 | } 361 | } while (_findnext(hFile, &fileinfo) == 0); //寻找下一个,成功返回0,否则-1 362 | _findclose(hFile); 363 | } 364 | } 365 | 366 | void print_file(const vector files) 367 | { 368 | int size = files.size(); 369 | for (int i = 0; i < size; i++) 370 | { 371 | cout << files[i] << endl; 372 | } 373 | } 374 | 375 | bool is_syslib(string rd) 376 | { 377 | if (regex_match(rd, regex("(std::)(.*)"))) 378 | return true; 379 | else if (regex_match(rd, regex("(stdext::)(.*)"))) 380 | return true; 381 | else if (regex_match(rd, regex("(type_info)(.*)"))) 382 | return true; 383 | else 384 | return false; 385 | } 386 | -------------------------------------------------------------------------------- /ASTReader/tmap.cpp: -------------------------------------------------------------------------------- 1 | #include "tmap.h" 2 | 3 | //默认构造函数,污染属性的类型对应为unknown 4 | Tainted_Attr::Tainted_Attr(){ 5 | ptrAttr = NULL; 6 | is_temp = false; 7 | #ifdef USECLASS 8 | ptrClassDecl = NULL; 9 | #endif 10 | 11 | type = TYPE_UNKNOWN; 12 | } 13 | 14 | //追加了类型参数的构造函数,如果是类请传入该类的classTmap 15 | Tainted_Attr::Tainted_Attr(VarDeclType mytype, classTmap *ct) 16 | { 17 | type = mytype; 18 | if (mytype == TYPE_VARIABLE) 19 | { 20 | attr = UNTAINTED; 21 | } 22 | else if (mytype == TYPE_POINTER) 23 | { 24 | attr = UNTAINTED; 25 | ptrAttr = NULL; 26 | ptrClassDecl = NULL; 27 | is_temp = false; 28 | } 29 | else if (mytype == TYPE_CLASS) 30 | { 31 | ptrClassDecl = ct; 32 | } 33 | else 34 | { 35 | ptrAttr = NULL; 36 | ptrClassDecl = NULL; 37 | type = TYPE_UNKNOWN; 38 | } 39 | } 40 | 41 | //拷贝构造函数 42 | Tainted_Attr::Tainted_Attr(Tainted_Attr& b) 43 | { 44 | set::iterator it = b.relation.begin(), it_end = b.relation.end(); 45 | type = b.type; 46 | switch (b.type) 47 | { 48 | case TYPE_VARIABLE: 49 | attr = b.attr; 50 | while (it != it_end) 51 | { 52 | relation.insert(relation.end(), *it); 53 | it++; 54 | } 55 | break; 56 | case TYPE_CLASS: 57 | ptrClassDecl = b.ptrClassDecl; 58 | break; 59 | case TYPE_POINTER: 60 | is_temp = b.is_temp; 61 | ptrAttr = b.ptrAttr; 62 | while (it != it_end) 63 | { 64 | relation.insert(relation.end(), *it); 65 | it++; 66 | } 67 | break; 68 | case TYPE_UNKNOWN: 69 | break; 70 | } 71 | } 72 | 73 | Tainted_Attr::~Tainted_Attr() 74 | { 75 | relation.clear(); 76 | if (type == TYPE_POINTER) 77 | { 78 | if (is_temp) 79 | { 80 | ptrAttr->~Tainted_Attr(); 81 | delete ptrAttr; 82 | } 83 | ptrAttr = NULL; 84 | type = TYPE_UNKNOWN; 85 | attr = UNTAINTED; 86 | 87 | } 88 | if (type == TYPE_CLASS) 89 | { 90 | ptrClassDecl->~classTmap(); 91 | delete ptrClassDecl; 92 | ptrClassDecl = NULL; 93 | } 94 | } 95 | 96 | //获取所存储的污染属性的类型 97 | VarDeclType Tainted_Attr::getType() 98 | { 99 | return type; 100 | } 101 | 102 | //获取变量类型的污染属性的污染情况 103 | e_tattr Tainted_Attr::getVariableAttr() 104 | { 105 | return attr; 106 | } 107 | 108 | //获取变量类型的污染属性的关联 109 | set *Tainted_Attr::getVariableRelation() 110 | { 111 | return &relation; 112 | } 113 | 114 | //获取类类型的污染属性的classTmap指针 115 | classTmap *Tainted_Attr::getClassDecl() 116 | { 117 | return ptrClassDecl; 118 | } 119 | 120 | //获得指针类型的污染属性所指向的污染属性 121 | Tainted_Attr *Tainted_Attr::getPointerAttr() 122 | { 123 | return ptrAttr; 124 | } 125 | 126 | bool Tainted_Attr::getistemp() 127 | { 128 | return is_temp; 129 | } 130 | 131 | //信息输出函数 调试用 132 | void Tainted_Attr::output() 133 | { 134 | const VarDecl *vd; 135 | set::iterator it = relation.begin(), it_end = relation.end(); 136 | if (type == TYPE_VARIABLE) 137 | { 138 | if (attr == TAINTED) 139 | cout << "TAINTED "; 140 | else if (attr == UNTAINTED) 141 | cout << "UN "; 142 | else 143 | { 144 | cout << "RE Related to: "; 145 | while (it != it_end) 146 | { 147 | vd = *it; 148 | cout << vd->getNameAsString() << " "; 149 | it++; 150 | } 151 | } 152 | } 153 | else if (type == TYPE_POINTER) 154 | { 155 | if (attr == TAINTED) 156 | cout << "TAINTED "; 157 | else if (attr == UNTAINTED) 158 | cout << "UN "; 159 | else 160 | { 161 | cout << "RE Related to: "; 162 | while (it != it_end) 163 | { 164 | vd = *it; 165 | cout << vd->getNameAsString() << " "; 166 | it++; 167 | } 168 | } 169 | } 170 | //here to add output 171 | else 172 | { 173 | cout << "unknown"; 174 | } 175 | } 176 | 177 | 178 | //复制p中的污染属性 179 | void Tainted_Attr::copy(Tainted_Attr *p) 180 | { 181 | set::iterator it = p->relation.begin(), it_end = p->relation.end(); 182 | if (type == TYPE_CLASS) 183 | { 184 | ptrClassDecl->~classTmap(); 185 | delete ptrClassDecl; 186 | } 187 | relation.clear(); 188 | type = p->type; 189 | if (type == TYPE_VARIABLE) 190 | { 191 | attr = p->attr; 192 | if (attr == RELATED) 193 | { 194 | while (it != it_end) 195 | { 196 | relation.insert(relation.end(), *it); 197 | it++; 198 | } 199 | } 200 | } 201 | else if (type == TYPE_POINTER) 202 | { 203 | ptrAttr = p->ptrAttr; 204 | attr = p->attr; 205 | if (attr == RELATED) 206 | { 207 | while (it != it_end) 208 | { 209 | relation.insert(relation.end(), *it); 210 | it++; 211 | } 212 | } 213 | is_temp = p->is_temp; 214 | } 215 | else if (type == TYPE_CLASS) 216 | { 217 | ptrClassDecl = new classTmap(*p->ptrClassDecl); 218 | } 219 | } 220 | 221 | void Tainted_Attr::settemp(bool b) 222 | { 223 | if (is_temp == true && b == false) 224 | { 225 | ptrAttr->~Tainted_Attr(); 226 | ptrAttr = NULL; 227 | } 228 | is_temp = b; 229 | } 230 | 231 | //信息设置函数,如果当前污染属性的类型不为VARIABLE,不会进行修改,并警告 232 | void Tainted_Attr::var_attr_set(e_tattr a, const VarDecl *vd) 233 | { 234 | relation.clear(); 235 | if (type != TYPE_VARIABLE && type != TYPE_POINTER) 236 | { 237 | cout << "warning: type != TYPE_VARIABLE" << endl; 238 | return; 239 | } 240 | 241 | attr = a; 242 | if (a == RELATED) 243 | relation.insert(relation.end(), vd); 244 | } 245 | 246 | void Tainted_Attr::var_attr_set(e_tattr a, set r) 247 | { 248 | relation.clear(); 249 | if (a != RELATED) 250 | { 251 | attr = a; 252 | return; 253 | } 254 | set::iterator it = r.begin(), it_end = r.end(); 255 | while (it != it_end) 256 | { 257 | relation.insert(relation.end(), *it); 258 | it++; 259 | } 260 | 261 | } 262 | 263 | //信息设置函数,如果当前的污染属性的类型不为CLASS,不会进行修改,并警告 264 | void Tainted_Attr::class_attr_set(e_tattr a, const VarDecl *vd, Expr *ptrExp) 265 | { 266 | if (type != TYPE_CLASS) 267 | { 268 | cout << "warning: type != TYPE_CLASS" << endl; 269 | return; 270 | } 271 | //here to add 272 | } 273 | 274 | //信息设置函数,如果当前的污染属性的类型不为POINTER,不会进行修改,并警告 275 | void Tainted_Attr::pointer_attr_set(e_tattr a, const VarDecl *vd) 276 | { 277 | 278 | if (type != TYPE_POINTER) 279 | { 280 | cout << "warning: type != TYPE_POINTER" << endl; 281 | return; 282 | } 283 | ptrAttr->var_attr_set(a, vd); 284 | } 285 | 286 | //将已生成好的类成员自身的表链接到属性上 287 | void Tainted_Attr::classmember_set(classTmap *ct) 288 | { 289 | if (ptrClassDecl != NULL) 290 | { 291 | ptrClassDecl->~classTmap(); 292 | delete ptrClassDecl; 293 | } 294 | ptrClassDecl = ct; 295 | } 296 | 297 | //将当前污染属性指向pt指向的位置,如果当前污染属性的类型不为POINTER,不会进行修改,并警告 298 | void Tainted_Attr::setPointer(Tainted_Attr *pt) 299 | { 300 | if (pt == NULL) 301 | { 302 | ptrAttr = NULL; 303 | return; 304 | } 305 | if (type != TYPE_POINTER) 306 | { 307 | cout << "Warning: type != POINTER" << endl; 308 | return; 309 | } 310 | while (1) 311 | { 312 | if (pt->type == TYPE_VARIABLE || pt->type == TYPE_CLASS) 313 | { 314 | copy(pt); 315 | ptrAttr = pt; 316 | return; 317 | } 318 | pt = pt->ptrAttr; 319 | } 320 | } 321 | 322 | //设置污染属性的类型 323 | void Tainted_Attr::setType(VarDeclType tp) 324 | { 325 | type = tp; 326 | if (tp == TYPE_VARIABLE) 327 | { 328 | attr = UNTAINTED; 329 | } 330 | else if (tp == TYPE_POINTER) 331 | { 332 | attr = UNTAINTED; 333 | ptrAttr = NULL; 334 | is_temp = false; 335 | } 336 | else if (tp == TYPE_CLASS) 337 | { 338 | ptrClassDecl = NULL; 339 | } 340 | else 341 | { 342 | ptrAttr = NULL; 343 | type = TYPE_UNKNOWN; 344 | } 345 | } 346 | 347 | //将两个污染属性取并,存到当前变量中 348 | void Tainted_Attr::unionAttr(Tainted_Attr &a, Tainted_Attr &b) 349 | { 350 | set::iterator it, it_end; 351 | relation.clear(); 352 | if (a.type != b.type) 353 | { 354 | cout << "Error in unionAttr()" << endl; 355 | return; 356 | } 357 | type = a.type; 358 | if (type == TYPE_VARIABLE) 359 | { 360 | if (a.attr == TAINTED || b.attr == TAINTED) 361 | { 362 | attr = TAINTED; 363 | return; 364 | } 365 | else if (a.attr == UNTAINTED && b.attr == UNTAINTED) 366 | { 367 | attr = UNTAINTED; 368 | return; 369 | } 370 | else if (a.attr == RELATED && b.attr != RELATED) 371 | { 372 | attr = RELATED; 373 | copy(&a); 374 | return; 375 | } 376 | else if (a.attr != RELATED && b.attr == RELATED) 377 | { 378 | attr = RELATED; 379 | copy(&b); 380 | return; 381 | } 382 | else 383 | { 384 | attr = RELATED; 385 | copy(&a); 386 | it = b.relation.begin(); 387 | it_end = b.relation.end(); 388 | while (it != it_end) 389 | { 390 | relation.insert(relation.end(), *it); 391 | it++; 392 | } 393 | } 394 | return; 395 | } 396 | } 397 | 398 | //当前变量与其他变量取并,存到当前变量中 399 | void Tainted_Attr::unionAttr(Tainted_Attr &a) 400 | { 401 | Tainted_Attr b; 402 | b.copy(this); 403 | unionAttr(a, b); 404 | } 405 | 406 | //构造函数 407 | CTmap::CTmap(){} 408 | 409 | //拷贝构造函数 410 | CTmap::CTmap(CTmap& b) 411 | { 412 | Tainted_Attr *t = NULL, *newattr; 413 | const VarDecl *pdec = NULL; 414 | map::iterator it = b.tmap.begin(), it_end = b.tmap.end(); 415 | 416 | while (it != it_end) 417 | { 418 | pdec = (*it).first; 419 | t = (*it).second; 420 | newattr = new Tainted_Attr(*t); 421 | tmap[pdec] = newattr; 422 | it++; 423 | } 424 | } 425 | 426 | //析构函数 427 | CTmap::~CTmap() 428 | { 429 | Tainted_Attr *t; 430 | classTmap *ct; 431 | map::iterator iter = tmap.begin(), iter_end = tmap.end(); 432 | while (iter != iter_end) 433 | { 434 | t = iter->second; 435 | if (t->getType() == TYPE_CLASS) 436 | { 437 | ct = t->getClassDecl(); 438 | ct->classClear(); 439 | delete ct; 440 | } 441 | delete iter->second; 442 | iter->second = NULL; 443 | iter++; 444 | } 445 | tmap.clear(); 446 | } 447 | 448 | //map中的元素及对应的污染情况输出 449 | void CTmap::output() 450 | { 451 | map::iterator iter = tmap.begin(), iter_end = tmap.end(); 452 | while (iter != iter_end) 453 | { 454 | std::cout << iter->first->getQualifiedNameAsString() << " "; 455 | iter->second->output(); 456 | cout << endl; 457 | iter++; 458 | } 459 | } 460 | 461 | map::iterator CTmap::getmap() 462 | { 463 | return tmap.begin(); 464 | } 465 | 466 | map::iterator CTmap::getend() 467 | { 468 | return tmap.end(); 469 | } 470 | 471 | //将当前map清空,并将b中的元素及污染属性整个拷贝到map中 472 | void CTmap::CopyMap(CTmap& b) 473 | { 474 | clear(); 475 | Tainted_Attr *t = NULL, *newattr, *ptrattr; 476 | const VarDecl *pdec = NULL; 477 | map::iterator it = b.tmap.begin(), it_end = b.tmap.end(); 478 | 479 | while (it != it_end) 480 | { 481 | pdec = it->first; 482 | t = it->second; 483 | //pdec==class here to add how to copy 484 | 485 | //若t只是一个普通的变量,则调用一般的复制函数 486 | if (t->getType() == TYPE_VARIABLE) 487 | { 488 | newattr = new Tainted_Attr; 489 | newattr->copy(t); 490 | tmap[pdec] = newattr; 491 | } 492 | //若为指针 493 | else if (t->getType() == TYPE_POINTER) 494 | { 495 | newattr = new Tainted_Attr; 496 | newattr->copy(t); 497 | tmap[pdec] = newattr; 498 | ptrattr = newattr->getPointerAttr(); 499 | if (ptrattr == NULL) 500 | { 501 | 502 | } 503 | else if (newattr->getistemp() == true) 504 | { 505 | ptrattr = new Tainted_Attr; 506 | ptrattr->copy(t->getPointerAttr()); 507 | } 508 | //是表t中的某个元素 509 | else 510 | { 511 | map::iterator it2 = b.tmap.begin(), it_end2 = b.tmap.end(); 512 | bool find = false; 513 | while (it2 != it_end2) 514 | { 515 | if (it2->second == ptrattr) 516 | { 517 | find = true; 518 | newattr->setPointer(getAttr(it2->first)); 519 | } 520 | it2++; 521 | } 522 | //是某个类中的元素 523 | } 524 | } 525 | it++; 526 | } 527 | } 528 | 529 | //若p不在表中,插入一个以p为索引的空条目 530 | void CTmap::insert(const VarDecl *p) 531 | { 532 | Tainted_Attr *t = new Tainted_Attr(); 533 | 534 | int count; 535 | count = tmap.count(p); 536 | if (count == 0) 537 | { 538 | tmap[p] = t; 539 | //==class here to add how to insert 540 | } 541 | else 542 | delete t; 543 | } 544 | 545 | //从map中删除p 546 | void CTmap::del(const VarDecl *p) 547 | { 548 | Tainted_Attr *t = tmap[p]; 549 | //==class here to add how to delete 550 | if (t->getType() == TYPE_CLASS) 551 | { 552 | t->getClassDecl()->~classTmap(); 553 | delete t->getClassDecl(); 554 | } 555 | delete t; 556 | tmap.erase(p); 557 | } 558 | 559 | //取得变量定义节点p对应的污染属性 560 | Tainted_Attr *CTmap::getAttr(const VarDecl *p) 561 | { 562 | int count; 563 | count = tmap.count(p); 564 | if (count == 0) 565 | return NULL; 566 | else 567 | { 568 | return tmap[p]; 569 | } 570 | } 571 | 572 | //取得变量定义节点p指针指向的污染属性 573 | Tainted_Attr *CTmap::getPointerAttr(const VarDecl *vd) 574 | { 575 | int count; 576 | count = tmap.count(vd); 577 | if (count == 0) 578 | return NULL; 579 | else 580 | { 581 | if (tmap[vd]->getType() != TYPE_POINTER) 582 | return NULL; 583 | else 584 | return tmap[vd]->getPointerAttr(); 585 | } 586 | } 587 | 588 | //获取类的变量的自身的map 589 | classTmap *CTmap::getClassTmap(const VarDecl *p) 590 | { 591 | int count; 592 | count = tmap.count(p); 593 | if (count == 0) 594 | { 595 | return NULL; 596 | } 597 | else 598 | { 599 | if (tmap[p]->getType() != TYPE_CLASS) 600 | { 601 | return NULL; 602 | } 603 | return tmap[p]->getClassDecl(); 604 | } 605 | } 606 | 607 | //设置某个变量的属性(变量、指针、类) 608 | void CTmap::setType(const VarDecl *p, VarDeclType tp) 609 | { 610 | int count; 611 | count = tmap.count(p); 612 | if (count == 0) 613 | { 614 | cout << "Error: No such variable in the function" << endl; 615 | return; 616 | } 617 | else 618 | { 619 | tmap[p]->setType(tp); 620 | } 621 | } 622 | 623 | //设置p的污染属性,p为普通变量类型 624 | void CTmap::var_attr_set(const VarDecl *p, e_tattr e, const VarDecl *vd) 625 | { 626 | //cout << "relation = " << r << endl; 627 | int count; 628 | Tainted_Attr *tp; 629 | count = tmap.count(p); 630 | if (count == 0) 631 | { 632 | cout << "Error: No such variable in the function" << endl; 633 | return; 634 | } 635 | else 636 | { 637 | tp = tmap[p]; 638 | if (tp->getType() != TYPE_VARIABLE && tp->getType() != TYPE_POINTER) 639 | { 640 | cout << "Warning: type != TYPE_VARIABLE" << endl; 641 | return; 642 | } 643 | tp->var_attr_set(e, vd); 644 | } 645 | } 646 | 647 | //设置vd的污染属性 648 | void CTmap::var_attr_set(const VarDecl *vd, Tainted_Attr *ta) 649 | { 650 | getAttr(vd)->copy(ta); 651 | } 652 | 653 | //设置pt指向的变量 654 | void CTmap::ptr_set(const VarDecl *p, Tainted_Attr *tp) 655 | { 656 | int count; 657 | count = tmap.count(p); 658 | if (count == 0) 659 | { 660 | cout << "Error: No such variable in the function" << endl; 661 | return; 662 | } 663 | else 664 | { 665 | if (tmap[p]->getType() != TYPE_POINTER) 666 | { 667 | cout << "Warning: type != POINTER" << endl; 668 | return; 669 | } 670 | tmap[p]->setPointer(tp); 671 | } 672 | } 673 | 674 | //设置pt指向的变量的污染属性 675 | void CTmap::ptr_attr_set(const VarDecl *p, e_tattr e, const VarDecl *vd) 676 | { 677 | int count; 678 | Tainted_Attr *tp; 679 | count = tmap.count(p); 680 | if (count == 0) 681 | { 682 | cout << "Error: No such variable in the function" << endl; 683 | return; 684 | } 685 | else 686 | { 687 | tp = tmap[p]; 688 | if (tp->getType() != TYPE_POINTER) 689 | { 690 | cout << "Warning: type != TYPE_POINTER" << endl; 691 | return; 692 | } 693 | tp->pointer_attr_set(e, vd); 694 | } 695 | } 696 | 697 | //将classTmap的指针链接到VarDecl的条目上 698 | void CTmap::classmember_attr_set(const VarDecl *p, classTmap *ct) 699 | { 700 | int count; 701 | Tainted_Attr *tp; 702 | count = tmap.count(p); 703 | if (count == 0) 704 | { 705 | cout << "Error: No such variable in the function" << endl; 706 | return; 707 | } 708 | else 709 | { 710 | tp = tmap[p]; 711 | if (tp->getType() != TYPE_CLASS) 712 | { 713 | cout << "Warning: type != TYPE_POINTER" << endl; 714 | return; 715 | } 716 | else 717 | { 718 | tp->classmember_set(ct); 719 | } 720 | } 721 | } 722 | 723 | //设置污染属性 724 | void CTmap::classmember_attr_set(const VarDecl *p, e_tattr e, const VarDecl *r, Expr *ptrExpr) 725 | {} 726 | 727 | //将两个map中的污染属性合并 728 | void CTmap::unionMap(CTmap &b) 729 | { 730 | const VarDecl *p; 731 | map::iterator iter = tmap.begin(), iter_end = tmap.end(); 732 | while (iter != iter_end) 733 | { 734 | p = (*iter).first; 735 | if (b.getAttr(p) != NULL) 736 | (*iter).second->unionAttr(*b.getAttr(p)); 737 | iter++; 738 | } 739 | } 740 | 741 | //清空map中的元素 742 | void CTmap::clear() 743 | { 744 | Tainted_Attr *t; 745 | classTmap *ct; 746 | map::iterator iter = tmap.begin(), iter_end = tmap.end(); 747 | while (iter != iter_end) 748 | { 749 | t = iter->second; 750 | if (t->getType() == TYPE_CLASS) 751 | { 752 | ct = t->getClassDecl(); 753 | ct->classClear(); 754 | } 755 | delete iter->second; 756 | iter->second = NULL; 757 | iter++; 758 | } 759 | tmap.clear(); 760 | } 761 | 762 | //获取第n个变量定义 763 | const VarDecl *CTmap::get_VarDecl(int n) 764 | { 765 | int i = 0; 766 | map::iterator iter = tmap.begin(), iter_end = tmap.end(); 767 | for (; iter != iter_end; iter++) 768 | { 769 | if (i == n) 770 | return iter->first; 771 | i++; 772 | } 773 | return NULL; 774 | } 775 | 776 | //比较两个属性是否相同,自用 777 | bool Tainted_Attr::compareAttr(Tainted_Attr &ta) 778 | { 779 | if (type != ta.type) 780 | return false; 781 | if (type == TYPE_VARIABLE || type == TYPE_POINTER) 782 | { 783 | if (attr != ta.attr) 784 | return false; 785 | if (attr == RELATED) 786 | { 787 | set::iterator it = relation.begin(), it_end = relation.end(); 788 | while (it != it_end) 789 | { 790 | if (ta.relation.find(*it) == ta.relation.end()) 791 | return false; 792 | it++; 793 | } 794 | it = ta.relation.begin(); 795 | it_end = ta.relation.end(); 796 | while (it != it_end) 797 | { 798 | if (relation.find(*it) == relation.end()) 799 | return false; 800 | it++; 801 | } 802 | } 803 | } 804 | else 805 | { 806 | cout << "must Add something" << endl; 807 | } 808 | return true; 809 | } 810 | 811 | //比较两个map是否相同,相同则返回true,自用 812 | bool CTmap::compareMap(CTmap &tm) 813 | { 814 | Tainted_Attr *ta; 815 | map::iterator it = tmap.begin(), it_end = tmap.end(); 816 | while (it != it_end) 817 | { 818 | ta = tm.getAttr(it->first); 819 | if (ta != NULL) 820 | { 821 | if (it->second->compareAttr(*ta) != true) 822 | return false; 823 | } 824 | it++; 825 | } 826 | return true; 827 | } 828 | 829 | /*void f() 830 | { 831 | Tainted_Attr *ptr_p, *ptr_a;//分别存了p和a的污染状况 832 | //p = &a;(p为指针,a为一般变量) 833 | ptr_p->~Tainted_Attr(); 834 | ptr_p->setType(TYPE_POINTER); 835 | ptr_p->setPointer(ptr_a); //会自动将p的污染属性设置为与a相同,且指针会指向a的条目 836 | //p = p + 1;(指针指向了下一个位置) 837 | if (ptr_p->getistemp() == false)//不是动态创建的变量 838 | ptr_p->setPointer(NULL);//将指针从本来指向的内存移开 839 | else 840 | ptr_p->settemp(false); 841 | //a = (*p) + b;(a,b为变量,p为指针) 842 | ptr_p->getPointerAttr(); //取得指向的变量的污染条目,之后用这个条目与b的取并 843 | //*p = a + b; 844 | ptr_p->getPointerAttr(); //取得指向的变量的污染条目,之后操作与一般变量相同 845 | //p = new int;(例如p指向了动态变量) 846 | Tainted_Attr *temp = new Tainted_Attr(); 847 | ptr_p->~Tainted_Attr(); 848 | ptr_p->setType(TYPE_POINTER); 849 | ptr_p->settemp(true); 850 | }*/ 851 | 852 | 853 | 854 | //classTmap.cpp 855 | classTmap::classTmap() 856 | { 857 | methodNum = 0; 858 | varNum = 0; 859 | rd = NULL; 860 | } 861 | void classTmap::setCXXRecordDecl(CXXRecordDecl* cxxrd) 862 | { 863 | rd = cxxrd; 864 | } 865 | void classTmap::addMethod(CXXMethodDecl* md) 866 | { 867 | cxxmds.push_back(md); 868 | methodNum++; 869 | } 870 | void classTmap::addVar(FieldDecl* fd, VarDeclType evt) 871 | { 872 | fds.push_back(fd); 873 | map.insert((VarDecl*)fd); 874 | map.setType((VarDecl*)fd, evt); 875 | CXXRecordDecl* t; 876 | classTmap* ct; 877 | classTmap* new_ct; 878 | switch (evt) 879 | { 880 | case TYPE_POINTER:break; 881 | case TYPE_VARIABLE: 882 | map.var_attr_set((VarDecl*)fd, UNTAINTED, NULL); 883 | break; 884 | case TYPE_CLASS: 885 | t = fd->getType()->getAsCXXRecordDecl(); 886 | ct = getClassTmap(t); 887 | new_ct = new classTmap(); 888 | new_ct->classCopy(ct); 889 | map.classmember_attr_set((VarDecl*)fd, new_ct); 890 | break; 891 | default:break; 892 | } 893 | varNum++; 894 | } 895 | const vector& classTmap::get_cxxmds() 896 | { 897 | return cxxmds; 898 | } 899 | const vector& classTmap::get_fds() 900 | { 901 | return fds; 902 | } 903 | CXXRecordDecl* classTmap::get_cxxrd()const 904 | { 905 | return rd; 906 | } 907 | int classTmap::getMethodNum() 908 | { 909 | return methodNum; 910 | } 911 | int classTmap::getVarNum() 912 | { 913 | return varNum; 914 | } 915 | 916 | void printClassTmap(vector CT) 917 | { 918 | vector::iterator it_ct = CT.begin(), it_ct_end = CT.end(); 919 | vector::iterator it_cxxmd; 920 | vector cxxmds; 921 | int methodNum; 922 | vector::iterator it_fd; 923 | vectorfds; 924 | int varNum; 925 | for (; it_ct != it_ct_end; it_ct++) 926 | { 927 | cxxmds = (*it_ct)->get_cxxmds(); 928 | fds = (*it_ct)->get_fds(); 929 | cout << (*it_ct)->get_cxxrd()->getQualifiedNameAsString() << "\n"; 930 | it_cxxmd = cxxmds.begin(); 931 | methodNum = (*it_ct)->getMethodNum(); 932 | it_fd = fds.begin(); 933 | varNum = (*it_ct)->getVarNum(); 934 | cout << "\tVar:\n"; 935 | if (fds.size() > 0) 936 | { 937 | for (int i = 0; i < varNum; i++) 938 | { 939 | cout << "\t\t" << (*it_fd)->getQualifiedNameAsString() << "\n"; 940 | it_fd++; 941 | } 942 | } 943 | if (cxxmds.size() > 0) 944 | { 945 | cout << "\tMethod:\n"; 946 | for (int i = 0; i < methodNum; i++) 947 | { 948 | cout << "\t\t" << (*it_cxxmd)->getQualifiedNameAsString() << "\n"; 949 | it_cxxmd++; 950 | } 951 | } 952 | } 953 | } 954 | 955 | bool if_find_class(vectorClassTmap, CXXRecordDecl* rd) 956 | { 957 | if (ClassTmap.size() == 0) 958 | return false; 959 | vector::iterator it = ClassTmap.begin(), it_end = ClassTmap.end(); 960 | for (; it != it_end; it++) 961 | { 962 | if ((*it)->get_cxxrd() == rd) 963 | return true; 964 | } 965 | return false; 966 | } 967 | 968 | CTmap* classTmap::getMap() 969 | { 970 | return ↦ 971 | } 972 | 973 | void classTmap::classCopy(classTmap* temp) 974 | { 975 | rd = temp->rd; 976 | 977 | cxxmds.clear(); 978 | vector::iterator it_cxxmd = temp->cxxmds.begin(), 979 | it_cxxmd_end = temp->cxxmds.end(); 980 | for (; it_cxxmd != it_cxxmd_end; it_cxxmd++) 981 | { 982 | cxxmds.push_back((*it_cxxmd)); 983 | } 984 | 985 | fds.clear(); 986 | vector::iterator it_fd = temp->fds.begin(), 987 | it_fd_end = temp->fds.end(); 988 | for (; it_fd != it_fd_end; it_fd++) 989 | { 990 | fds.push_back((*it_fd)); 991 | } 992 | 993 | map.CopyMap(temp->map); 994 | 995 | methodNum = temp->methodNum; 996 | varNum = temp->varNum; 997 | 998 | } 999 | 1000 | void classTmap::classUnion(classTmap* m, classTmap* a, classTmap* b) 1001 | { 1002 | if (a->rd != b->rd) 1003 | cout << "不允许不同的classTmap的合并" << endl; 1004 | 1005 | //classTmap map_re; 1006 | m->classCopy(a); 1007 | m->map.unionMap(b->map); 1008 | } 1009 | 1010 | void classTmap::classClear() 1011 | { 1012 | cxxmds.clear(); 1013 | fds.clear(); 1014 | map.clear(); 1015 | } 1016 | 1017 | classTmap* getClassTmap(CXXRecordDecl* rd) 1018 | { 1019 | int size = ClassTmap.size(); 1020 | for (int i = 0; i < size; i++) 1021 | { 1022 | if (ClassTmap[i]->get_cxxrd() == rd) 1023 | return ClassTmap[i]; 1024 | } 1025 | return NULL; 1026 | } 1027 | -------------------------------------------------------------------------------- /ASTReader/TaintedStmtAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "TaintedStmtAnalysis.h" 2 | 3 | //Tainted_Attr *StmtTa = new Tainted_Attr(); //each statement only has one common StmtTa 4 | 5 | /* 6 | interface function ,used to scan CFG Blocks each a time 7 | referenced by 8 | void checkCFG(clang::CFG &cfg, CTmap &tm, callgraph *cg) 9 | defined in "CFGtattr.cpp" 10 | */ 11 | 12 | extern vector Callgraph; 13 | CFGBlock *CFGB; 14 | 15 | bool checkblock(CFGBlock* cfgb, CTmap &out, callgraph* cg) 16 | { 17 | int i = 0; 18 | CFGB = cfgb; 19 | CFGBlock::iterator v = cfgb->begin(); 20 | for (; v != cfgb->end(); v++) 21 | { 22 | i++; 23 | //scan each statement 24 | if (v->getKind() == CFGElement::Kind::Statement) 25 | { 26 | CFGStmt s = v->castAs(); 27 | Stmt_analysis(s.getStmt(), out, cg); 28 | //out.output(); 29 | } 30 | cout << "Stmt " << i << " has been analysised" << endl; 31 | } 32 | return false; 33 | } 34 | 35 | // 循环上界检测 36 | bool checkCond(const Stmt* stmt, CTmap &out, callgraph* cg) 37 | { 38 | if (stmt->getStmtClass() == Stmt::BinaryOperatorClass) 39 | { 40 | Tainted_Attr* lta, *rta; 41 | const BinaryOperator* bo = dyn_cast(stmt); 42 | lta = Expr_analysis(bo->getLHS(), out, cg); 43 | rta = Expr_analysis(bo->getRHS(), out, cg); 44 | if (lta->getVariableAttr() == RELATED || rta->getVariableAttr() == RELATED) 45 | { 46 | //Error kind = 3 47 | TCI * tci = new TCI; 48 | tci->fd = cg->getCur(); 49 | tci->re = new Tainted_Attr; 50 | tci->re->setType(TYPE_VARIABLE); 51 | tci->re->unionAttr(*lta, *rta); 52 | tci->type = 3; 53 | tci->vd = NULL; 54 | tci->expr = bo; 55 | tci->astcontext = cg->getASTContext(); 56 | cg->TCI_list.insert(cg->TCI_list.end(), tci); 57 | } 58 | } 59 | return true; 60 | } 61 | /* 62 | Analysis a statement and modify the outmap at the same time 63 | */ 64 | int Stmt_analysis(const Stmt* stmt, CTmap &out, callgraph* cg) 65 | { 66 | const DeclStmt* ds; 67 | const Decl* decl; 68 | const VarDecl* vd,*vd2; 69 | const Expr* expr; 70 | const UnaryOperator* uo; 71 | DeclGroupRef::const_iterator di; 72 | // const ReturnStmt* rs; 73 | 74 | /* 75 | analysis Stmt in different ways accroding to it's StmtClass 76 | */ 77 | switch (stmt->getStmtClass()) { 78 | case Stmt::CompoundStmtClass:break; 79 | case Stmt::WhileStmtClass: 80 | cout << "Get While Stmt Here" << endl; 81 | break; 82 | case Stmt::BinaryOperatorClass: 83 | expr = dyn_cast(stmt); 84 | Expr_analysis(expr, out, cg); 85 | break; 86 | 87 | //定义语句 88 | case Stmt::DeclStmtClass: 89 | ds = dyn_cast(stmt); 90 | if (ds->isSingleDecl()) 91 | { 92 | decl = ds->getSingleDecl(); 93 | vd = dyn_cast(decl); 94 | expr = vd->getInit(); 95 | if (expr != NULL) 96 | { 97 | if (out.getAttr(vd)->getType() == TYPE_POINTER) //指针定义 98 | { 99 | if (expr->getStmtClass() == Stmt::UnaryOperatorClass) 100 | { 101 | uo = dyn_cast(expr); 102 | if (uo->getOpcode() == UnaryOperatorKind::UO_AddrOf) //int *p = &a; 103 | { 104 | Tainted_Attr* ptr_p = out.getAttr(vd); 105 | //ptr_p->~Tainted_Attr(); 106 | ptr_p->setType(TYPE_POINTER); 107 | ptr_p->setPointer(Expr_analysis(uo->getSubExpr(),out,cg)); 108 | } 109 | } 110 | else if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) 111 | { 112 | vd2 = dyn_cast(dyn_cast(dyn_cast(expr)->getSubExpr())->getDecl()); 113 | out.getAttr(vd)->setPointer(out.getPointerAttr(vd2)); 114 | } 115 | else 116 | { 117 | Tainted_Attr* ptr_p = out.getAttr(vd); 118 | //ptr_p->~Tainted_Attr(); 119 | ptr_p = Expr_analysis(expr, out, cg); 120 | ptr_p->setType(TYPE_POINTER); 121 | } 122 | } 123 | else if (out.getAttr(vd)->getType() == TYPE_VARIABLE) //变量定义 124 | { 125 | out.var_attr_set(vd, Expr_analysis(expr, out, cg)); 126 | } 127 | } 128 | } 129 | else 130 | { 131 | di = ds->getDeclGroup().begin(); 132 | for (; di != ds->getDeclGroup().end(); di++) 133 | { 134 | vd = dyn_cast(*di); 135 | expr = vd->getInit(); 136 | if (expr != NULL) 137 | { 138 | if (out.getAttr(vd)->getType() == TYPE_POINTER) //指针定义 139 | { 140 | if (expr->getStmtClass() == Stmt::UnaryOperatorClass) 141 | { 142 | uo = dyn_cast(expr); 143 | if (uo->getOpcode() == UnaryOperatorKind::UO_AddrOf) //int *p = &a; 144 | { 145 | Tainted_Attr* ptr_p = out.getAttr(vd); 146 | //ptr_p->~Tainted_Attr(); 147 | ptr_p->setType(TYPE_POINTER); 148 | ptr_p->setPointer(Expr_analysis(uo->getSubExpr(), out, cg)); 149 | //out.var_attr_set(vd, ptr_p); 150 | } 151 | } 152 | else if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) 153 | { 154 | vd2 = dyn_cast(dyn_cast(dyn_cast(expr)->getSubExpr())->getDecl()); 155 | out.getAttr(vd)->setPointer(out.getPointerAttr(vd2)); 156 | } 157 | else 158 | { 159 | Tainted_Attr* ptr_p = out.getAttr(vd); 160 | //ptr_p->~Tainted_Attr(); 161 | ptr_p = Expr_analysis(expr, out, cg); 162 | ptr_p->setType(TYPE_POINTER); 163 | } 164 | } 165 | else if (out.getAttr(vd)->getType() == TYPE_VARIABLE) //变量定义 166 | { 167 | out.var_attr_set(vd, Expr_analysis(expr, out, cg)); 168 | } 169 | } 170 | } 171 | } 172 | break; 173 | case Stmt::ReturnStmtClass: 174 | expr = dyn_cast(stmt)->getRetValue(); 175 | //get tainted_attr of the return expr 176 | if (expr != NULL) 177 | { 178 | cg->get_return()->unionAttr(*Expr_analysis(expr, out, cg)); 179 | } 180 | break; 181 | case Stmt::CallExprClass: 182 | expr = dyn_cast (stmt); 183 | Expr_analysis(expr, out, cg); 184 | break; 185 | case Stmt::CompoundAssignOperatorClass: 186 | expr = dyn_cast (stmt); 187 | Expr_analysis(expr, out, cg); 188 | break; 189 | default:break; 190 | } 191 | return 0; 192 | } 193 | 194 | Tainted_Attr* Expr_analysis(const Expr* expr, CTmap &out, callgraph* cg) 195 | { 196 | const VarDecl *vd; 197 | const ImplicitCastExpr* icexpr; 198 | const DeclRefExpr* drexpr; 199 | const UnaryOperator* uo; 200 | const ParenExpr* pexpr; 201 | Tainted_Attr* temp; 202 | Tainted_Attr* res = new Tainted_Attr(); 203 | res->setType(TYPE_VARIABLE); 204 | if (expr == NULL) 205 | { 206 | return res; 207 | } 208 | switch (expr->getStmtClass()) { 209 | case Stmt::BinaryOperatorClass: 210 | return BinaryOperator_Expr_analysis(expr, out, cg); 211 | case Stmt::BlockExprClass:break; 212 | case Stmt::CallExprClass: 213 | return CallExpr_analysis(expr, out, cg); 214 | case Stmt::ImplicitCastExprClass: 215 | icexpr = dyn_cast(expr); 216 | return Expr_analysis(icexpr->getSubExpr(), out, cg); 217 | case Stmt::DeclRefExprClass: 218 | drexpr = dyn_cast(expr); 219 | vd = dyn_cast(drexpr->getDecl()); 220 | res->copy(out.getAttr(vd)); 221 | return res; 222 | case Stmt::IntegerLiteralClass: 223 | return res; 224 | case Stmt::UnaryOperatorClass: 225 | uo = dyn_cast(expr); 226 | if (uo->getOpcode() == UnaryOperatorKind::UO_Deref) 227 | { 228 | if (uo->getSubExpr()->getStmtClass() == Stmt::ImplicitCastExprClass) 229 | { 230 | icexpr = dyn_cast(uo->getSubExpr()); 231 | if (icexpr->getSubExpr()->getStmtClass() == Stmt::DeclRefExprClass) 232 | { 233 | drexpr = dyn_cast(icexpr->getSubExpr()); 234 | vd = dyn_cast(drexpr->getDecl()); 235 | if (out.getAttr(vd)->getType() == TYPE_POINTER) 236 | { 237 | cout << "::::::::::::::::::::::::::::::::::::::::::::::::::" << endl; 238 | return out.getAttr(vd)->getPointerAttr(); 239 | } 240 | } 241 | } 242 | else if (uo->getSubExpr()->getStmtClass() == Stmt::DeclRefExprClass) 243 | { 244 | drexpr = dyn_cast(uo->getSubExpr()); 245 | vd = dyn_cast(drexpr->getDecl()); 246 | if (out.getAttr(vd)->getType() == TYPE_POINTER) 247 | { 248 | //out.getAttr(vd)->getPointerAttr()->output(); 249 | return out.getAttr(vd)->getPointerAttr(); 250 | } 251 | } 252 | else 253 | { 254 | temp = Expr_analysis(uo->getSubExpr(), out, cg); 255 | 256 | //ErrorKind == 7 (取地址操作操作数污染) 257 | if (temp->getVariableAttr() == RELATED) 258 | { 259 | TCI * tci = new TCI; 260 | tci->fd = cg->getCur(); 261 | tci->re = temp; 262 | tci->type = 7; 263 | tci->vd = NULL; 264 | tci->expr = expr; 265 | tci->astcontext = cg->getASTContext(); 266 | cg->TCI_list.insert(cg->TCI_list.end(), tci); 267 | } 268 | } 269 | return res; 270 | } 271 | else 272 | { 273 | return Expr_analysis(uo->getSubExpr(), out, cg); 274 | } 275 | case Stmt::ArraySubscriptExprClass: 276 | return ArrayExpr_analysis(expr, out, cg); 277 | case Stmt::ParenExprClass: 278 | pexpr = dyn_cast(expr); 279 | return Expr_analysis(pexpr->getSubExpr(), out, cg); 280 | case Stmt::CompoundAssignOperatorClass: 281 | CompoundAssignOperator_Expr_analysis(expr,out,cg); 282 | default:break; 283 | } 284 | return res; 285 | } 286 | 287 | Tainted_Attr* BinaryOperator_Expr_analysis(const Expr* expr, CTmap &out, callgraph* cg) 288 | { 289 | Tainted_Attr* res = new Tainted_Attr(); 290 | res->setType(TYPE_VARIABLE); 291 | Tainted_Attr* ata = new Tainted_Attr(); 292 | ata->setType(TYPE_VARIABLE); 293 | const BinaryOperator* bo = dyn_cast(expr); 294 | const Expr* lexpr = bo->getLHS(); 295 | const Expr* rexpr = bo->getRHS(); 296 | const VarDecl *vd,*lvd,*rvd; 297 | const DeclRefExpr* drexpr; 298 | const UnaryOperator* uo; 299 | const ImplicitCastExpr* icexpr; 300 | const Expr* arrayBase; 301 | const Expr* arrayIdx; 302 | Tainted_Attr* lta, *rta,*temp; 303 | const ArraySubscriptExpr *asexpr; 304 | switch (bo->getOpcode()) { 305 | case BinaryOperatorKind::BO_LAnd: //if && is in a Expr other than IfExpr ,there is still some problens 306 | case BinaryOperatorKind::BO_Add: 307 | case BinaryOperatorKind::BO_And: 308 | case BinaryOperatorKind::BO_Div: 309 | case BinaryOperatorKind::BO_Mul: 310 | case BinaryOperatorKind::BO_Sub: 311 | case BinaryOperatorKind::BO_EQ: 312 | case BinaryOperatorKind::BO_GE: 313 | case BinaryOperatorKind::BO_GT: 314 | case BinaryOperatorKind::BO_LE: 315 | case BinaryOperatorKind::BO_LOr: 316 | case BinaryOperatorKind::BO_LT: 317 | case BinaryOperatorKind::BO_NE: 318 | case BinaryOperatorKind::BO_Or: 319 | case BinaryOperatorKind::BO_Rem: 320 | case BinaryOperatorKind::BO_Shl: 321 | case BinaryOperatorKind::BO_Shr: 322 | case BinaryOperatorKind::BO_Xor: 323 | lta = Expr_analysis(lexpr, out, cg); 324 | rta = Expr_analysis(rexpr, out, cg); 325 | 326 | //除模操作检测 327 | if (bo->getOpcode() == BinaryOperatorKind::BO_Div || bo->getOpcode() == BinaryOperatorKind::BO_Rem) 328 | { 329 | if (rta->getVariableAttr() == RELATED) 330 | { 331 | cout << "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" << endl; 332 | if (rexpr->getStmtClass() == Stmt::ImplicitCastExprClass) 333 | { 334 | cout << "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" << endl; 335 | icexpr = dyn_cast(rexpr); 336 | if (icexpr->getSubExpr()->getStmtClass() == Stmt::DeclRefExprClass) 337 | { 338 | drexpr = dyn_cast(icexpr->getSubExpr()); 339 | vd = dyn_cast(drexpr->getDecl()); 340 | } 341 | else if (icexpr->getSubExpr()->getStmtClass() == Stmt::UnaryOperatorClass) 342 | { 343 | uo = dyn_cast(icexpr->getSubExpr()); 344 | icexpr = dyn_cast(uo->getSubExpr()); 345 | drexpr = dyn_cast(icexpr->getSubExpr()); 346 | vd = dyn_cast(drexpr->getDecl()); 347 | } 348 | else if (icexpr->getSubExpr()->getStmtClass() == Stmt::ArraySubscriptExprClass) 349 | { 350 | asexpr = dyn_cast(icexpr); 351 | arrayBase = asexpr->getBase(); 352 | arrayIdx = asexpr->getIdx(); 353 | while (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass || arrayBase->getStmtClass() == Stmt::ImplicitCastExprClass) 354 | { 355 | if (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass) 356 | { 357 | asexpr = dyn_cast(arrayBase); 358 | arrayBase = asexpr->getBase(); 359 | arrayIdx = asexpr->getIdx(); 360 | } 361 | else 362 | { 363 | arrayBase = dyn_cast(asexpr->getBase())->getSubExpr(); 364 | } 365 | } 366 | drexpr = dyn_cast(arrayBase); 367 | vd = dyn_cast(drexpr->getDecl()); 368 | } 369 | Stmt *cond; 370 | cond = checkBeforeCond(*CFGB); 371 | if (cond != NULL) 372 | { 373 | if (cond->getStmtClass() == Stmt::BinaryOperatorClass) 374 | { 375 | bo = dyn_cast(cond); 376 | lexpr = bo->getLHS(); 377 | rexpr = bo->getRHS(); 378 | if (lexpr->getStmtClass() == Stmt::ImplicitCastExprClass) 379 | { 380 | icexpr = dyn_cast(lexpr); 381 | if (icexpr->getSubExpr()->getStmtClass() == Stmt::DeclRefExprClass) 382 | { 383 | drexpr = dyn_cast(icexpr->getSubExpr()); 384 | lvd = dyn_cast(drexpr->getDecl()); 385 | } 386 | else if (icexpr->getSubExpr()->getStmtClass() == Stmt::UnaryOperatorClass) 387 | { 388 | uo = dyn_cast(icexpr->getSubExpr()); 389 | drexpr = dyn_cast(uo->getSubExpr()); 390 | lvd = dyn_cast(drexpr->getDecl()); 391 | } 392 | else if (icexpr->getSubExpr()->getStmtClass() == Stmt::ArraySubscriptExprClass) 393 | { 394 | asexpr = dyn_cast(icexpr); 395 | arrayBase = asexpr->getBase(); 396 | arrayIdx = asexpr->getIdx(); 397 | while (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass || arrayBase->getStmtClass() == Stmt::ImplicitCastExprClass) 398 | { 399 | if (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass) 400 | { 401 | asexpr = dyn_cast(arrayBase); 402 | arrayBase = asexpr->getBase(); 403 | arrayIdx = asexpr->getIdx(); 404 | } 405 | else 406 | { 407 | arrayBase = dyn_cast(asexpr->getBase())->getSubExpr(); 408 | } 409 | } 410 | drexpr = dyn_cast(arrayBase); 411 | lvd = dyn_cast(drexpr->getDecl()); 412 | } 413 | } 414 | if (rexpr->getStmtClass() == Stmt::ImplicitCastExprClass) 415 | { 416 | icexpr = dyn_cast(rexpr); 417 | if (icexpr->getSubExpr()->getStmtClass() == Stmt::DeclRefExprClass) 418 | { 419 | drexpr = dyn_cast(icexpr->getSubExpr()); 420 | rvd = dyn_cast(drexpr->getDecl()); 421 | } 422 | else if (icexpr->getSubExpr()->getStmtClass() == Stmt::UnaryOperatorClass) 423 | { 424 | uo = dyn_cast(icexpr->getSubExpr()); 425 | drexpr = dyn_cast(uo->getSubExpr()); 426 | rvd = dyn_cast(drexpr->getDecl()); 427 | } 428 | else if (icexpr->getSubExpr()->getStmtClass() == Stmt::ArraySubscriptExprClass) 429 | { 430 | asexpr = dyn_cast(icexpr); 431 | arrayBase = asexpr->getBase(); 432 | arrayIdx = asexpr->getIdx(); 433 | while (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass || arrayBase->getStmtClass() == Stmt::ImplicitCastExprClass) 434 | { 435 | if (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass) 436 | { 437 | asexpr = dyn_cast(arrayBase); 438 | arrayBase = asexpr->getBase(); 439 | arrayIdx = asexpr->getIdx(); 440 | } 441 | else 442 | { 443 | arrayBase = dyn_cast(asexpr->getBase())->getSubExpr(); 444 | } 445 | } 446 | drexpr = dyn_cast(arrayBase); 447 | rvd = dyn_cast(drexpr->getDecl()); 448 | } 449 | } 450 | if (vd == lvd || vd ==rvd) 451 | { 452 | res->unionAttr(*lta, *rta); 453 | delete lta, rta; 454 | return res; 455 | } 456 | } 457 | } 458 | } 459 | TCI * tci = new TCI; 460 | tci->fd = cg->getCur(); 461 | tci->re = rta; 462 | tci->type = 2; 463 | tci->vd = NULL; 464 | tci->expr = expr; 465 | tci->astcontext = cg->getASTContext(); 466 | cg->TCI_list.insert(cg->TCI_list.end(), tci); 467 | } 468 | } 469 | res->unionAttr(*lta, *rta); 470 | delete lta,rta; 471 | return res; 472 | case BinaryOperatorKind::BO_AndAssign: 473 | case BinaryOperatorKind::BO_AddAssign: 474 | case BinaryOperatorKind::BO_DivAssign: 475 | case BinaryOperatorKind::BO_MulAssign: 476 | case BinaryOperatorKind::BO_SubAssign: 477 | case BinaryOperatorKind::BO_OrAssign: 478 | case BinaryOperatorKind::BO_RemAssign: 479 | case BinaryOperatorKind::BO_ShlAssign: 480 | case BinaryOperatorKind::BO_ShrAssign: 481 | case BinaryOperatorKind::BO_XorAssign: 482 | if (lexpr->getStmtClass() == Stmt::ArraySubscriptExprClass) 483 | { 484 | //多维函数,循环操作取数组名称 485 | asexpr = dyn_cast(lexpr); 486 | arrayBase = asexpr->getBase(); 487 | arrayIdx = asexpr->getIdx(); 488 | ata->unionAttr(*Expr_analysis(arrayIdx, out, cg)); 489 | while (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass || arrayBase->getStmtClass() == Stmt::ImplicitCastExprClass) 490 | { 491 | if (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass) 492 | { 493 | ata->unionAttr(*Expr_analysis(arrayIdx, out, cg)); 494 | asexpr = dyn_cast(arrayBase); 495 | arrayBase = asexpr->getBase(); 496 | arrayIdx = asexpr->getIdx(); 497 | } 498 | else 499 | { 500 | arrayBase = dyn_cast(asexpr->getBase())->getSubExpr(); 501 | } 502 | } 503 | drexpr = dyn_cast(arrayBase); 504 | 505 | //Error kind = 1 (array tainted) 506 | if (ata->getVariableAttr() == RELATED) 507 | { 508 | TCI * tci = new TCI; 509 | tci->fd = cg->getCur(); 510 | tci->re = ata; 511 | tci->type = 1; 512 | tci->vd = dyn_cast(drexpr->getDecl());; 513 | tci->expr = expr; 514 | tci->astcontext = cg->getASTContext(); 515 | cg->TCI_list.insert(cg->TCI_list.end(), tci); 516 | } 517 | } 518 | else if (lexpr->getStmtClass() == Stmt::UnaryOperatorClass) 519 | { 520 | cout << "::::::::::::::::::::::::LLALAL:::::::::::::::::::::::::::::::::" << endl; 521 | uo = dyn_cast(lexpr); 522 | if (uo->getOpcode() == UnaryOperatorKind::UO_Deref) //等号左边为取指针操作 523 | { 524 | res = Expr_analysis(rexpr, out, cg); 525 | if (uo->getSubExpr()->getStmtClass() == Stmt::ImplicitCastExprClass) 526 | { 527 | icexpr = dyn_cast(uo->getSubExpr()); 528 | drexpr = dyn_cast(icexpr->getSubExpr()); 529 | vd = dyn_cast(drexpr->getDecl()); 530 | if (out.getPointerAttr(vd) != NULL) 531 | out.getPointerAttr(vd)->unionAttr(*res); 532 | } 533 | else 534 | { 535 | temp = Expr_analysis(uo->getSubExpr(), out, cg); 536 | 537 | //ErrorKind == 7 538 | if (temp->getVariableAttr() == RELATED) 539 | { 540 | TCI * tci = new TCI; 541 | tci->fd = cg->getCur(); 542 | tci->re = temp; 543 | tci->type = 7; 544 | tci->vd = NULL; 545 | tci->expr = expr; 546 | tci->astcontext = cg->getASTContext(); 547 | cg->TCI_list.insert(cg->TCI_list.end(), tci); 548 | } 549 | } 550 | } 551 | } 552 | else 553 | { 554 | drexpr = dyn_cast(lexpr); 555 | } 556 | vd = dyn_cast(drexpr->getDecl()); //获取到最终的VarDecl 557 | 558 | rta = Expr_analysis(rexpr, out, cg); 559 | 560 | //除法操作检查 561 | if (bo->getOpcode() == BinaryOperatorKind::BO_DivAssign) 562 | { 563 | if (rta->getVariableAttr() == RELATED) 564 | { 565 | TCI * tci = new TCI; 566 | tci->fd = cg->getCur(); 567 | tci->re = rta; 568 | tci->type = 2; 569 | tci->vd = NULL; 570 | tci->expr = expr; 571 | tci->astcontext = cg->getASTContext(); 572 | cg->TCI_list.insert(cg->TCI_list.end(), tci); 573 | } 574 | } 575 | res->unionAttr(*rta); 576 | out.var_attr_set(vd, res); 577 | return res; 578 | 579 | //双目操作符为等号 580 | case BinaryOperatorKind::BO_Assign: 581 | if (lexpr->getStmtClass() == Stmt::ArraySubscriptExprClass) 582 | { 583 | //多维函数,循环操作取数组名称 584 | asexpr = dyn_cast(lexpr); 585 | arrayBase = asexpr->getBase(); 586 | arrayIdx = asexpr->getIdx(); 587 | ata->unionAttr(*Expr_analysis(arrayIdx, out, cg)); 588 | while (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass || arrayBase->getStmtClass() == Stmt::ImplicitCastExprClass) 589 | { 590 | if (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass) 591 | { 592 | asexpr = dyn_cast(arrayBase); 593 | arrayBase = asexpr->getBase(); 594 | arrayIdx = asexpr->getIdx(); 595 | ata->unionAttr(*Expr_analysis(arrayIdx, out, cg)); 596 | } 597 | else 598 | { 599 | arrayBase = dyn_cast(asexpr->getBase())->getSubExpr(); 600 | } 601 | } 602 | drexpr = dyn_cast(arrayBase); 603 | 604 | //Error kind = 1 (array tainted) 605 | if (ata->getVariableAttr() == RELATED) 606 | { 607 | TCI * tci = new TCI; 608 | tci->fd = cg->getCur(); 609 | tci->re = ata; 610 | tci->type = 1; 611 | tci->vd = dyn_cast(drexpr->getDecl());; 612 | tci->expr = expr; 613 | tci->astcontext = cg->getASTContext(); 614 | cg->TCI_list.insert(cg->TCI_list.end(), tci); 615 | } 616 | 617 | vd = dyn_cast(drexpr->getDecl()); 618 | res = Expr_analysis(rexpr, out, cg); 619 | out.var_attr_set(vd, res); 620 | 621 | } 622 | 623 | else if (lexpr->getStmtClass() == Stmt::UnaryOperatorClass) 624 | { 625 | uo = dyn_cast(lexpr); 626 | if (uo->getOpcode() == UnaryOperatorKind::UO_Deref) //等号左边为取指针操作 627 | { 628 | res = Expr_analysis(rexpr, out, cg); 629 | if (uo->getSubExpr()->getStmtClass() == Stmt::ImplicitCastExprClass) 630 | { 631 | icexpr = dyn_cast(uo->getSubExpr()); 632 | drexpr = dyn_cast(icexpr->getSubExpr()); 633 | vd = dyn_cast(drexpr->getDecl()); 634 | if (out.getPointerAttr(vd) != NULL) 635 | out.getPointerAttr(vd)->copy(res); 636 | } 637 | else 638 | { 639 | temp = Expr_analysis(uo->getSubExpr(), out, cg); 640 | 641 | //ErrorKind == 7 642 | if (temp->getVariableAttr() == RELATED) 643 | { 644 | TCI * tci = new TCI; 645 | tci->fd = cg->getCur(); 646 | tci->re = temp; 647 | tci->type = 7; 648 | tci->vd = NULL; 649 | tci->expr = expr; 650 | tci->astcontext = cg->getASTContext(); 651 | cg->TCI_list.insert(cg->TCI_list.end(), tci); 652 | } 653 | } 654 | } 655 | } 656 | else 657 | { 658 | drexpr = dyn_cast(lexpr); 659 | vd = dyn_cast(drexpr->getDecl()); 660 | if (rexpr->getStmtClass() == Stmt::UnaryOperatorClass) 661 | { 662 | uo = dyn_cast(rexpr); 663 | if (uo->getOpcode() == UnaryOperatorKind::UO_AddrOf) 664 | { 665 | Tainted_Attr* ptr_p = out.getAttr(vd); 666 | ptr_p->~Tainted_Attr(); 667 | ptr_p->setType(TYPE_POINTER); 668 | res = Expr_analysis(uo->getSubExpr(), out, cg); 669 | ptr_p->setPointer(res); 670 | return res; 671 | } 672 | } 673 | 674 | res = Expr_analysis(rexpr, out, cg); 675 | out.var_attr_set(vd, res); 676 | } 677 | return res; 678 | case BinaryOperatorKind::BO_Comma: 679 | Expr_analysis(lexpr, out, cg); 680 | Expr_analysis(rexpr, out, cg); 681 | return res; 682 | case BinaryOperatorKind::BO_PtrMemD:break; 683 | case BinaryOperatorKind::BO_PtrMemI:break; 684 | default:break; 685 | } 686 | return res; 687 | } 688 | 689 | Tainted_Attr* CompoundAssignOperator_Expr_analysis(const Expr* expr, CTmap &out, callgraph* cg) 690 | { 691 | Tainted_Attr* res = new Tainted_Attr(); 692 | res->setType(TYPE_VARIABLE); 693 | Tainted_Attr* ata = new Tainted_Attr(); 694 | ata->setType(TYPE_VARIABLE); 695 | const CompoundAssignOperator* cao = dyn_cast(expr); 696 | const Expr* lexpr = cao->getLHS(); 697 | const Expr* rexpr = cao->getRHS(); 698 | const VarDecl *vd; 699 | const DeclRefExpr* drexpr; 700 | const UnaryOperator* uo; 701 | const ImplicitCastExpr* icexpr; 702 | const Expr* arrayBase; 703 | const Expr* arrayIdx; 704 | Tainted_Attr* lta, *rta, *temp; 705 | const ArraySubscriptExpr *asexpr; 706 | if (lexpr->getStmtClass() == Stmt::ArraySubscriptExprClass) 707 | { 708 | //多维函数,循环操作取数组名称 709 | asexpr = dyn_cast(lexpr); 710 | arrayBase = asexpr->getBase(); 711 | arrayIdx = asexpr->getIdx(); 712 | ata->unionAttr(*Expr_analysis(arrayIdx, out, cg)); 713 | while (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass || arrayBase->getStmtClass() == Stmt::ImplicitCastExprClass) 714 | { 715 | if (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass) 716 | { 717 | ata->unionAttr(*Expr_analysis(arrayIdx, out, cg)); 718 | asexpr = dyn_cast(arrayBase); 719 | arrayBase = asexpr->getBase(); 720 | arrayIdx = asexpr->getIdx(); 721 | } 722 | else 723 | { 724 | arrayBase = dyn_cast(asexpr->getBase())->getSubExpr(); 725 | } 726 | } 727 | drexpr = dyn_cast(arrayBase); 728 | 729 | //Error kind = 1 (array tainted) 730 | if (ata->getVariableAttr() == RELATED) 731 | { 732 | TCI * tci = new TCI; 733 | tci->fd = cg->getCur(); 734 | tci->re = ata; 735 | tci->type = 1; 736 | tci->vd = dyn_cast(drexpr->getDecl());; 737 | tci->expr = expr; 738 | tci->astcontext = cg->getASTContext(); 739 | cg->TCI_list.insert(cg->TCI_list.end(), tci); 740 | } 741 | } 742 | else if (lexpr->getStmtClass() == Stmt::UnaryOperatorClass) 743 | { 744 | cout << "::::::::::::::::::::::::LLALAL:::::::::::::::::::::::::::::::::" << endl; 745 | uo = dyn_cast(lexpr); 746 | if (uo->getOpcode() == UnaryOperatorKind::UO_Deref) //等号左边为取指针操作 747 | { 748 | res = Expr_analysis(rexpr, out, cg); 749 | if (uo->getSubExpr()->getStmtClass() == Stmt::ImplicitCastExprClass) 750 | { 751 | icexpr = dyn_cast(uo->getSubExpr()); 752 | drexpr = dyn_cast(icexpr->getSubExpr()); 753 | vd = dyn_cast(drexpr->getDecl()); 754 | if (out.getPointerAttr(vd) != NULL) 755 | out.getPointerAttr(vd)->unionAttr(*res); 756 | } 757 | else 758 | { 759 | temp = Expr_analysis(uo->getSubExpr(), out, cg); 760 | 761 | //ErrorKind == 7 762 | if (temp->getVariableAttr() == RELATED) 763 | { 764 | TCI * tci = new TCI; 765 | tci->fd = cg->getCur(); 766 | tci->re = temp; 767 | tci->type = 7; 768 | tci->vd = NULL; 769 | tci->expr = expr; 770 | tci->astcontext = cg->getASTContext(); 771 | cg->TCI_list.insert(cg->TCI_list.end(), tci); 772 | } 773 | } 774 | } 775 | } 776 | else 777 | { 778 | drexpr = dyn_cast(lexpr); 779 | } 780 | vd = dyn_cast(drexpr->getDecl()); //获取到最终的VarDecl 781 | 782 | rta = Expr_analysis(rexpr, out, cg); 783 | 784 | //除法操作检查 785 | if (cao->getOpcode() == BinaryOperatorKind::BO_DivAssign) 786 | { 787 | if (rta->getVariableAttr() == RELATED) 788 | { 789 | TCI * tci = new TCI; 790 | tci->fd = cg->getCur(); 791 | tci->re = rta; 792 | tci->type = 2; 793 | tci->vd = NULL; 794 | tci->expr = expr; 795 | tci->astcontext = cg->getASTContext(); 796 | cg->TCI_list.insert(cg->TCI_list.end(), tci); 797 | } 798 | } 799 | res->unionAttr(*rta); 800 | out.var_attr_set(vd, res); 801 | return res; 802 | } 803 | 804 | Tainted_Attr* CallExpr_analysis(const Expr* expr, CTmap &out, callgraph* cg) 805 | { 806 | Tainted_Attr* res = new Tainted_Attr(); 807 | res->setType(TYPE_VARIABLE); 808 | const CallExpr* cexpr; 809 | const FunctionDecl* fd; 810 | callgraph* calleeCg; 811 | cexpr = dyn_cast(expr); 812 | fd = cexpr->getDirectCallee(); 813 | calleeCg = findById(Callgraph, fd->getQualifiedNameAsString()); 814 | if (calleeCg == NULL) //the function can't be found ,which means its in the lib 815 | { 816 | /* 817 | if (strcmp(fd->getQualifiedNameAsString, "free") 818 | { 819 | } 820 | if (cexpr->getNumArgs() == 1) 821 | { 822 | cout << "11111111111111111111111111111111111111111111111111111111" << endl; 823 | //return Expr_analysis(cexpr->getArg(),out,cg); 824 | } 825 | else if (cexpr->getNumArgs() > 1) 826 | { 827 | cout << "22222222222222222222222222222222222" << endl; 828 | } 829 | */ 830 | } 831 | else 832 | { 833 | /* 834 | check if the funtion has been analysised 835 | */ 836 | //cout << cg->is_callee(fd) << ":::::::::::::::::::::::::::::::::::::::" << endl; 837 | if (cg->is_callee(fd)) 838 | { 839 | if (calleeCg->get_if_check_cfg() == false) 840 | { 841 | checkCFG(*(calleeCg->get_cfg()), calleeCg->getCTmap(), calleeCg); 842 | calleeCg->set_if_check_cfg(); 843 | } 844 | int n = calleeCg->getParamNum(); 845 | Tainted_Attr *tp = new Tainted_Attr[n]; 846 | 847 | set::iterator it = calleeCg->get_return()->getVariableRelation()->begin(), it_end = calleeCg->get_return()->getVariableRelation()->end(); 848 | int argNo; 849 | int i = 0; 850 | while (it != it_end) 851 | { 852 | argNo = calleeCg->get_param_no(*it); 853 | if (argNo == -1) 854 | { 855 | cout << "argNo == -1 which means it can't be found" << endl; 856 | } 857 | else 858 | { 859 | tp[i].copy(Expr_analysis(cexpr->getArg(argNo), out, cg)); 860 | //tp[i].output(); 861 | //cout << endl; 862 | res->unionAttr(tp[i]); //将形参序号转化为实参的具体Expr 863 | //res->output(); 864 | //cout << endl; 865 | } 866 | i++; 867 | it++; 868 | } 869 | BuildSecondList(cg, calleeCg, tp, n); 870 | delete[] tp; 871 | } 872 | else 873 | { 874 | return res; 875 | } 876 | } 877 | return res; 878 | } 879 | 880 | Tainted_Attr* ArrayExpr_analysis(const Expr* expr, CTmap &out, callgraph* cg) 881 | { 882 | Tainted_Attr* res = new Tainted_Attr(); 883 | res->setType(TYPE_VARIABLE); 884 | const ArraySubscriptExpr *asexpr; 885 | const Expr* arrayBase; 886 | const Expr* arrayIdx; 887 | const VarDecl* vd; 888 | const ImplicitCastExpr* icexpr; 889 | const DeclRefExpr* drexpr; 890 | asexpr = dyn_cast(expr); 891 | arrayBase = asexpr->getBase(); 892 | arrayIdx = asexpr->getIdx(); 893 | while (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass || arrayBase->getStmtClass() == Stmt::ImplicitCastExprClass) 894 | { 895 | if (arrayBase->getStmtClass() == Stmt::ArraySubscriptExprClass) 896 | { 897 | res->unionAttr(*Expr_analysis(arrayIdx, out, cg)); 898 | asexpr = dyn_cast(arrayBase); 899 | arrayBase = asexpr->getBase(); 900 | arrayIdx = asexpr->getIdx(); 901 | } 902 | else 903 | { 904 | arrayBase = dyn_cast(asexpr->getBase())->getSubExpr(); 905 | } 906 | } 907 | res->unionAttr(*Expr_analysis(arrayIdx, out, cg)); 908 | if (arrayBase->getStmtClass() == Stmt::ImplicitCastExprClass) 909 | { 910 | icexpr = dyn_cast(arrayBase); 911 | arrayBase = icexpr->getSubExpr(); 912 | } 913 | if (arrayBase->getStmtClass() == Stmt::DeclRefExprClass) 914 | { 915 | drexpr = dyn_cast(expr); 916 | vd = dyn_cast(drexpr->getDecl()); 917 | 918 | //Error kind = 1 (array tainted) 919 | if (res->getVariableAttr() == RELATED) 920 | { 921 | TCI * tci = new TCI; 922 | tci->fd = cg->getCur(); 923 | tci->re = res; 924 | tci->type = 1; 925 | tci->vd = vd; 926 | tci->expr = expr; 927 | tci->astcontext = cg->getASTContext(); 928 | cg->TCI_list.insert(cg->TCI_list.end(), tci); 929 | } 930 | out.var_attr_set(vd, res); 931 | } 932 | else //exception 933 | { 934 | cout << "ArrayBase is not a Decl or ImplicateCast" << endl; 935 | } 936 | return res; 937 | } 938 | -------------------------------------------------------------------------------- /ASTReader/tinyxmlparser.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | www.sourceforge.net/projects/tinyxml 3 | Original code by Lee Thomason (www.grinninglizard.com) 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any 7 | damages arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any 10 | purpose, including commercial applications, and to alter it and 11 | redistribute it freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must 14 | not claim that you wrote the original software. If you use this 15 | software in a product, an acknowledgment in the product documentation 16 | would be appreciated but is not required. 17 | 18 | 2. Altered source versions must be plainly marked as such, and 19 | must not be misrepresented as being the original software. 20 | 21 | 3. This notice may not be removed or altered from any source 22 | distribution. 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | #include "tinyxml.h" 29 | 30 | //#define DEBUG_PARSER 31 | #if defined( DEBUG_PARSER ) 32 | # if defined( DEBUG ) && defined( _MSC_VER ) 33 | # include 34 | # define TIXML_LOG OutputDebugString 35 | # else 36 | # define TIXML_LOG printf 37 | # endif 38 | #endif 39 | 40 | // Note tha "PutString" hardcodes the same list. This 41 | // is less flexible than it appears. Changing the entries 42 | // or order will break putstring. 43 | TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = 44 | { 45 | { "&", 5, '&' }, 46 | { "<", 4, '<' }, 47 | { ">", 4, '>' }, 48 | { """, 6, '\"' }, 49 | { "'", 6, '\'' } 50 | }; 51 | 52 | // Bunch of unicode info at: 53 | // http://www.unicode.org/faq/utf_bom.html 54 | // Including the basic of this table, which determines the #bytes in the 55 | // sequence from the lead byte. 1 placed for invalid sequences -- 56 | // although the result will be junk, pass it through as much as possible. 57 | // Beware of the non-characters in UTF-8: 58 | // ef bb bf (Microsoft "lead bytes") 59 | // ef bf be 60 | // ef bf bf 61 | 62 | const unsigned char TIXML_UTF_LEAD_0 = 0xefU; 63 | const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; 64 | const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; 65 | 66 | const int TiXmlBase::utf8ByteTable[256] = 67 | { 68 | // 0 1 2 3 4 5 6 7 8 9 a b c d e f 69 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 70 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 71 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 72 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 73 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 74 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 75 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 76 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range 77 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid 78 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 79 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 80 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 81 | 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte 82 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 83 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte 84 | 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid 85 | }; 86 | 87 | 88 | void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) 89 | { 90 | const unsigned long BYTE_MASK = 0xBF; 91 | const unsigned long BYTE_MARK = 0x80; 92 | const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 93 | 94 | if (input < 0x80) 95 | *length = 1; 96 | else if ( input < 0x800 ) 97 | *length = 2; 98 | else if ( input < 0x10000 ) 99 | *length = 3; 100 | else if ( input < 0x200000 ) 101 | *length = 4; 102 | else 103 | { *length = 0; return; } // This code won't covert this correctly anyway. 104 | 105 | output += *length; 106 | 107 | // Scary scary fall throughs. 108 | switch (*length) 109 | { 110 | case 4: 111 | --output; 112 | *output = (char)((input | BYTE_MARK) & BYTE_MASK); 113 | input >>= 6; 114 | case 3: 115 | --output; 116 | *output = (char)((input | BYTE_MARK) & BYTE_MASK); 117 | input >>= 6; 118 | case 2: 119 | --output; 120 | *output = (char)((input | BYTE_MARK) & BYTE_MASK); 121 | input >>= 6; 122 | case 1: 123 | --output; 124 | *output = (char)(input | FIRST_BYTE_MARK[*length]); 125 | } 126 | } 127 | 128 | 129 | /*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) 130 | { 131 | // This will only work for low-ascii, everything else is assumed to be a valid 132 | // letter. I'm not sure this is the best approach, but it is quite tricky trying 133 | // to figure out alhabetical vs. not across encoding. So take a very 134 | // conservative approach. 135 | 136 | // if ( encoding == TIXML_ENCODING_UTF8 ) 137 | // { 138 | if ( anyByte < 127 ) 139 | return isalpha( anyByte ); 140 | else 141 | return 1; // What else to do? The unicode set is huge...get the english ones right. 142 | // } 143 | // else 144 | // { 145 | // return isalpha( anyByte ); 146 | // } 147 | } 148 | 149 | 150 | /*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) 151 | { 152 | // This will only work for low-ascii, everything else is assumed to be a valid 153 | // letter. I'm not sure this is the best approach, but it is quite tricky trying 154 | // to figure out alhabetical vs. not across encoding. So take a very 155 | // conservative approach. 156 | 157 | // if ( encoding == TIXML_ENCODING_UTF8 ) 158 | // { 159 | if ( anyByte < 127 ) 160 | return isalnum( anyByte ); 161 | else 162 | return 1; // What else to do? The unicode set is huge...get the english ones right. 163 | // } 164 | // else 165 | // { 166 | // return isalnum( anyByte ); 167 | // } 168 | } 169 | 170 | 171 | class TiXmlParsingData 172 | { 173 | friend class TiXmlDocument; 174 | public: 175 | void Stamp( const char* now, TiXmlEncoding encoding ); 176 | 177 | const TiXmlCursor& Cursor() const { return cursor; } 178 | 179 | private: 180 | // Only used by the document! 181 | TiXmlParsingData( const char* start, int _tabsize, int row, int col ) 182 | { 183 | assert( start ); 184 | stamp = start; 185 | tabsize = _tabsize; 186 | cursor.row = row; 187 | cursor.col = col; 188 | } 189 | 190 | TiXmlCursor cursor; 191 | const char* stamp; 192 | int tabsize; 193 | }; 194 | 195 | 196 | void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) 197 | { 198 | assert( now ); 199 | 200 | // Do nothing if the tabsize is 0. 201 | if ( tabsize < 1 ) 202 | { 203 | return; 204 | } 205 | 206 | // Get the current row, column. 207 | int row = cursor.row; 208 | int col = cursor.col; 209 | const char* p = stamp; 210 | assert( p ); 211 | 212 | while ( p < now ) 213 | { 214 | // Treat p as unsigned, so we have a happy compiler. 215 | const unsigned char* pU = (const unsigned char*)p; 216 | 217 | // Code contributed by Fletcher Dunn: (modified by lee) 218 | switch (*pU) { 219 | case 0: 220 | // We *should* never get here, but in case we do, don't 221 | // advance past the terminating null character, ever 222 | return; 223 | 224 | case '\r': 225 | // bump down to the next line 226 | ++row; 227 | col = 0; 228 | // Eat the character 229 | ++p; 230 | 231 | // Check for \r\n sequence, and treat this as a single character 232 | if (*p == '\n') { 233 | ++p; 234 | } 235 | break; 236 | 237 | case '\n': 238 | // bump down to the next line 239 | ++row; 240 | col = 0; 241 | 242 | // Eat the character 243 | ++p; 244 | 245 | // Check for \n\r sequence, and treat this as a single 246 | // character. (Yes, this bizarre thing does occur still 247 | // on some arcane platforms...) 248 | if (*p == '\r') { 249 | ++p; 250 | } 251 | break; 252 | 253 | case '\t': 254 | // Eat the character 255 | ++p; 256 | 257 | // Skip to next tab stop 258 | col = (col / tabsize + 1) * tabsize; 259 | break; 260 | 261 | case TIXML_UTF_LEAD_0: 262 | if ( encoding == TIXML_ENCODING_UTF8 ) 263 | { 264 | if ( *(p+1) && *(p+2) ) 265 | { 266 | // In these cases, don't advance the column. These are 267 | // 0-width spaces. 268 | if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) 269 | p += 3; 270 | else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) 271 | p += 3; 272 | else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) 273 | p += 3; 274 | else 275 | { p +=3; ++col; } // A normal character. 276 | } 277 | } 278 | else 279 | { 280 | ++p; 281 | ++col; 282 | } 283 | break; 284 | 285 | default: 286 | if ( encoding == TIXML_ENCODING_UTF8 ) 287 | { 288 | // Eat the 1 to 4 byte utf8 character. 289 | int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; 290 | if ( step == 0 ) 291 | step = 1; // Error case from bad encoding, but handle gracefully. 292 | p += step; 293 | 294 | // Just advance one column, of course. 295 | ++col; 296 | } 297 | else 298 | { 299 | ++p; 300 | ++col; 301 | } 302 | break; 303 | } 304 | } 305 | cursor.row = row; 306 | cursor.col = col; 307 | assert( cursor.row >= -1 ); 308 | assert( cursor.col >= -1 ); 309 | stamp = p; 310 | assert( stamp ); 311 | } 312 | 313 | 314 | const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) 315 | { 316 | if ( !p || !*p ) 317 | { 318 | return 0; 319 | } 320 | if ( encoding == TIXML_ENCODING_UTF8 ) 321 | { 322 | while ( *p ) 323 | { 324 | const unsigned char* pU = (const unsigned char*)p; 325 | 326 | // Skip the stupid Microsoft UTF-8 Byte order marks 327 | if ( *(pU+0)==TIXML_UTF_LEAD_0 328 | && *(pU+1)==TIXML_UTF_LEAD_1 329 | && *(pU+2)==TIXML_UTF_LEAD_2 ) 330 | { 331 | p += 3; 332 | continue; 333 | } 334 | else if(*(pU+0)==TIXML_UTF_LEAD_0 335 | && *(pU+1)==0xbfU 336 | && *(pU+2)==0xbeU ) 337 | { 338 | p += 3; 339 | continue; 340 | } 341 | else if(*(pU+0)==TIXML_UTF_LEAD_0 342 | && *(pU+1)==0xbfU 343 | && *(pU+2)==0xbfU ) 344 | { 345 | p += 3; 346 | continue; 347 | } 348 | 349 | if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. 350 | ++p; 351 | else 352 | break; 353 | } 354 | } 355 | else 356 | { 357 | while ( *p && IsWhiteSpace( *p ) ) 358 | ++p; 359 | } 360 | 361 | return p; 362 | } 363 | 364 | #ifdef TIXML_USE_STL 365 | /*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) 366 | { 367 | for( ;; ) 368 | { 369 | if ( !in->good() ) return false; 370 | 371 | int c = in->peek(); 372 | // At this scope, we can't get to a document. So fail silently. 373 | if ( !IsWhiteSpace( c ) || c <= 0 ) 374 | return true; 375 | 376 | *tag += (char) in->get(); 377 | } 378 | } 379 | 380 | /*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) 381 | { 382 | //assert( character > 0 && character < 128 ); // else it won't work in utf-8 383 | while ( in->good() ) 384 | { 385 | int c = in->peek(); 386 | if ( c == character ) 387 | return true; 388 | if ( c <= 0 ) // Silent failure: can't get document at this scope 389 | return false; 390 | 391 | in->get(); 392 | *tag += (char) c; 393 | } 394 | return false; 395 | } 396 | #endif 397 | 398 | // One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The 399 | // "assign" optimization removes over 10% of the execution time. 400 | // 401 | const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) 402 | { 403 | // Oddly, not supported on some comilers, 404 | //name->clear(); 405 | // So use this: 406 | *name = ""; 407 | assert( p ); 408 | 409 | // Names start with letters or underscores. 410 | // Of course, in unicode, tinyxml has no idea what a letter *is*. The 411 | // algorithm is generous. 412 | // 413 | // After that, they can be letters, underscores, numbers, 414 | // hyphens, or colons. (Colons are valid ony for namespaces, 415 | // but tinyxml can't tell namespaces from names.) 416 | if ( p && *p 417 | && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) 418 | { 419 | const char* start = p; 420 | while( p && *p 421 | && ( IsAlphaNum( (unsigned char ) *p, encoding ) 422 | || *p == '_' 423 | || *p == '-' 424 | || *p == '.' 425 | || *p == ':' ) ) 426 | { 427 | //(*name) += *p; // expensive 428 | ++p; 429 | } 430 | if ( p-start > 0 ) { 431 | name->assign( start, p-start ); 432 | } 433 | return p; 434 | } 435 | return 0; 436 | } 437 | 438 | const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) 439 | { 440 | // Presume an entity, and pull it out. 441 | TIXML_STRING ent; 442 | int i; 443 | *length = 0; 444 | 445 | if ( *(p+1) && *(p+1) == '#' && *(p+2) ) 446 | { 447 | unsigned long ucs = 0; 448 | ptrdiff_t delta = 0; 449 | unsigned mult = 1; 450 | 451 | if ( *(p+2) == 'x' ) 452 | { 453 | // Hexadecimal. 454 | if ( !*(p+3) ) return 0; 455 | 456 | const char* q = p+3; 457 | q = strchr( q, ';' ); 458 | 459 | if ( !q || !*q ) return 0; 460 | 461 | delta = q-p; 462 | --q; 463 | 464 | while ( *q != 'x' ) 465 | { 466 | if ( *q >= '0' && *q <= '9' ) 467 | ucs += mult * (*q - '0'); 468 | else if ( *q >= 'a' && *q <= 'f' ) 469 | ucs += mult * (*q - 'a' + 10); 470 | else if ( *q >= 'A' && *q <= 'F' ) 471 | ucs += mult * (*q - 'A' + 10 ); 472 | else 473 | return 0; 474 | mult *= 16; 475 | --q; 476 | } 477 | } 478 | else 479 | { 480 | // Decimal. 481 | if ( !*(p+2) ) return 0; 482 | 483 | const char* q = p+2; 484 | q = strchr( q, ';' ); 485 | 486 | if ( !q || !*q ) return 0; 487 | 488 | delta = q-p; 489 | --q; 490 | 491 | while ( *q != '#' ) 492 | { 493 | if ( *q >= '0' && *q <= '9' ) 494 | ucs += mult * (*q - '0'); 495 | else 496 | return 0; 497 | mult *= 10; 498 | --q; 499 | } 500 | } 501 | if ( encoding == TIXML_ENCODING_UTF8 ) 502 | { 503 | // convert the UCS to UTF-8 504 | ConvertUTF32ToUTF8( ucs, value, length ); 505 | } 506 | else 507 | { 508 | *value = (char)ucs; 509 | *length = 1; 510 | } 511 | return p + delta + 1; 512 | } 513 | 514 | // Now try to match it. 515 | for( i=0; iappend( cArr, len ); 594 | } 595 | } 596 | else 597 | { 598 | bool whitespace = false; 599 | 600 | // Remove leading white space: 601 | p = SkipWhiteSpace( p, encoding ); 602 | while ( p && *p 603 | && !StringEqual( p, endTag, caseInsensitive, encoding ) ) 604 | { 605 | if ( *p == '\r' || *p == '\n' ) 606 | { 607 | whitespace = true; 608 | ++p; 609 | } 610 | else if ( IsWhiteSpace( *p ) ) 611 | { 612 | whitespace = true; 613 | ++p; 614 | } 615 | else 616 | { 617 | // If we've found whitespace, add it before the 618 | // new character. Any whitespace just becomes a space. 619 | if ( whitespace ) 620 | { 621 | (*text) += ' '; 622 | whitespace = false; 623 | } 624 | int len; 625 | char cArr[4] = { 0, 0, 0, 0 }; 626 | p = GetChar( p, cArr, &len, encoding ); 627 | if ( len == 1 ) 628 | (*text) += cArr[0]; // more efficient 629 | else 630 | text->append( cArr, len ); 631 | } 632 | } 633 | } 634 | if ( p && *p ) 635 | p += strlen( endTag ); 636 | return ( p && *p ) ? p : 0; 637 | } 638 | 639 | #ifdef TIXML_USE_STL 640 | 641 | void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) 642 | { 643 | // The basic issue with a document is that we don't know what we're 644 | // streaming. Read something presumed to be a tag (and hope), then 645 | // identify it, and call the appropriate stream method on the tag. 646 | // 647 | // This "pre-streaming" will never read the closing ">" so the 648 | // sub-tag can orient itself. 649 | 650 | if ( !StreamTo( in, '<', tag ) ) 651 | { 652 | SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); 653 | return; 654 | } 655 | 656 | while ( in->good() ) 657 | { 658 | int tagIndex = (int) tag->length(); 659 | while ( in->good() && in->peek() != '>' ) 660 | { 661 | int c = in->get(); 662 | if ( c <= 0 ) 663 | { 664 | SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); 665 | break; 666 | } 667 | (*tag) += (char) c; 668 | } 669 | 670 | if ( in->good() ) 671 | { 672 | // We now have something we presume to be a node of 673 | // some sort. Identify it, and call the node to 674 | // continue streaming. 675 | TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); 676 | 677 | if ( node ) 678 | { 679 | node->StreamIn( in, tag ); 680 | bool isElement = node->ToElement() != 0; 681 | delete node; 682 | node = 0; 683 | 684 | // If this is the root element, we're done. Parsing will be 685 | // done by the >> operator. 686 | if ( isElement ) 687 | { 688 | return; 689 | } 690 | } 691 | else 692 | { 693 | SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); 694 | return; 695 | } 696 | } 697 | } 698 | // We should have returned sooner. 699 | SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); 700 | } 701 | 702 | #endif 703 | 704 | const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) 705 | { 706 | ClearError(); 707 | 708 | // Parse away, at the document level. Since a document 709 | // contains nothing but other tags, most of what happens 710 | // here is skipping white space. 711 | if ( !p || !*p ) 712 | { 713 | SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); 714 | return 0; 715 | } 716 | 717 | // Note that, for a document, this needs to come 718 | // before the while space skip, so that parsing 719 | // starts from the pointer we are given. 720 | location.Clear(); 721 | if ( prevData ) 722 | { 723 | location.row = prevData->cursor.row; 724 | location.col = prevData->cursor.col; 725 | } 726 | else 727 | { 728 | location.row = 0; 729 | location.col = 0; 730 | } 731 | TiXmlParsingData data( p, TabSize(), location.row, location.col ); 732 | location = data.Cursor(); 733 | 734 | if ( encoding == TIXML_ENCODING_UNKNOWN ) 735 | { 736 | // Check for the Microsoft UTF-8 lead bytes. 737 | const unsigned char* pU = (const unsigned char*)p; 738 | if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 739 | && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 740 | && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) 741 | { 742 | encoding = TIXML_ENCODING_UTF8; 743 | useMicrosoftBOM = true; 744 | } 745 | } 746 | 747 | p = SkipWhiteSpace( p, encoding ); 748 | if ( !p ) 749 | { 750 | SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); 751 | return 0; 752 | } 753 | 754 | while ( p && *p ) 755 | { 756 | TiXmlNode* node = Identify( p, encoding ); 757 | if ( node ) 758 | { 759 | p = node->Parse( p, &data, encoding ); 760 | LinkEndChild( node ); 761 | } 762 | else 763 | { 764 | break; 765 | } 766 | 767 | // Did we get encoding info? 768 | if ( encoding == TIXML_ENCODING_UNKNOWN 769 | && node->ToDeclaration() ) 770 | { 771 | TiXmlDeclaration* dec = node->ToDeclaration(); 772 | const char* enc = dec->Encoding(); 773 | assert( enc ); 774 | 775 | if ( *enc == 0 ) 776 | encoding = TIXML_ENCODING_UTF8; 777 | else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) 778 | encoding = TIXML_ENCODING_UTF8; 779 | else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) 780 | encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice 781 | else 782 | encoding = TIXML_ENCODING_LEGACY; 783 | } 784 | 785 | p = SkipWhiteSpace( p, encoding ); 786 | } 787 | 788 | // Was this empty? 789 | if ( !firstChild ) { 790 | SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); 791 | return 0; 792 | } 793 | 794 | // All is well. 795 | return p; 796 | } 797 | 798 | void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) 799 | { 800 | // The first error in a chain is more accurate - don't set again! 801 | if ( error ) 802 | return; 803 | 804 | assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); 805 | error = true; 806 | errorId = err; 807 | errorDesc = errorString[ errorId ]; 808 | 809 | errorLocation.Clear(); 810 | if ( pError && data ) 811 | { 812 | data->Stamp( pError, encoding ); 813 | errorLocation = data->Cursor(); 814 | } 815 | } 816 | 817 | 818 | TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) 819 | { 820 | TiXmlNode* returnNode = 0; 821 | 822 | p = SkipWhiteSpace( p, encoding ); 823 | if( !p || !*p || *p != '<' ) 824 | { 825 | return 0; 826 | } 827 | 828 | p = SkipWhiteSpace( p, encoding ); 829 | 830 | if ( !p || !*p ) 831 | { 832 | return 0; 833 | } 834 | 835 | // What is this thing? 836 | // - Elements start with a letter or underscore, but xml is reserved. 837 | // - Comments: "; 1351 | 1352 | if ( !StringEqual( p, startTag, false, encoding ) ) 1353 | { 1354 | if ( document ) 1355 | document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); 1356 | return 0; 1357 | } 1358 | p += strlen( startTag ); 1359 | 1360 | // [ 1475201 ] TinyXML parses entities in comments 1361 | // Oops - ReadText doesn't work, because we don't want to parse the entities. 1362 | // p = ReadText( p, &value, false, endTag, false, encoding ); 1363 | // 1364 | // from the XML spec: 1365 | /* 1366 | [Definition: Comments may appear anywhere in a document outside other markup; in addition, 1367 | they may appear within the document type declaration at places allowed by the grammar. 1368 | They are not part of the document's character data; an XML processor MAY, but need not, 1369 | make it possible for an application to retrieve the text of comments. For compatibility, 1370 | the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity 1371 | references MUST NOT be recognized within comments. 1372 | 1373 | An example of a comment: 1374 | 1375 | 1376 | */ 1377 | 1378 | value = ""; 1379 | // Keep all the white space. 1380 | while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) 1381 | { 1382 | value.append( p, 1 ); 1383 | ++p; 1384 | } 1385 | if ( p && *p ) 1386 | p += strlen( endTag ); 1387 | 1388 | return p; 1389 | } 1390 | 1391 | 1392 | const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) 1393 | { 1394 | p = SkipWhiteSpace( p, encoding ); 1395 | if ( !p || !*p ) return 0; 1396 | 1397 | if ( data ) 1398 | { 1399 | data->Stamp( p, encoding ); 1400 | location = data->Cursor(); 1401 | } 1402 | // Read the name, the '=' and the value. 1403 | const char* pErr = p; 1404 | p = ReadName( p, &name, encoding ); 1405 | if ( !p || !*p ) 1406 | { 1407 | if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); 1408 | return 0; 1409 | } 1410 | p = SkipWhiteSpace( p, encoding ); 1411 | if ( !p || !*p || *p != '=' ) 1412 | { 1413 | if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); 1414 | return 0; 1415 | } 1416 | 1417 | ++p; // skip '=' 1418 | p = SkipWhiteSpace( p, encoding ); 1419 | if ( !p || !*p ) 1420 | { 1421 | if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); 1422 | return 0; 1423 | } 1424 | 1425 | const char* end; 1426 | const char SINGLE_QUOTE = '\''; 1427 | const char DOUBLE_QUOTE = '\"'; 1428 | 1429 | if ( *p == SINGLE_QUOTE ) 1430 | { 1431 | ++p; 1432 | end = "\'"; // single quote in string 1433 | p = ReadText( p, &value, false, end, false, encoding ); 1434 | } 1435 | else if ( *p == DOUBLE_QUOTE ) 1436 | { 1437 | ++p; 1438 | end = "\""; // double quote in string 1439 | p = ReadText( p, &value, false, end, false, encoding ); 1440 | } 1441 | else 1442 | { 1443 | // All attribute values should be in single or double quotes. 1444 | // But this is such a common error that the parser will try 1445 | // its best, even without them. 1446 | value = ""; 1447 | while ( p && *p // existence 1448 | && !IsWhiteSpace( *p ) // whitespace 1449 | && *p != '/' && *p != '>' ) // tag end 1450 | { 1451 | if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { 1452 | // [ 1451649 ] Attribute values with trailing quotes not handled correctly 1453 | // We did not have an opening quote but seem to have a 1454 | // closing one. Give up and throw an error. 1455 | if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); 1456 | return 0; 1457 | } 1458 | value += *p; 1459 | ++p; 1460 | } 1461 | } 1462 | return p; 1463 | } 1464 | 1465 | #ifdef TIXML_USE_STL 1466 | void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) 1467 | { 1468 | while ( in->good() ) 1469 | { 1470 | int c = in->peek(); 1471 | if ( !cdata && (c == '<' ) ) 1472 | { 1473 | return; 1474 | } 1475 | if ( c <= 0 ) 1476 | { 1477 | TiXmlDocument* document = GetDocument(); 1478 | if ( document ) 1479 | document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); 1480 | return; 1481 | } 1482 | 1483 | (*tag) += (char) c; 1484 | in->get(); // "commits" the peek made above 1485 | 1486 | if ( cdata && c == '>' && tag->size() >= 3 ) { 1487 | size_t len = tag->size(); 1488 | if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { 1489 | // terminator of cdata. 1490 | return; 1491 | } 1492 | } 1493 | } 1494 | } 1495 | #endif 1496 | 1497 | const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) 1498 | { 1499 | value = ""; 1500 | TiXmlDocument* document = GetDocument(); 1501 | 1502 | if ( data ) 1503 | { 1504 | data->Stamp( p, encoding ); 1505 | location = data->Cursor(); 1506 | } 1507 | 1508 | const char* const startTag = ""; 1510 | 1511 | if ( cdata || StringEqual( p, startTag, false, encoding ) ) 1512 | { 1513 | cdata = true; 1514 | 1515 | if ( !StringEqual( p, startTag, false, encoding ) ) 1516 | { 1517 | if ( document ) 1518 | document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); 1519 | return 0; 1520 | } 1521 | p += strlen( startTag ); 1522 | 1523 | // Keep all the white space, ignore the encoding, etc. 1524 | while ( p && *p 1525 | && !StringEqual( p, endTag, false, encoding ) 1526 | ) 1527 | { 1528 | value += *p; 1529 | ++p; 1530 | } 1531 | 1532 | TIXML_STRING dummy; 1533 | p = ReadText( p, &dummy, false, endTag, false, encoding ); 1534 | return p; 1535 | } 1536 | else 1537 | { 1538 | bool ignoreWhite = true; 1539 | 1540 | const char* end = "<"; 1541 | p = ReadText( p, &value, ignoreWhite, end, false, encoding ); 1542 | if ( p && *p ) 1543 | return p-1; // don't truncate the '<' 1544 | return 0; 1545 | } 1546 | } 1547 | 1548 | #ifdef TIXML_USE_STL 1549 | void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) 1550 | { 1551 | while ( in->good() ) 1552 | { 1553 | int c = in->get(); 1554 | if ( c <= 0 ) 1555 | { 1556 | TiXmlDocument* document = GetDocument(); 1557 | if ( document ) 1558 | document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); 1559 | return; 1560 | } 1561 | (*tag) += (char) c; 1562 | 1563 | if ( c == '>' ) 1564 | { 1565 | // All is well. 1566 | return; 1567 | } 1568 | } 1569 | } 1570 | #endif 1571 | 1572 | const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) 1573 | { 1574 | p = SkipWhiteSpace( p, _encoding ); 1575 | // Find the beginning, find the end, and look for 1576 | // the stuff in-between. 1577 | TiXmlDocument* document = GetDocument(); 1578 | if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); 1581 | return 0; 1582 | } 1583 | if ( data ) 1584 | { 1585 | data->Stamp( p, _encoding ); 1586 | location = data->Cursor(); 1587 | } 1588 | p += 5; 1589 | 1590 | version = ""; 1591 | encoding = ""; 1592 | standalone = ""; 1593 | 1594 | while ( p && *p ) 1595 | { 1596 | if ( *p == '>' ) 1597 | { 1598 | ++p; 1599 | return p; 1600 | } 1601 | 1602 | p = SkipWhiteSpace( p, _encoding ); 1603 | if ( StringEqual( p, "version", true, _encoding ) ) 1604 | { 1605 | TiXmlAttribute attrib; 1606 | p = attrib.Parse( p, data, _encoding ); 1607 | version = attrib.Value(); 1608 | } 1609 | else if ( StringEqual( p, "encoding", true, _encoding ) ) 1610 | { 1611 | TiXmlAttribute attrib; 1612 | p = attrib.Parse( p, data, _encoding ); 1613 | encoding = attrib.Value(); 1614 | } 1615 | else if ( StringEqual( p, "standalone", true, _encoding ) ) 1616 | { 1617 | TiXmlAttribute attrib; 1618 | p = attrib.Parse( p, data, _encoding ); 1619 | standalone = attrib.Value(); 1620 | } 1621 | else 1622 | { 1623 | // Read over whatever it is. 1624 | while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) 1625 | ++p; 1626 | } 1627 | } 1628 | return 0; 1629 | } 1630 | 1631 | bool TiXmlText::Blank() const 1632 | { 1633 | for ( unsigned i=0; i