@yinnner
2018-12-20T13:55:59.000000Z
字数 9174
阅读 1047
论文地址:Towards security defect prediction with AI
代码仓库地址:sa-bAbI
核心文件:
sa_babi/
.
├── generate.py # 主要生成代码的文件
├── sa_tag.py # 每行代码性质标签
└── templates.py # 生成不同模块(控制流、函数体等)的模版
如果要添加漏洞种类,则则需要往sa_tag.py
中添加新的行标签,往templates.py
中添加新的模块模版。
generate.py
重要函数逻辑如下:
main()
函数逻辑generators
(含有各种例子生成器的数组) linear_only
表示代码顺序执行,不包含控制流,生成器只有一种。有以下几种生成器,对应相应的函数:
buffe write 格式:"$buf_var[$idx_var] = '$char';"
fv含义:free variable
函数名/生成器 | 作用 |
---|---|
gen_cond_example | idx_var经过while循环模块得到 |
gen_for_example | $idx_var经过for循环模块得到 |
gen_fv_cond_example | 有一个自由变量,经过if条件判断模块 |
gen_fv_while_example | 有一个自由变量,经过while循环模块 |
gen_fv_for_example | 有一个自由变量,for循环模块 |
gen_tautonly_linear_example | 不经过控制流直接进行不安全的buffer write |
以上生成器逻辑几乎相同,只是需要的变量和判断safe的条件不一样。逻辑如下:
_get_anon_vars()
生成得到。dummy_vars
,只用来传递数值,实际不起什么作用。_get_char()
生成得到。substitutions
字典将其封装好。templates.xxx_MAIN_LINES
。safe
用来指示。templates.xxx_DEC_INIT_PAIRS
。_assemble_general_example
组装模块生成代码。gen_tautonly_linear_example
函数由于不经过控制流,直接进行buffer write,因此所有变量都是dummy_vars
,substitutions
、main_lines
、dec_init_pairs
均为空。
如果要添加漏洞种类,我觉得可以按照以上函数的模式写gen_xxx_{Vulnerability Name}_example
7个对应函数,具体是否要写那么多个要看漏洞的性质,main函数可能只需要少量改动。
_assemble_general_example()
组装模块函数逻辑:
main_lines
加一句templates.BUFWRITE_LINES
。_get_lines
得到所有代码行。(这个函数及相应调用函数需要修改。)_get_tags
得到所有代码行标签。_get_instance_str
得到最终c语言代码文本。_get_lines()
获得所有代码行,包含声明初始化、主体内容、dummy变量
(只用来传递数值,实际不起什么作用)的使用。函数逻辑:
_get_setup_lines
获得声明初始化代码行。include_cond_bufwrite == True
),则为最后一个代码行(即为buffer write代码)打上Tag.BUFWRITE_COND_SAFE
或 Tag.BUFWRITE_COND_UNSAFE
(通过safe
判断)。_insert_dummies
为现有代码行添加dummy变量相关的代码行。_insert_dummies()
插入所有dummy变量的声明和赋值语句。函数逻辑如下:
num_dummies
次,调用_insert_referential_dummy
依次插入每一个dummy变量的相关代码行。_insert_referential_dummy()
插入指定dummy变量的声明、初始化和buffer write语句。这里面出现的buffer write不经过控制流,因此标签为BUFWRITE_TAUT_SAFE 或 BUFWRITE_TAUT_UNSAFE。
函数逻辑如下:
dum_len
和buffer write需要用到的下标dum_idx
。dum_buf_var
;指示buffer write位置的下标——dum_int_var
。lines
中。dum_idx
、 dum_len
的大小关系判断buffer write是否安全。body_tags
中。_test()
测试每个生成器生成代码。
这个函数大部分不需要修改,只需要改从745-757
行测试标签种类的代码。
函数名 | 作用 |
---|---|
_get_char() | 获得一个字符 |
_get_anon_vars() | 获得MAX_NUM_VARS 个变量并打乱 |
_get_tags() | 获得完整的标签,即加上函数主体外的其他标签(#include... int main() {return 0;} ) |
_get_instance_str() | 替换模版中的文本并获得最终c语言代码文本。 |
_get_setup_lines() | 获得打乱顺序的声明初始化变量代码行 |
_get_args() | 设置命令行参数格式并获得命令行参数(可能会修改) |
_get_full_template() | 似乎这个文件里面没有使用到 |
*.c.tok
文件*.c.tok
文件是按json格式组织的,在tokenizer工具中生成的,是在执行完生成源文件数据后才进行的步骤。
首先明确深度学习神经网络里面的一些概念:
以上三者的关系是:一般情况下,一趟会训练一次整个的训练集;在一趟中分steps_per_epoch步进行,一步处理batch_size个数据。即 训练集数据总数。
[ 1., 0., 0.]
表示苹果,[ 0., 1., 0.]
表示雪梨,[ 0., 0., 1.]
表示香蕉。这样便于代码使用。用np.argmax()
就可获得最大值的下标,由于数组只有0、1,取最大值就取到了1所在的索引,其实就获得了标签索引。逻辑如下:
utils.load_data()
从npy文件中获得代码实例矩阵instances_mat
、标签矩阵labels_mat
和 训练集与验证集字典索引partition
。datagen.DataGenerator()
得到数据生成器data_generator
。num_classes
。run_experiments
开始训练。逻辑如下:
datagen.DataGenerator()
得到验证集数据生成器val_data_generator
。datagen.generate_balanced()
从验证集数据生成器中得到平均了每个类分布(每个类的分布是相同的)后的生成器,再调用next
返回该生成器的下一个项目,即获得验证集代码实例矩阵val_instances_mat
、验证集标签矩阵val_labels_mat
。np.argmax()
可获得验证集标签索引数组y_true
。np.zeros()
初始化混淆矩阵(误差矩阵)cnf_matrices
。juliet_memnet.get_model()
获得未训练的网络model
。predics
sklearn.metrics.confusion_matrix()
获得预测结果和标签y_true
的混淆矩阵并将其存入数组中。==注意:只要import juliet_memnet
就会执行这段代码!!==
utils.generate_sa_data()
生成sa_babi数据(就是这一步会调用utils.save_data()
生成npy文件)utils.load_data()
从npy文件加载获得代码实例矩阵instances_mat
、标签矩阵labels_mat
和 训练集与验证集分割后的字典索引partition
。datagen.DataGenerator()
得到数据生成器data_generator
。预处理数据:
from sa_babi.sa_tag import Tag
获得所有标签。生成sa_babi数据矩阵并且保存到工作目录中。
输入参数:
working_dir
:保存数据的工作目录,默认是sa-train-1000coarse_labels
:一般不管他。布尔类型,如果是true,表明只有安全和不安全两种情况,默认为false。逻辑如下:
get_examples()
从tokens/*.c.tok
获得实例instance
、标签labels
、路径paths。set()
获得不重复的标签集合unique_elements
。tautonly_elements
。is_tautonly
。coarse_labels
或者is_tautonly
,重新映射labels里的标签,即不区分TAUT
和COND
,只保留safe
和unsafe
。get_vocab_mapping()
获得词汇映射为整数的字典。get_data_dimensions()
获得数据的维数:实例数目、最大行数、最大行长。get_example_matrices()
获得实例矩阵、标签矩阵。get_partition()
获得训练集与验证集分割后的字典索引partition
。print_data_stats()
打印数据。save_data()
将实例矩阵、标签矩阵、整数映射字典、分割数据集的字典、路径存入npy文件和pkl文件中。从tokens/*.c.tok
获得实例instance
、标签labels
、路径paths。
返回值含义如下:
instance[i][j][k]
是第i个文件第j行第k个token字符串。
instances: list of list of list of str
instances[i][j][k] represents
- the i-th CWE121 C example
- the j-th line
- the k-th token in that line
labels[i][j]
是第i个文件第j行对应标签的整数值。
labels: list of list of int
labels[i][j] represents
- the i-th CWE121 C example
- the j-th line
in SA: the value is the integer Tag value
paths
这些*.c.tok*
文件的路径数组。该函数逻辑如下:
*.c.tok*
文件的路径数组path_list
。ann_tok_to_lines()
得到代码行数组lines
。lines
,获得包含代码行号和tokens的实例代码数组instances
: labels
: *.c.tok*
与对应的 *.c
文件名称相同,因此通过*.c.tok*
文件名加上路径拼接找到对应的 *.c
文件路径。*.c
文件路径为参数,调用get_sa_tags()
获得sa_babi数据集标签数组tags
。*.c.tok*
文件中不包含include行,因此移除相应的标签。tags
中标签对应整数构成最后所需的标签。将instances、labels转换为以0填充的np数组。
返回值含义如下:
instances_mat
:代码实例矩阵,3维np数组,各维度最大值:[num_examples, max_numlines, max_linelen]labels_mat
:标签矩阵:2维np数组,各维度最大值: [num_examples, max_numlines]。 labels_mat[i][j]
是第i个文件第j行的标签函数逻辑如下:
get_data_dimensions()
获得数据的维数:实例数目、最大行数、最大行长。get_vocab_mapping()
获得词汇映射为整数的字典。instances_mat
、labels_mat
。instances
中的token
,来给instances_mat
中token对应位置赋映射字典中对应的整数值;同时在两层循环的地方,将labels
对应的值直接复制给labels_mat
对应的值,注意此时的labels
已经合并了body和other标签。获得训练集与验证集分割后的字典索引partition
。
逻辑如下:
partition
字典结果如下:
partition = {
'train': idx_list[:num_train],
'validation': idx_list[num_train:]
}
将*.c.tok
文件转换为代码行数组lines
。
*.c.tok
文件格式如下:
{
"filename": "/mnt/data/src/0a8b6849a9.c",
"tokens": [
{
"kind": "Keyword",
"line": 2,
"sem": "FunctionDecl",
"text": "int"
},
{
"kind": "Identifier",
"line": 2,
"sem": "FunctionDecl",
"sym": {
"id": "c:@F@main",
"kind": "FunctionDecl",
"type": "int ()"
},
"text": "main"
},
....
]
}
函数逻辑如下:
tok_data
。line_data
,该字典长这样——{行号:token字符串数组}。注意这里行号从1开始,但是为了统一从0开始索引,规定line_data[0]=[]
。tok_data
,将token加入字典中对应行号的数组里。lines
。获得从词汇元素(代码里的token)到整数的字典映射。
逻辑如下:
vocab
,有重复。sorted(list(set(vocab)))
获得无重复并且排序后的词汇。将实例矩阵、标签矩阵、整数映射字典、分割数据集的字典、路径存入npy文件和pkl文件中。
将实例矩阵、标签矩阵、整数映射字典、分割数据集的字典、路径从npy文件和pkl文件中加载出来。
print_data_stats()
:打印数据。get_data_dimensions()
:获得数据的维数:实例数目、最大行数、最大行长。get_sa_tags()
获得sa_babi数据集标签数组tags
。函数名 |
---|
generate_data() |
generate_choi_data() |
get_juliet_label() |
get_choi_examples() |
simp_tok_to_lines() |
get_vuln_lines() |
get_label_counts() |
get_tok_line() |
python validate.py
可能出现的问题和解决方法
找不到matplotlib模块——因为在enviroment.yml里被原作者注释了…,所以在sa_babi环境下
pip intall matplotlib
。在virtualenv环境下使用matplotlib绘图时遇到了这样的问题:
>>> import matplotlib.pyplot as plt
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
...
in <module>
from matplotlib.backends import _macosx
RuntimeError: Python is not installed as a framework. The Mac OS X backend will not be able to function correctly if Python is not installed as a framework. See the Python documentation for more information on installing Python as a framework on Mac OS X. Please either reinstall Python as a framework, or try one of the other backends. If you are Working with Matplotlib in a virtual enviroment see 'Working with Matplotlib in Virtual environments' in the Matplotlib FAQ
解决方案来自https://www.cnblogs.com/harelion/p/5637767.html:
似乎是因为虚拟环境与默认环境的安装配置不同造成的。
搜索错误信息之后,在STO上找到了解决方案:
1、pip安装matplotlib之后,会在根目录下产生一个.matplotlib的目录:
cd ~/.matplotlib
total 280
-rw-r--r-- 1 me staff 78K 10 4 2015 fontList.cache
-rw-r--r-- 1 me staff 59K 1 17 15:56 fontList.py3k.cache
drwxr-xr-x 2 me staff 68B 10 4 2015 tex.cache
2、在这个目录下创建一个名为
matplotlibrc
的文件,内容是:
backend: TkAgg
然后保存退出,重启Python交互界面或重新运行脚本,import正常执行。
STO答案地址:http://stackoverflow.com/questions/21784641/installation-issue-with-matplotlib-python
- 似乎跑到后面还会报错,还没解决....