1# TEE 安全驱动开发指导<a name="ZH-CN_TOPIC_0000001212014566"></a> 2 3## 概述<a name="section351681313544"></a> 4 5### 功能简介<a name="section167701178548"></a> 6 7本文对TEE安全驱动的开发流程、接口、函数库等进行说明,指导驱动开发者进行安全驱动程序的开发与调试工作。 8 9### 约束与限制<a name="section67447370556"></a> 10 11- 开发的驱动程序仅支持在TEE可信执行环境子系统上加载和运行。 12 13### 场景介绍<a name="section148731215195617"></a> 14 15目前TEEOS支持内置驱动的开发,驱动和TEEOS镜像共同编译打包。具体开发指导请参考开发示例章节。 16 17## 驱动开发框架<a name="section12432132218372"></a> 18 19驱动开发整体可以分为两部分,第一个是驱动业务开发框架,第二个是访问该驱动的驱动访问者框架。 20 21### 驱动业务框架<a name="section6705194712373"></a> 22 23为方便各个驱动开发统一,TEE可信执行环境子系统为各个驱动设计了一套基础框架,如下所示,驱动开发者结合驱动实际逻辑分别定义这些基础函数即可。 24``` 25#define DRV_NAME_MAX_LEN 32U 26#define DRV_RESERVED_NUM 8U 27 28struct drv_data { 29 int32_t fd; /* fd信息,对应驱动的唯一标识 */ 30 uint32_t taskid; /* 访问者的taskid */ 31 void *private_data; /* 私有数据 */ 32 struct tee_uuid uuid; /* 访问者的uuid */ 33}; 34 35/* 驱动加载时初始化函数 */ 36typedef int32_t (*init_func)(void); 37 38/* 驱动在系统休眠时被调用的函数 */ 39typedef int32_t (*suspned_func)(void); 40 41/* 驱动在系统唤醒时被调用的函数 */ 42typedef int32_t (*resume_func)(void); 43 44/* 驱动被访问时命令分发函数 */ 45typedef int64_t (*ioctl_func)(struct drv_data *drv, uint32_t cmd, unsigned long args, uint32_t args_len); 46 47/* 驱动被访问时初始化函数 */ 48typedef int64_t (*open_func)(struct drv_data *drv, unsigned long args, uint32_t args_len); 49 50/* 驱动被访问结束时资源释放函数 */ 51typedef int64_t (*close_func)(struct drv_data *drv); 52 53struct tee_driver_module { 54 init_func init; 55 ioctl_func ioctl; 56 open_func open; 57 close_func close; 58 suspned_func suspend; 59 resume_func resume; 60 suspned_func suspend_s4; 61 resume_func resume_s4; 62 uint64_t reserved[DRV_RESERVED_NUM]; /* has not used, just reserved */ 63}; 64 65#define tee_driver_declare(name, init, open, ioctl, close, suspend, resume, suspend_s4, resume_s4) \ 66__attribute__((visibility("default"))) const struct tee_driver_module g_driver_##name = { \ 67 init, ioctl, open, close, suspend, resume, suspend_s4, resume_s4, {0} } 68``` 69 70结构体struct tee_driver_module便是每个驱动业务开发时需要注册的信息,各个变量说明如下: 71 72**表 1** 驱动业务开发注册信息表 73 74<a></a> 75<table><thead align="left"><tr><th class="cellrowborder" valign="top" width="33.33333333333333%"><p>变量名</p> 76</th> 77<th class="cellrowborder" valign="top" width="33.33333333333333%"><p>类型</p> 78</th> 79<th class="cellrowborder" valign="top" width="33.33333333333333%"><p>说明</p> 80</th> 81</tr> 82</thead> 83<tbody><tr><td><p>name</p></td> 84<td><p>常量字符串</p></td> 85<td><p>驱动名字,每个驱动必须唯一,有效长度小于32个字节,仅支持数字、字母和'_'。</p></td> 86</tr> 87<tr><td><p>init</p></td> 88<td><p>init_func函数指针</p></td> 89<td><p>驱动加载时初始化函数。</p></td> 90</tr> 91<tr><td><p>open</p></td> 92<td><p>函数指针</p></td> 93<td><p>驱动被访问时初始化函数。</p></td> 94</tr> 95<tr><td><p>ioctl</p></td> 96<td><p>函数指针</p></td> 97<td><p>驱动被访问时命令分发函数。</p></td> 98</tr> 99<tr><td><p>close</p></td> 100<td><p>函数指针</p></td> 101<td><p>驱动被访问结束时资源释放函数。</p></td> 102</tr> 103<tr><td><p>suspend</p></td> 104<td><p>函数指针</p></td> 105<td><p>驱动在系统休眠时被调用的函数。</p></td> 106</tr> 107<tr><td><p>resume</p></td> 108<td><p>函数指针</p></td> 109<td><p>驱动在系统唤醒时被调用的函数。</p></td> 110</tr> 111<tr><td><p>suspend_s4</p></td> 112<td><p>函数指针</p></td> 113<td><p>驱动在系统休眠时被调用的函数,对应linux kernel里freeze_noirq操作流程。</p></td> 114</tr> 115<tr><td><p>resume_s4</p></td> 116<td><p>函数指针</p></td> 117<td><p>驱动在系统唤醒时被调用的函数,对应linux kernel里restore_noirq操作流程。</p></td> 118</tr> 119<tr><td><p>reserved</p></td> 120<td><p>预留</p></td> 121<td><p>现有框架暂未使用。</p></td> 122</tr> 123</tbody> 124</table> 125 126**表 2** 驱动业务框架接口说明 127<a></a> 128<table><thead><tr><th class="cellrowborder" valign="top" width="50%"><p>接口名</p> 129</th> 130<th class="cellrowborder" valign="top" width="50%"><p>描述</p> 131</th> 132</tr> 133</thead> 134<tbody><tr><td><p>int32_t (*init_func)(void)</p></td> 135<td><p>该函数是在驱动加载完后便被驱动框架调用的初始化函数,其主要作用是在该驱动被访问之前进行初始化操作。该函数在驱动加载后的整个生命周期内只会被调用一次。</p> 136<p><b>返回值:</b></p> 137<p>0:初始化成功</p> 138<p>非0:初始化失败</p></td> 139</tr> 140<tr><td><p>int64_t (*open_func)(struct drv_data *drv, unsigned long args, uint32_t args_len)</p></td> 141<td><p>该函数是驱动访问者访问驱动时调用的初始化函数,其主要作用是在驱动里申请一个fd,并进行初始化。该函数在每次新增驱动访问时都会调用。</p> 142<p><b>参数:</b></p> 143<p>drv:入参,表示此次open该驱动的fd所有信息</p> 144<p>args:入参,表示给驱动传入参数对应的buffer地址,由驱动访问者设置</p> 145<p>args_len:入参,表示给驱动传入参数对应的buffer长度,由驱动访问者设置</p> 146<p><b>返回值:</b></p> 147<p>非正数:异常值</p> 148<p>其他:返回的fd信息</p></td> 149</tr> 150<tr><td><p>int64_t (*ioctl_func)(struct drv_data *drv, uint32_t cmd, unsigned long args, uint32_t args_len)</p></td> 151<td><p>该函数是驱动在open初始化之后,进行的一系列针对业务逻辑的操作。其主要作用是根据传入的drv获取fd资源信息,再执行cmd命令对应的执行流,其中[args.args_len]组成的buffer信息是给该cmd执行流传入的参数。</p> 152<p><b>参数:</b></p> 153<p>drv:入参,表示此次ioctl该驱动的fd所有信息,fd由驱动访问者传入,驱动框架根据fd传入对应drv_data结构体</p> 154<p>cmd:入参,表示此次ioctl该驱动传入的命令号,驱动可根据不同命令号执行不同的业务逻辑,由驱动访问者设置</p> 155<p>args:入参,表示给驱动传递参数的buffer基地址</p> 156<p>args_len:入参,表示给驱动传递参数的buffer长度</p> 157<p><b>返回值:</b></p> 158<p>0:操作成功</p> 159<p>-1:操作失败,框架层面返回的异常值</p> 160<p>其他值:操作失败,驱动自行定义的异常值</p></td> 161</tr> 162<tr><td><p>int64_t (*close_func)(struct drv_data *drv)</p></td> 163<td><p>该函数主要作用是在驱动业务逻辑访问结束后进行对该fd对应的资源清理操作。</p> 164<p><b>参数:</b></p> 165<p>drv:入参,表示此次ioctl该驱动的fd所有信息</p> 166<p><b>返回值:</b></p> 167<p>0:操作成功</p> 168<p>非0:操作失败</p></td> 169</tr> 170<tr><td><p>int32_t (*suspned_func)(void)</p></td> 171<td><p>该函数主要作用是此驱动休眠状态下的一些列操作,会在系统休眠时有驱动框架自行调用。</p> 172<p><b>返回值:</b></p> 173<p>0:操作成功</p> 174<p>非0:操作失败</p></td> 175</tr> 176<tr><td><p>int32_t (*resume_func)(void)</p></td> 177<td><p>该函数主要作用是此驱动唤醒态下的一系列操作,会在系统唤醒流程中由驱动框架自行调用,与suspend函数对应。</p> 178<p><b>返回值:</b></p> 179<p>0:操作成功</p> 180<p>非0:操作失败</p></td> 181</tr> 182</tbody> 183</table> 184 185### 驱动访问者框架<a name="section18123151133811"></a> 186 187驱动访问时,驱动访问者先调用tee_drv_open函数获取驱动唯一标记fd;再调用tee_drv_ioctl函数,传入cmd信息,访问该驱动对应cmd执行流,如果针对某个fd有多个ioctl执行流,多次调用tee_drv_ioctl即可;如果访问结束,驱动访问者还需要调用tee_drv_close函数关闭该fd信息。 188 189**表 3** 驱动访问者框架接口说明 190 191<a></a> 192<table><thead><tr><th class="cellrowborder" valign="top" width="50%"><p>接口名</p> 193</th> 194<th class="cellrowborder" valign="top" width="50%"><p>描述</p> 195</th> 196</tr> 197</thead> 198<tbody><tr><td><p>int64_t tee_drv_open(const char *drv_name, const void *param, uint32_t param_len)</p></td> 199<td><p>主要作用是驱动访问者通过调用该函数,访问drv_name指定的驱动,调用驱动的open函数,返回与该驱动对应的唯一标记fd信息。其中param buffer对应的内容组装结构由drv_name对应驱动定义,实际与驱动open函数里[args.args_len]表示的buffer内容一致。</p> 200<p><b>参数:</b></p> 201<p>drv_name:入参,表示要访问的驱动名称;</p> 202<p>param:入参,表示给驱动传递的参数地址;</p> 203<p>param_len:入参,表示给驱动传递的参数长度,与param组成的buffer内容便是给驱动传递的参数信息。</p> 204<p><b>返回值:</b></p> 205<p>非正数:非法值,操作失败</p> 206<p>大于0:fd信息,对应驱动的唯一标识</p></td> 207</tr> 208<tr><td><p>int64_t tee_drv_ioctl(int64_t fd, uint32_t cmd_id, const void *param, uint32_t param_len)</p></td> 209<td><p>主要作用是驱动访问者通过调用该函数,访问fd对应的驱动模块,执行命令ID号为cmd_id对应的业务逻辑,传入参数为param与param_len对应buffer存储的内容,其中param与param_len对应buffer内容组装结构由fd对应的驱动定义,实际与驱动ioctl函数[args.args_len]组成的buffer内容一致。</p> 210<p><b>参数:</b></p> 211<p>fd:入参,表示open该驱动成功返回时的返回值;</p> 212<p>cmd_id:入参,表示ioctl该驱动时对应的命令id号;</p> 213<p>param:入参,表示ioctl该驱动cmd_id流程时传入的参数基地址;</p> 214<p>param_len:入参,表示ioctl该驱动cmd_id流程时传入的参数buffer长度。与param组成的buffer内容便是给驱动命令号cmd_id对应的参数信息。</p> 215<p><b>返回值:</b></p> 216<p>0:操作成功</p> 217<p>-1:框架层面访问失败</p> 218<p>其他值:各驱动自定义失败返回值</p></td> 219</tr> 220<tr><td><p>int64_t tee_drv_close(int64_t fd)</p></td> 221<td><p>主要作用是关闭fd对应驱动信息,一般常见操作是释放该fd维护的驱动资源。</p> 222<p><b>返回值:</b></p> 223<p>0:操作成功</p> 224<p>-1:操作失败</p></td> 225</tr> 226</tbody> 227</table> 228 229## 接口说明<a name="section1748173625619"></a> 230 231### 地址转换接口说明<a name="section101297155716"></a> 232 233驱动进行地址转换操作需要使用的接口列表。 234 235**表 4** 地址转换接口列表 236 237<a name="table13739184111427"></a> 238<table><thead align="left"><tr id="row2739154118421"><th class="cellrowborder" valign="top" width="54.31%" id="mcps1.2.3.1.1"><p id="p462103214410"><a name="p462103214410"></a><a name="p462103214410"></a>接口名</p> 239</th> 240<th class="cellrowborder" valign="top" width="45.69%" id="mcps1.2.3.1.2"><p id="p1762163219448"><a name="p1762163219448"></a><a name="p1762163219448"></a>描述</p> 241</th> 242</tr> 243</thead> 244<tbody><tr id="row7739441104213"><td class="cellrowborder" valign="top" width="54.31%" headers="mcps1.2.3.1.1 "><p id="p137395418427"><a name="p137395418427"></a><a name="p137395418427"></a>uint64_t drv_virt_to_phys(uintptr_t addr);</p> 245</td> 246<td class="cellrowborder" valign="top" width="45.69%" headers="mcps1.2.3.1.2 "><p id="p177391841124218"><a name="p177391841124218"></a><a name="p177391841124218"></a>虚拟地址转换为物理地址。</p> 247</td> 248</tr> 249</tbody> 250</table> 251 252### map接口说明<a name="section1831091675716"></a> 253 254驱动进行内存映射操作所需要的接口列表。 255 256**表 5** map接口列表 257 258<a name="table1690431511432"></a> 259<table><thead align="left"><tr id="row189041315194317"><th class="cellrowborder" valign="top" width="54.67999999999999%" id="mcps1.2.3.1.1"><p id="p34281633124413"><a name="p34281633124413"></a><a name="p34281633124413"></a>接口名</p> 260</th> 261<th class="cellrowborder" valign="top" width="45.32%" id="mcps1.2.3.1.2"><p id="p4428133174412"><a name="p4428133174412"></a><a name="p4428133174412"></a>描述</p> 262</th> 263</tr> 264</thead> 265<tbody><tr id="row9904121594312"><td class="cellrowborder" valign="top" width="54.67999999999999%" headers="mcps1.2.3.1.1 "><p id="p1090471594316"><a name="p1090471594316"></a><a name="p1090471594316"></a>int32_t tee_map_secure(paddr_t paddr, uint64_t size, uintptr_t *vaddr, cache_mode_type cache_mode);</p> 266</td> 267<td class="cellrowborder" valign="top" width="45.32%" headers="mcps1.2.3.1.2 "><p id="p583mcpsimp"><a name="p583mcpsimp"></a><a name="p583mcpsimp"></a>给驱动访问者映射一段安全属性的物理内存。</p> 268</td> 269</tr> 270<tr id="row190417158431"><td class="cellrowborder" valign="top" width="54.67999999999999%" headers="mcps1.2.3.1.1 "><p id="p4904715174317"><a name="p4904715174317"></a><a name="p4904715174317"></a>int32_t tee_map_nonsecure(paddr_t paddr, uint64_t size, uintptr_t *vaddr, cache_mode_type cache_mode);</p> 271</td> 272<td class="cellrowborder" valign="top" width="45.32%" headers="mcps1.2.3.1.2 "><p id="p10904115204310"><a name="p10904115204310"></a><a name="p10904115204310"></a>给驱动访问者映射一段非安全属性的物理内存,其中映射属性是只读不能写。</p> 273</td> 274</tr> 275</tbody> 276</table> 277 278### IO操作接口说明<a name="section6512133012574"></a> 279 280驱动进行IO操作所需要的接口列表。 281 282**表 6** IO操作接口列表 283 284<a name="table6311346194315"></a> 285<table><thead align="left"><tr id="row831212462439"><th class="cellrowborder" valign="top" width="54.730000000000004%" id="mcps1.2.3.1.1"><p id="p7945143412442"><a name="p7945143412442"></a><a name="p7945143412442"></a>接口名</p> 286</th> 287<th class="cellrowborder" valign="top" width="45.269999999999996%" id="mcps1.2.3.1.2"><p id="p7945183494416"><a name="p7945183494416"></a><a name="p7945183494416"></a>描述</p> 288</th> 289</tr> 290</thead> 291<tbody><tr id="row143121846164318"><td class="cellrowborder" valign="top" width="54.730000000000004%" headers="mcps1.2.3.1.1 "><p id="p133121246194317"><a name="p133121246194317"></a><a name="p133121246194317"></a>void *ioremap(uintptr_t phys_addr, unsigned long size, int32_t prot);</p> 292</td> 293<td class="cellrowborder" valign="top" width="45.269999999999996%" headers="mcps1.2.3.1.2 "><p id="p133126466437"><a name="p133126466437"></a><a name="p133126466437"></a>将IO地址映射至虚拟地址。</p> 294</td> 295</tr> 296<tr id="row1431214468430"><td class="cellrowborder" valign="top" width="54.730000000000004%" headers="mcps1.2.3.1.1 "><p id="p103122046114317"><a name="p103122046114317"></a><a name="p103122046114317"></a>int32_t iounmap(uintptr_t pddr, void *addr);</p> 297</td> 298<td class="cellrowborder" valign="top" width="45.269999999999996%" headers="mcps1.2.3.1.2 "><p id="p4312194674313"><a name="p4312194674313"></a><a name="p4312194674313"></a>解除物理地址映射。</p> 299</td> 300</tr> 301<tr id="row1131211467433"><td class="cellrowborder" valign="top" width="54.730000000000004%" headers="mcps1.2.3.1.1 "><p id="p63121446154315"><a name="p63121446154315"></a><a name="p63121446154315"></a>void read_from_io (void *to, const volatile void *from, unsigned long count);</p> 302</td> 303<td class="cellrowborder" valign="top" width="45.269999999999996%" headers="mcps1.2.3.1.2 "><p id="p16312174619438"><a name="p16312174619438"></a><a name="p16312174619438"></a>将IO输入的值读取至驱动指定的地址,读取长度由count指定。</p> 304</td> 305</tr> 306<tr id="row1331219468434"><td class="cellrowborder" valign="top" width="54.730000000000004%" headers="mcps1.2.3.1.1 "><p id="p8312104614437"><a name="p8312104614437"></a><a name="p8312104614437"></a>void write_to_io(volatile void *to, const void *from, unsigned long count);</p> 307</td> 308<td class="cellrowborder" valign="top" width="45.269999999999996%" headers="mcps1.2.3.1.2 "><p id="p193mcpsimp"><a name="p193mcpsimp"></a><a name="p193mcpsimp"></a>将驱动指定地址的值输出至IO,读取长度由count指定。</p> 309</td> 310</tr> 311</tbody> 312</table> 313 314### 内存拷贝接口说明<a name="section75381736318"></a> 315 316驱动进行内存拷贝操作所需要的接口列表。 317 318**表 7** 内存拷贝接口列表 319 320<a name="table7469133214314"></a> 321<table><thead align="left"><tr id="row24693321135"><th class="cellrowborder" valign="top" width="55.35%" id="mcps1.2.3.1.1"><p id="p109015511039"><a name="p109015511039"></a><a name="p109015511039"></a>接口名</p> 322</th> 323<th class="cellrowborder" valign="top" width="44.65%" id="mcps1.2.3.1.2"><p id="p2090117510315"><a name="p2090117510315"></a><a name="p2090117510315"></a>描述</p> 324</th> 325</tr> 326</thead> 327<tbody><tr id="row15469133212312"><td class="cellrowborder" valign="top" width="55.35%" headers="mcps1.2.3.1.1 "><p id="p04692032734"><a name="p04692032734"></a><a name="p04692032734"></a>int32_t copy_from_client(uint64_t src, uint32_t src_size, uintptr_t dst, uint32_t dst_size);</p> 328</td> 329<td class="cellrowborder" valign="top" width="44.65%" headers="mcps1.2.3.1.2 "><p id="p184693323311"><a name="p184693323311"></a><a name="p184693323311"></a>将驱动内存拷入client端。</p> 330</td> 331</tr> 332<tr id="row246915325319"><td class="cellrowborder" valign="top" width="55.35%" headers="mcps1.2.3.1.1 "><p id="p94881980512"><a name="p94881980512"></a><a name="p94881980512"></a>int32_t copy_to_client(uintptr_t src, uint32_t src_size, uint64_t dst, uint32_t dst_size);</p> 333</td> 334<td class="cellrowborder" valign="top" width="44.65%" headers="mcps1.2.3.1.2 "><p id="p647018327314"><a name="p647018327314"></a><a name="p647018327314"></a>将client端数据拷出至驱动。</p> 335</td> 336</tr> 337</tbody> 338</table> 339 340### 共享内存接口说明<a name="section5891654459"></a> 341 342驱动进行共享内存操作所需要的接口列表。 343 344**表 8** 共享内存接口列表 345 346<a name="table186909151063"></a> 347<table><thead align="left"><tr id="row369016151263"><th class="cellrowborder" valign="top" width="55.620000000000005%" id="mcps1.2.3.1.1"><p id="p1033416207618"><a name="p1033416207618"></a><a name="p1033416207618"></a>接口名</p> 348</th> 349<th class="cellrowborder" valign="top" width="44.379999999999995%" id="mcps1.2.3.1.2"><p id="p19334172010619"><a name="p19334172010619"></a><a name="p19334172010619"></a>描述</p> 350</th> 351</tr> 352</thead> 353<tbody><tr id="row1069019153610"><td class="cellrowborder" valign="top" width="55.620000000000005%" headers="mcps1.2.3.1.1 "><p id="p176901815266"><a name="p176901815266"></a><a name="p176901815266"></a>void *tee_alloc_sharemem_aux(const struct tee_uuid *uuid, uint32_t size);</p> 354</td> 355<td class="cellrowborder" valign="top" width="44.379999999999995%" headers="mcps1.2.3.1.2 "><p id="p11690101520612"><a name="p11690101520612"></a><a name="p11690101520612"></a>申请进程间通信共享内存。</p> 356</td> 357</tr> 358<tr id="row19690615967"><td class="cellrowborder" valign="top" width="55.620000000000005%" headers="mcps1.2.3.1.1 "><p id="p166901915464"><a name="p166901915464"></a><a name="p166901915464"></a>uint32_t tee_free_sharemem(void *addr, uint32_t size);</p> 359</td> 360<td class="cellrowborder" valign="top" width="44.379999999999995%" headers="mcps1.2.3.1.2 "><p id="p186901215366"><a name="p186901215366"></a><a name="p186901215366"></a>释放进程间通信共享内存。</p> 361</td> 362</tr> 363</tbody> 364</table> 365 366## 开发示例<a name="section198361520981"></a> 367### 编译文件配置 368- 进入base/tee/tee_os_framework/目录 369- 首先在drivers/目录新建一个目录,例如demo_driver 370- 在demo_driver目录新建src目录用于存放源代码文件,新建Makefile编译文件 371 372Makefile示例如下 373 374``` 375DRIVER := demo_driver.elf 376 377include $(BUILD_CONFIG)/var.mk 378 379demo_driver_c_files += $(wildcard src/*.c) 380 381#include 382inc-flags += -I./src 383 384# Libraries 385 386SVC_PARTITIAL_LINK = y 387include $(BUILD_SERVICE)/svc-common.mk 388``` 389 390- 修改build/mk/common/operation/project.mk,增加drivers += demo_driver 391- 修改build/mk/pack/plat_config.mk, 增加以下内容 392 393``` 394ifeq ($(CONFIG_ARCH_AARCH64),y) 395product_apps += $(OUTPUTDIR)/aarch64/drivers/demo_driver.elf 396check-a64-syms-y += $(OUTPUTDIR)/aarch64/drivers/demo_driver.elf 397else 398product_apps += $(OUTPUTDIR)/arm/drivers/demo_driver.elf 399check-syms-y += $(OUTPUTDIR)/arm/drivers/demo_driver.elf 400endif 401``` 402 403### 驱动开发示例<a name="section198361520981"></a> 404 405驱动框架注册实例如下: 406 407``` 408#define TEST_NUM_INIT_VAL 0x11 409#define TEST_NUM_ADD_TAG 0x10 410static int32_t g_test_num = TEST_NUM_INIT_VAL; 411 412/* 驱动初始化函数 */ 413int32_t init_test(void) 414{ 415 if (g_test_num != TEST_NUM_INIT_VAL) { 416 tloge("driver init test failed, g_test_num:0x%x not equal 0x%x\n", g_test_num, TEST_NUM_INIT_VAL); 417 return -1; 418 } 419 420 g_test_num += TEST_NUM_ADD_TAG; 421 tloge("driver init test end\n"); 422 return 0; 423} 424 425/* buffer校验的相关逻辑 */ 426static int32_t buf_check(uint32_t *buf, uint32_t size, uint32_t args) 427{ 428 if (buf == NULL) { 429 tloge("buf is invalid, check failed\n"); 430 return -1; 431 } 432 433 uint32_t i; 434 for (i = 0; i < size; i++) { 435 if (buf[i] != args) { 436 tloge("buf[%u]=%u which not equal %u\n", i, buf[i], args); 437 return -1; 438 } 439 } 440 441 return 0; 442} 443 444/* 驱动具体业务处理逻辑函数 */ 445static int64_t args_test(struct drv_data *drv, unsigned long args, uint32_t args_len) 446{ 447 /* cmd处理函数在使用参数之前需要判断参数合法性 */ 448 if (args_len != sizeof(uint32_t) || args == 0) { 449 tloge("invalid args args_len:%u\n", args_len); 450 return -1; 451 } 452 453 uint32_t *input_args = (uint32_t *)(uintptr_t)args; 454 455 tloge("driver args test begin: drv.fd=%d args=0x%x g_test_num:0x%x\n", drv->fd, *input_args, g_test_num); 456 int64_t ret = buf_check(drv->private_data, TOKEN_BUF_SIZE, *input_args); 457 if (ret != 0) 458 tloge("args test FAIL\n"); 459 else 460 tloge("args test SUCC\n"); 461 462 return ret; 463} 464 465/* 驱动命令分发函数,根据不同cmdid调用不同函数逻辑 */ 466int64_t ioctl_test(struct drv_data *drv, uint32_t cmd, unsigned long args, uint32_t args_len) 467{ 468 if (drv == NULL) { /* drv可以在调用业务逻辑之前判断,args和args_len需要根据具体cmdid逻辑去判断 */ 469 tloge("ioctl invalid drv\n"); 470 return -1; 471 } 472 473 int64_t ret = -1; 474 475 switch (cmd) { 476 case ARGS_TEST_ID: 477 ret = args_test(drv, args, args_len); 478 break; 479 default: 480 tloge("cmd:0x%x not support\n", cmd); 481 } 482 483 return ret; 484} 485 486/* buffer 初始化 */ 487static uint32_t *buf_init(uint32_t args) 488{ 489 uint32_t *buf = (uint32_t *)malloc(TOKEN_BUF_SIZE * sizeof(uint32_t)); 490 if (buf == NULL) { 491 tloge("alloc buf failed\n"); 492 return NULL; 493 } 494 495 int32_t i; 496 for (i = 0; i < TOKEN_BUF_SIZE; i++) 497 buf[i] = args; 498 499 return buf; 500} 501 502/* 驱动被访问时初始化函数 */ 503int64_t open_test(struct drv_data *drv, unsigned long args, uint32_t args_len) 504{ 505 if (drv == NULL) { 506 tloge("open invalid drv\n"); 507 return -1; 508 } 509 510 if (args_len < sizeof(uint32_t) || args == 0) { 511 tloge("open invalid drv\n"); 512 return -1; 513 } 514 515 uint32_t *input = (uint32_t *)args; 516 if (*input == UINT32_MAX) { 517 tloge("open test input args is UINT32_MAX, just retrun -1\n"); 518 return -1; 519 } 520 521 uint32_t *buf = buf_init(*input); 522 if (buf == NULL) 523 return -1; 524 525 /* 将buf赋值给fd结构的private_data,后续都可以通过此fd获取到buf内容 */ 526 drv->private_data = buf; 527 tloge("driver open test begin: fd=%d args=0x%x g_test_num:0x%x\n", drv->fd, *input, g_test_num); 528 529 return 0; 530} 531 532/* 驱动业务逻辑访问结束后的资源清理操作 */ 533int64_t close_test(struct drv_data *drv) 534{ 535 if (drv == NULL) { 536 tloge("close invalid drv\n"); 537 return -1; 538 } 539 540 tloge("driver close test begin: fd:%d g_test_num:0x%x\n", drv->fd, g_test_num); 541 /* close流程需要释放fd对应的所有资源 */ 542 if (drv->private_data != NULL) { 543 tloge("free private data in close\n"); 544 free(drv->private_data); 545 } 546 547 return 0; 548} 549 550/* 在系统休眠时由驱动框架自行调用 */ 551int32_t suspend_test(void) 552{ 553 tloge("suspend test begin\n"); 554 return 0; 555} 556 557/* 在系统唤醒时有驱动框架自行调用 */ 558int32_t resume_test(void) 559{ 560 tloge("resume test begin\n"); 561 return 0; 562} 563 564/* 在系统s4休眠时被调用的函数 */ 565int32_t suspend_s4_test(void) 566{ 567 tloge("suspend_s4 test begin\n"); 568 return 0; 569} 570 571/* 在系统s4唤醒时被调用的函数 */ 572int32_t resume_s4_test(void) 573{ 574 tloge("resume_s4 test begin\n"); 575 return 0; 576} 577 578/* 驱动框架注册 */ 579tee_driver_declare(drv_test_module, init_test, open_test, ioctl_test, close_test, \ 580 suspend_test, resume_test, suspend_s4_test, resume_s4_test); 581``` 582 583### 驱动访问者开发示例<a name="section198361520981"></a> 584``` 585 586#include <securec.h> 587#include <stdlib.h> 588#include <string.h> 589#include <tee_drv_client.h> 590#include <tee_ext_api.h> 591#include <tee_log.h> 592#include <test_drv_cmdid.h> 593#include <mem_ops.h> 594 595 596#define DRV_UUID1 \ 597 { \ 598 0x11112222, 0x0000, 0x0000, \ 599 { \ 600 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 \ 601 } \ 602 } 603 604#define BUFFER_SIZE 1024 605struct share_buffer_arg { 606 uint64_t addr; 607 uint32_t len; 608 uint32_t share_token; 609}; 610 611/* 访问驱动的各个流程,在TA的TA_InvokeCommandEntryPoint阶段被执行 */ 612static TEE_Result TeeTestDrive(uint32_t cmd) 613{ 614 int ret; 615 const char *drvName = "drv_test_module"; 616 uint32_t args = (uint32_t)(&drvName); 617 const char drvcallerInput[] = "the param is drvcaller_input"; 618 char drvOutput[] = "DRVMEM_OUTPUT"; 619 620 uint32_t drvcallerInputLen = (uint32_t)strlen(drvcallerInput) + 1; 621 uint32_t drvOutputLen = (uint32_t)strlen(drvOutput) + 1; 622 TEE_UUID uuid = DRV_UUID1; 623 624 /* 调用驱动的open函数,返回与该驱动对应的唯一标记fd信息 */ 625 int64_t fd = tee_drv_open(drvName, &args, sizeof(args)); 626 if (fd <= 0) { 627 tloge("open %s for get fd failed\n", drvName); 628 return TEE_ERROR_GENERIC; 629 } 630 631 char *tempBuffer = tee_alloc_sharemem_aux(&uuid, BUFFER_SIZE); 632 if (tempBuffer == NULL) { 633 tloge("alloc share mem failed\n"); 634 return TEE_ERROR_GENERIC; 635 } 636 (void)memset_s(tempBuffer, BUFFER_SIZE, 0x0, BUFFER_SIZE); 637 ret = strcpy_s(tempBuffer, drvcallerInputLen, drvcallerInput); 638 if (ret != 0) { 639 tloge("strcpy_s failed,ret = 0x%x\n", ret); 640 return TEE_ERROR_GENERIC; 641 } 642 643 struct share_buffer_arg inputArg = { 0 }; 644#ifndef __aarch64__ 645 inputArg.addr = (uint64_t)(uint32_t)tempBuffer; 646#else 647 inputArg.addr = (uint64_t)tempBuffer; 648#endif 649 650 inputArg.len = BUFFER_SIZE; 651 652 tlogi("%s drv test ioctl begin args:0x%x fd:%d\n", drvName, inputArg, (int32_t)fd); 653 654 /* 访问fd对应的驱动模块,执行命令ID号为cmd_id对应的业务逻辑 */ 655 ret = (int)tee_drv_ioctl(fd, cmd, (const void *)(&inputArg), sizeof(inputArg)); 656 if (ret != 0) { 657 tloge("%s drv test ioctl failed, fd:%d \n", drvName, (int32_t)fd); 658 } 659 if (cmd == DRVTEST_COMMAND_COPYTOCLIENT) { 660 if (strncmp(drvOutput, (char *)tempBuffer, drvOutputLen) != 0) { 661 tloge("%s drv copy_to_client test failed, fd:%d, heap_buffer is:%s \n", drvName, (int32_t)fd, tempBuffer); 662 free_sharemem(tempBuffer, BUFFER_SIZE); 663 return TEE_ERROR_GENERIC; 664 } 665 } 666 667 /* 关闭fd对应驱动信息 */ 668 ret |= (int)tee_drv_close(fd); 669 if (ret != 0) { 670 tloge("drv test fail!\n"); 671 } 672 673 if (free_sharemem(tempBuffer, BUFFER_SIZE) != 0) { 674 tloge("free sharemem failed\n"); 675 ret = -1; 676 } 677 return (TEE_Result)ret; 678} 679 680/* TA实例的构造函数,每个TA实例的生命周期中只被调用一次 */ 681TEE_Result TA_CreateEntryPoint(void) 682{ 683 tlogi("---- TA_CreateEntryPoint ----------- \n"); 684 685 return TEE_SUCCESS; 686} 687 688/* 在CA请求创建一个与TA的会话时,TEE系统会调用此函数 */ 689TEE_Result TA_OpenSessionEntryPoint(uint32_t parmType, TEE_Param params[4], void **sessionContext) 690{ 691 (void)parmType; 692 (void)sessionContext; 693 tlogi("---- TA_OpenSessionEntryPoint -------- \n"); 694 if (params[0].value.b == 0xFFFFFFFE) 695 return TEE_ERROR_GENERIC; 696 else 697 return TEE_SUCCESS; 698} 699 700/* 在CA发送指令给TA时,需要指定之前创建成功的会话,TEE系统收到请求后会调用此函数 */ 701TEE_Result TA_InvokeCommandEntryPoint(void *sessionContext, uint32_t cmd, uint32_t parmType, TEE_Param params[4]) 702{ 703 TEE_Result ret = TEE_SUCCESS; 704 (void)sessionContext; 705 (void)parmType; 706 (void)params; 707 tlogi("---- TA invoke command ----------- command id: %u\n", cmd); 708 709 switch (cmd) { 710 case DRVTEST_COMMAND_DRVVIRTTOPHYS: 711 case DRVTEST_COMMAND_COPYFROMCLIENT: 712 case DRVTEST_COMMAND_COPYTOCLIENT: 713 ret = TeeTestDrive(cmd); 714 if (ret != TEE_SUCCESS) 715 tloge("invoke command for driver test failed! cmdId: %u, ret: 0x%x\n", cmd, ret); 716 break; 717 default: 718 tloge("not support this invoke command! cmdId: %u\n", cmd); 719 ret = TEE_ERROR_GENERIC; 720 break; 721 } 722 723 return ret; 724} 725 726/* 在CA发起关闭与TA的会话连接时,TEE系统会调用此函数 */ 727void TA_CloseSessionEntryPoint(void *sessionContext) 728{ 729 (void)sessionContext; 730 tlogi("---- TA_CloseSessionEntryPoint ----- \n"); 731} 732 733/* TA实例的析构函数,TEE系统在销毁TA实例时调用此函数 */ 734void TA_DestroyEntryPoint(void) 735{ 736 tlogi("---- TA_DestroyEntryPoint ---- \n"); 737} 738``` 739 740## 标准C库支持<a name="section14109139161012"></a> 741 742支持绝大多数的libc接口。支持大多数的POSIX接口,具体支持情况请看附件。标准文档请参照如下网址: 743 744POSIX:[https://mirror.math.princeton.edu/pub/oldlinux/download/c953.pdf](https://mirror.math.princeton.edu/pub/oldlinux/download/c953.pdf) 745 746目前使用的openharmony的musl-1.2.5/libc库。 747 748**表 9** 标准C支持列表 749 750<a name="table7336617112614"></a> 751<table><thead align="left"><tr id="row1633681714266"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p1653154512717"><a name="p1653154512717"></a><a name="p1653154512717"></a>模块</p> 752</th> 753<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p1253114512274"><a name="p1253114512274"></a><a name="p1253114512274"></a>函数接口名</p> 754</th> 755<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p75311145202718"><a name="p75311145202718"></a><a name="p75311145202718"></a>说明</p> 756</th> 757</tr> 758</thead> 759<tbody><tr id="row6340121710262"><td class="cellrowborder" rowspan="6" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p18534845102711"><a name="p18534845102711"></a><a name="p18534845102711"></a>malloc</p> 760</td> 761<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p553444592710"><a name="p553444592710"></a><a name="p553444592710"></a>aligned_alloc</p> 762</td> 763<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 764</tr> 765<tr id="row10341181782614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p753424552719"><a name="p753424552719"></a><a name="p753424552719"></a>calloc</p> 766</td> 767<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 768</tr> 769<tr id="row534110172268"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1853444542719"><a name="p1853444542719"></a><a name="p1853444542719"></a>malloc</p> 770</td> 771<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 772</tr> 773<tr id="row203411176269"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1553474572712"><a name="p1553474572712"></a><a name="p1553474572712"></a>realloc</p> 774</td> 775<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 776</tr> 777<tr id="row5341131742616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p10534184519273"><a name="p10534184519273"></a><a name="p10534184519273"></a>free</p> 778</td> 779<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 780</tr> 781<tr id="row18341101714263"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p12534184522712"><a name="p12534184522712"></a><a name="p12534184522712"></a>posix_memalign</p> 782</td> 783<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 784</tr> 785<tr id="row18341121732619"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p125341945182720"><a name="p125341945182720"></a><a name="p125341945182720"></a>mman</p> 786</td> 787<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p7534184532717"><a name="p7534184532717"></a><a name="p7534184532717"></a>mmap</p> 788</td> 789<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 790</tr> 791<tr id="row534131772614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p12534184513273"><a name="p12534184513273"></a><a name="p12534184513273"></a>munmap</p> 792</td> 793<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 794</tr> 795<tr id="row434101742618"><td class="cellrowborder" rowspan="3" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p253419457279"><a name="p253419457279"></a><a name="p253419457279"></a>time</p> 796</td> 797<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p16534124510274"><a name="p16534124510274"></a><a name="p16534124510274"></a>gettimeofday</p> 798</td> 799<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 800</tr> 801<tr id="row53411917172619"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p11534124522712"><a name="p11534124522712"></a><a name="p11534124522712"></a>strftime</p> 802</td> 803<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 804</tr> 805<tr id="row5341101712617"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p19535845152713"><a name="p19535845152713"></a><a name="p19535845152713"></a>time</p> 806</td> 807<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 808</tr> 809<tr id="row1334131792612"><td class="cellrowborder" rowspan="6" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p105357458277"><a name="p105357458277"></a><a name="p105357458277"></a>stdio</p> 810</td> 811<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p75354454278"><a name="p75354454278"></a><a name="p75354454278"></a>printf</p> 812</td> 813<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p4535134517270"><a name="p4535134517270"></a><a name="p4535134517270"></a>目前不支持文件系统,文件操作只支持标准输入输出。</p> 814</td> 815</tr> 816<tr id="row63421517192616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p2535154592716"><a name="p2535154592716"></a><a name="p2535154592716"></a>scanf</p> 817</td> 818<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 819</tr> 820<tr id="row83421817132613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p105351045132712"><a name="p105351045132712"></a><a name="p105351045132712"></a>snprintf</p> 821</td> 822<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 823</tr> 824<tr id="row434291782619"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p12535545132715"><a name="p12535545132715"></a><a name="p12535545132715"></a>sprintf</p> 825</td> 826<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 827</tr> 828<tr id="row19342517122616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p3535245132711"><a name="p3535245132711"></a><a name="p3535245132711"></a>vsnprintf</p> 829</td> 830<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 831</tr> 832<tr id="row1342161792613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p353518454270"><a name="p353518454270"></a><a name="p353518454270"></a>vsprintf</p> 833</td> 834<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 835</tr> 836<tr id="row734291715264"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p13535045172712"><a name="p13535045172712"></a><a name="p13535045172712"></a>errno</p> 837</td> 838<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p25351645132719"><a name="p25351645132719"></a><a name="p25351645132719"></a>errno</p> 839</td> 840<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 841</tr> 842<tr id="row11342181711269"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p11535164515276"><a name="p11535164515276"></a><a name="p11535164515276"></a>strerror</p> 843</td> 844<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 845</tr> 846<tr id="row5342151710264"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p10535945152714"><a name="p10535945152714"></a><a name="p10535945152714"></a>exit</p> 847</td> 848<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p8535124519274"><a name="p8535124519274"></a><a name="p8535124519274"></a>abort</p> 849</td> 850<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 851</tr> 852<tr id="row11342117182611"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p85358458277"><a name="p85358458277"></a><a name="p85358458277"></a>unistd</p> 853</td> 854<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1753517452273"><a name="p1753517452273"></a><a name="p1753517452273"></a>getpid</p> 855</td> 856<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 857</tr> 858<tr id="row1034281772615"><td class="cellrowborder" rowspan="4" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1553514592714"><a name="p1553514592714"></a><a name="p1553514592714"></a>locale</p> 859</td> 860<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p753574512278"><a name="p753574512278"></a><a name="p753574512278"></a>setlocale</p> 861</td> 862<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 863</tr> 864<tr id="row334220171263"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p115353451276"><a name="p115353451276"></a><a name="p115353451276"></a>strcoll</p> 865</td> 866<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 867</tr> 868<tr id="row13343151762618"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p95351145142716"><a name="p95351145142716"></a><a name="p95351145142716"></a>strxfrm</p> 869</td> 870<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 871</tr> 872<tr id="row173433172262"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p0535104512273"><a name="p0535104512273"></a><a name="p0535104512273"></a>strtod</p> 873</td> 874<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 875</tr> 876<tr id="row2343131732614"><td class="cellrowborder" rowspan="3" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p95351945132716"><a name="p95351945132716"></a><a name="p95351945132716"></a>multibyte</p> 877</td> 878<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p25351345122715"><a name="p25351345122715"></a><a name="p25351345122715"></a>mbrtowc</p> 879</td> 880<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 881</tr> 882<tr id="row1234321772614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p185354453273"><a name="p185354453273"></a><a name="p185354453273"></a>wcrtomb</p> 883</td> 884<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 885</tr> 886<tr id="row7343151762613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p115361445112716"><a name="p115361445112716"></a><a name="p115361445112716"></a>wctob</p> 887</td> 888<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 889</tr> 890<tr id="row1034351714262"><td class="cellrowborder" rowspan="4" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p135361645112710"><a name="p135361645112710"></a><a name="p135361645112710"></a>prng</p> 891</td> 892<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p19536134517272"><a name="p19536134517272"></a><a name="p19536134517272"></a>srandom</p> 893</td> 894<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 895</tr> 896<tr id="row73431717102610"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17536134518272"><a name="p17536134518272"></a><a name="p17536134518272"></a>initstate</p> 897</td> 898<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 899</tr> 900<tr id="row17343181742615"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p2536144515271"><a name="p2536144515271"></a><a name="p2536144515271"></a>setstate</p> 901</td> 902<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 903</tr> 904<tr id="row16343121711263"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p185362459278"><a name="p185362459278"></a><a name="p185362459278"></a>random</p> 905</td> 906<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 907</tr> 908<tr id="row63431217102612"><td class="cellrowborder" rowspan="17" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1153618451278"><a name="p1153618451278"></a><a name="p1153618451278"></a>string</p> 909</td> 910<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1553620456277"><a name="p1553620456277"></a><a name="p1553620456277"></a>memchr</p> 911</td> 912<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 913</tr> 914<tr id="row93431217112613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p14536154510275"><a name="p14536154510275"></a><a name="p14536154510275"></a>memcmp</p> 915</td> 916<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 917</tr> 918<tr id="row17344417112619"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p153684515275"><a name="p153684515275"></a><a name="p153684515275"></a>memcpy</p> 919</td> 920<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 921</tr> 922<tr id="row1934421712265"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1653694592712"><a name="p1653694592712"></a><a name="p1653694592712"></a>memmove</p> 923</td> 924<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 925</tr> 926<tr id="row934411712267"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p2536114510274"><a name="p2536114510274"></a><a name="p2536114510274"></a>memset</p> 927</td> 928<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 929</tr> 930<tr id="row163441117142619"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p105361345112715"><a name="p105361345112715"></a><a name="p105361345112715"></a>strchr</p> 931</td> 932<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 933</tr> 934<tr id="row1434451715262"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p175366451279"><a name="p175366451279"></a><a name="p175366451279"></a>strcmp</p> 935</td> 936<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 937</tr> 938<tr id="row534471762616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p353694514273"><a name="p353694514273"></a><a name="p353694514273"></a>strcpy</p> 939</td> 940<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 941</tr> 942<tr id="row334461752611"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1753694515274"><a name="p1753694515274"></a><a name="p1753694515274"></a>strlen</p> 943</td> 944<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 945</tr> 946<tr id="row834419172265"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p0536745102720"><a name="p0536745102720"></a><a name="p0536745102720"></a>strncmp</p> 947</td> 948<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 949</tr> 950<tr id="row1734415175268"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p55361345192717"><a name="p55361345192717"></a><a name="p55361345192717"></a>strncpy</p> 951</td> 952<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 953</tr> 954<tr id="row183445174264"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p115365457273"><a name="p115365457273"></a><a name="p115365457273"></a>strnlen</p> 955</td> 956<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 957</tr> 958<tr id="row1534401712611"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p19537245112712"><a name="p19537245112712"></a><a name="p19537245112712"></a>strrchr</p> 959</td> 960<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 961</tr> 962<tr id="row13451617142620"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p125371456272"><a name="p125371456272"></a><a name="p125371456272"></a>strstr</p> 963</td> 964<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 965</tr> 966<tr id="row15345181762614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p95371845142718"><a name="p95371845142718"></a><a name="p95371845142718"></a>wcschr</p> 967</td> 968<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 969</tr> 970<tr id="row10345151718267"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p0537124512279"><a name="p0537124512279"></a><a name="p0537124512279"></a>wcslen</p> 971</td> 972<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 973</tr> 974<tr id="row2345111710263"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p145371645142718"><a name="p145371645142718"></a><a name="p145371645142718"></a>wmemchr</p> 975</td> 976<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 977</tr> 978<tr id="row12345131715263"><td class="cellrowborder" rowspan="13" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p753714502717"><a name="p753714502717"></a><a name="p753714502717"></a>ctype</p> 979</td> 980<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p5537145142720"><a name="p5537145142720"></a><a name="p5537145142720"></a>isalpha</p> 981</td> 982<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 983</tr> 984<tr id="row1434581792614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p0537184511274"><a name="p0537184511274"></a><a name="p0537184511274"></a>isascii</p> 985</td> 986<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 987</tr> 988<tr id="row5345417182620"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p8537114513278"><a name="p8537114513278"></a><a name="p8537114513278"></a>isdigit</p> 989</td> 990<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 991</tr> 992<tr id="row8345117122618"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p8537204582712"><a name="p8537204582712"></a><a name="p8537204582712"></a>islower</p> 993</td> 994<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 995</tr> 996<tr id="row034551782617"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p253716455273"><a name="p253716455273"></a><a name="p253716455273"></a>isprint</p> 997</td> 998<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 999</tr> 1000<tr id="row4345101713267"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1053713455279"><a name="p1053713455279"></a><a name="p1053713455279"></a>isspace</p> 1001</td> 1002<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1003</tr> 1004<tr id="row16345201752616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p853764562716"><a name="p853764562716"></a><a name="p853764562716"></a>iswctype</p> 1005</td> 1006<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1007</tr> 1008<tr id="row33455179264"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p18537114522715"><a name="p18537114522715"></a><a name="p18537114522715"></a>iswdigit</p> 1009</td> 1010<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1011</tr> 1012<tr id="row83461317192614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p16537154512710"><a name="p16537154512710"></a><a name="p16537154512710"></a>iswlower</p> 1013</td> 1014<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1015</tr> 1016<tr id="row93461117152620"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p353713458276"><a name="p353713458276"></a><a name="p353713458276"></a>iswspace</p> 1017</td> 1018<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1019</tr> 1020<tr id="row19346161711268"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p75371145202717"><a name="p75371145202717"></a><a name="p75371145202717"></a>iswupper</p> 1021</td> 1022<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1023</tr> 1024<tr id="row123461517162613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p3537245152710"><a name="p3537245152710"></a><a name="p3537245152710"></a>towupper</p> 1025</td> 1026<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1027</tr> 1028<tr id="row1734671714268"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p175381245172715"><a name="p175381245172715"></a><a name="p175381245172715"></a>towlower</p> 1029</td> 1030<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1031</tr> 1032<tr id="row6346117112615"><td class="cellrowborder" rowspan="16" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p2538174512714"><a name="p2538174512714"></a><a name="p2538174512714"></a>math</p> 1033</td> 1034<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p19538184572712"><a name="p19538184572712"></a><a name="p19538184572712"></a>atan</p> 1035</td> 1036<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 1037</tr> 1038<tr id="row8346131782613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p15381945172717"><a name="p15381945172717"></a><a name="p15381945172717"></a>ceil</p> 1039</td> 1040<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1041</tr> 1042<tr id="row734617176261"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p953844582716"><a name="p953844582716"></a><a name="p953844582716"></a>ceilf</p> 1043</td> 1044<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1045</tr> 1046<tr id="row134610174264"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p053824511271"><a name="p053824511271"></a><a name="p053824511271"></a>copysignl</p> 1047</td> 1048<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1049</tr> 1050<tr id="row13346917152610"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p13538104522717"><a name="p13538104522717"></a><a name="p13538104522717"></a>exp</p> 1051</td> 1052<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1053</tr> 1054<tr id="row334661712269"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p5538154512710"><a name="p5538154512710"></a><a name="p5538154512710"></a>fabs</p> 1055</td> 1056<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1057</tr> 1058<tr id="row2347181722616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p2538184522716"><a name="p2538184522716"></a><a name="p2538184522716"></a>floor</p> 1059</td> 1060<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1061</tr> 1062<tr id="row123471517122616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1453874562717"><a name="p1453874562717"></a><a name="p1453874562717"></a>frexp</p> 1063</td> 1064<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1065</tr> 1066<tr id="row153471917112616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p14538134512271"><a name="p14538134512271"></a><a name="p14538134512271"></a>frexpl</p> 1067</td> 1068<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1069</tr> 1070<tr id="row234771717261"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p10538245102714"><a name="p10538245102714"></a><a name="p10538245102714"></a>log</p> 1071</td> 1072<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1073</tr> 1074<tr id="row1334711179265"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p185381245142719"><a name="p185381245142719"></a><a name="p185381245142719"></a>log2</p> 1075</td> 1076<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1077</tr> 1078<tr id="row103471317132612"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p20538144512275"><a name="p20538144512275"></a><a name="p20538144512275"></a>pow</p> 1079</td> 1080<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1081</tr> 1082<tr id="row133472178262"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p35389459277"><a name="p35389459277"></a><a name="p35389459277"></a>roundf</p> 1083</td> 1084<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1085</tr> 1086<tr id="row234731713261"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p4538154522715"><a name="p4538154522715"></a><a name="p4538154522715"></a>scalbn</p> 1087</td> 1088<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1089</tr> 1090<tr id="row1347917182619"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p85381845192718"><a name="p85381845192718"></a><a name="p85381845192718"></a>scalbnl</p> 1091</td> 1092<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1093</tr> 1094<tr id="row1134717178267"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p11538845102718"><a name="p11538845102718"></a><a name="p11538845102718"></a>sqrt</p> 1095</td> 1096<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1097</tr> 1098<tr id="row13348101715261"><td class="cellrowborder" rowspan="14" align="left" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p195391445102713"><a name="p195391445102713"></a><a name="p195391445102713"></a>stdlib</p> 1099</td> 1100<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1153954552713"><a name="p1153954552713"></a><a name="p1153954552713"></a>abs</p> 1101</td> 1102<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td> 1103</tr> 1104<tr id="row4348101732615"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1853910450272"><a name="p1853910450272"></a><a name="p1853910450272"></a>atof</p> 1105</td> 1106<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1107</tr> 1108<tr id="row12348111782617"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p12539124562717"><a name="p12539124562717"></a><a name="p12539124562717"></a>atoi</p> 1109</td> 1110<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1111</tr> 1112<tr id="row123482178261"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p95391945102713"><a name="p95391945102713"></a><a name="p95391945102713"></a>atol</p> 1113</td> 1114<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1115</tr> 1116<tr id="row163481117142610"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p35391745172718"><a name="p35391745172718"></a><a name="p35391745172718"></a>atoll</p> 1117</td> 1118<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1119</tr> 1120<tr id="row6348217132613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p4539164511276"><a name="p4539164511276"></a><a name="p4539164511276"></a>bsearch</p> 1121</td> 1122<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1123</tr> 1124<tr id="row12348191714269"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p195391245102717"><a name="p195391245102717"></a><a name="p195391245102717"></a>div</p> 1125</td> 1126<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1127</tr> 1128<tr id="row1634810170260"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p10539124513274"><a name="p10539124513274"></a><a name="p10539124513274"></a>ecvt</p> 1129</td> 1130<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1131</tr> 1132<tr id="row103481517182617"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p75392457277"><a name="p75392457277"></a><a name="p75392457277"></a>imaxabs</p> 1133</td> 1134<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1135</tr> 1136<tr id="row1834817175260"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p854014552719"><a name="p854014552719"></a><a name="p854014552719"></a>llabs</p> 1137</td> 1138<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1139</tr> 1140<tr id="row1349121792612"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1154054562718"><a name="p1154054562718"></a><a name="p1154054562718"></a>qsort</p> 1141</td> 1142<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1143</tr> 1144<tr id="row15349117192614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p14540645172719"><a name="p14540645172719"></a><a name="p14540645172719"></a>strtoul</p> 1145</td> 1146<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1147</tr> 1148<tr id="row134910176267"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p135401445172712"><a name="p135401445172712"></a><a name="p135401445172712"></a>strtol</p> 1149</td> 1150<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1151</tr> 1152<tr id="row183494173268"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p3540114519272"><a name="p3540114519272"></a><a name="p3540114519272"></a>wcstod</p> 1153</td> 1154<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td> 1155</tr> 1156</tbody> 1157</table> 1158 1159> **注意:** 1160>1. 不支持文件系统、控制台。 1161>2. 不支持fstat,fsync,writev接口。 1162 1163## 安全函数库<a name="section127921457151719"></a> 1164 1165### 概述<a name="section5848918131818"></a> 1166 1167危险函数依赖于程序员对参数进行检查或保证空间能足够容纳所产生的结果,函数本身不对这些情况进行判断,即使有问题也不会给出错误的指示。C11标准中对于过时的不安全的危险函数定义了对应的安全函数(\_s版本的函数),相比危险函数,安全函数对照C11标准进行了相应的安全增强,会对入参以及不同的错误情况进行判断,降低操作不当所引入的安全风险。下表列举了危险函数以及对应的安全函数,TA代码中涉及到相关危险函数的必须使用安全函数。 1168 1169**表 10** 危险函数以及对应的安全函数 1170 1171<a name="table18216829674"></a> 1172<table><thead align="left"><tr id="row1221612296715"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p1280043317715"><a name="p1280043317715"></a><a name="p1280043317715"></a>危险函数</p> 1173</th> 1174<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p880019332710"><a name="p880019332710"></a><a name="p880019332710"></a>安全函数</p> 1175</th> 1176</tr> 1177</thead> 1178<tbody><tr id="row122166291776"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p198006331074"><a name="p198006331074"></a><a name="p198006331074"></a>memcpy</p> 1179</td> 1180<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p16800533473"><a name="p16800533473"></a><a name="p16800533473"></a>memcpy_s</p> 1181</td> 1182</tr> 1183<tr id="row421610291977"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p080012331073"><a name="p080012331073"></a><a name="p080012331073"></a>memmove</p> 1184</td> 1185<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1680013331779"><a name="p1680013331779"></a><a name="p1680013331779"></a>memmove_s</p> 1186</td> 1187</tr> 1188<tr id="row152161229975"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1480013336712"><a name="p1480013336712"></a><a name="p1480013336712"></a>memset</p> 1189</td> 1190<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p4800103314713"><a name="p4800103314713"></a><a name="p4800103314713"></a>memset_s</p> 1191</td> 1192</tr> 1193<tr id="row02163297719"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1580017338710"><a name="p1580017338710"></a><a name="p1580017338710"></a>strcpy</p> 1194</td> 1195<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p20800233575"><a name="p20800233575"></a><a name="p20800233575"></a>strcpy_s</p> 1196</td> 1197</tr> 1198<tr id="row132161629777"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p680016331977"><a name="p680016331977"></a><a name="p680016331977"></a>strncpy</p> 1199</td> 1200<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1880013335719"><a name="p1880013335719"></a><a name="p1880013335719"></a>strncpy_s</p> 1201</td> 1202</tr> 1203<tr id="row1821642918715"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p180010331175"><a name="p180010331175"></a><a name="p180010331175"></a>strcat</p> 1204</td> 1205<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p158003331671"><a name="p158003331671"></a><a name="p158003331671"></a>strcat_s</p> 1206</td> 1207</tr> 1208<tr id="row72167299712"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p780014331373"><a name="p780014331373"></a><a name="p780014331373"></a>strncat</p> 1209</td> 1210<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p188017331171"><a name="p188017331171"></a><a name="p188017331171"></a>strncat_s</p> 1211</td> 1212</tr> 1213<tr id="row17217202917714"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p780113331478"><a name="p780113331478"></a><a name="p780113331478"></a>strtok</p> 1214</td> 1215<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p128013333711"><a name="p128013333711"></a><a name="p128013333711"></a>strtok_s</p> 1216</td> 1217</tr> 1218<tr id="row1021717291676"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p980111331072"><a name="p980111331072"></a><a name="p980111331072"></a>snprintf</p> 1219</td> 1220<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p98011331277"><a name="p98011331277"></a><a name="p98011331277"></a>snprintf_s</p> 1221</td> 1222</tr> 1223<tr id="row92174291974"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p380114333720"><a name="p380114333720"></a><a name="p380114333720"></a>vsnprintf</p> 1224</td> 1225<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p20801183316710"><a name="p20801183316710"></a><a name="p20801183316710"></a>vsnprintf_s</p> 1226</td> 1227</tr> 1228</tbody> 1229</table> 1230 1231详细描述请参考头文件<securec.h\>。 1232 1233安全函数包含部分如下特性: 1234 1235- 强化边界检查:在接口参数中增加一个buffer长度的参数,在长度参数正确情况下不会出现溢出。 1236- 保证结果字符串以’\\0’结尾,避免访问buffer边界之外的信息。 1237- 发现缓冲区溢出发生,将目的缓冲区的首字节置零。 1238- 增加错误返回值,便于程序员快速进行错误定位。 1239- 增强入参检查。 1240- 增加入参的内存重叠检查(memcpy\_sp宏中对于常量拷贝不进行内存重叠检查)。 1241- 定义SECUREC\_STRING\_MAX\_LEN和SECUREC\_MEM\_MAX\_LEN宏,可以通过其限定字符串和内存操作时的最大长度。 1242- 定义SECUREC\_ERROR\_INVALID\_PARAMTER、SECUREC\_ERROR\_INVALID\_RANGE和SECUREC\_ERROR\_BUFFER\_OVERLAP宏,其会在参数出错时进行统一处理,用户可自定义发生错误时的函数处理行为。 1243 1244### 内存复制<a name="section1620304312183"></a> 1245 1246memcpy\_s: 1247 1248``` 1249errno_t memcpy_s(void* dest, size_t destMax, const void* src, size_t count); 1250``` 1251 1252复制源缓冲区的数据到目的缓冲区。 1253 1254> **注意:** 1255>- 与系统函数相比:1)多了一个参数:目的缓冲区总大小; 2)系统函数返回值为指针,安全函数返回值为整型。 1256>- 调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。 1257>- 某些出错情况下,会对目的缓冲区清0,具体参考如上**表1**。 1258>- 进行字符串拷贝时,不会自动在末尾添加结束符。(对字符串操作,建议使用字符串操作函数) 1259 1260- 示例 1261 1262<figure> 1263 1264``` 1265 #include "securec.h" 1266 #include <string.h> 1267 1268 #define BUFFER_SIZE 11 1269 1270 int main() 1271 { 1272 char str1[BUFFER_SIZE] = "0123456789"; 1273 char str2[BUFFER_SIZE] = {0x00}; 1274 errno_t rc = EOK; 1275 1276 rc = memcpy_s(str2, BUFFER_SIZE, str1, BUFFER_SIZE - 1); 1277 printf("rc = %d, %s\n", rc, str2); 1278 1279 /* count is bigger than destMax, return ERANGE_AND_RESET and dest is reset. */ 1280 rc = memcpy_s(str2, BUFFER_SIZE, str1, BUFFER_SIZE + 1); 1281 printf("rc = %d, %s\n", rc, str2); 1282 1283 /* initialize */ 1284 rc = memcpy_s(str2, BUFFER_SIZE, str1, BUFFER_SIZE - 1); 1285 printf("rc = %d, %s\n", rc, str2); 1286 1287 /* overlap, return EOVERLAP_AND_RESET and dest is reset. */ 1288 rc = memcpy_s(str2, BUFFER_SIZE, str2 + 2, BUFFER_SIZE - 1); 1289 printf("rc = %d, %s\n", rc, str2); 1290 1291 return 0; 1292 } 1293运行结果: 1294rc = 0, 0123456789 1295rc = 162 1296rc = 0, 0123456789 1297rc = 182 1298``` 1299 1300</figure> 1301 1302memmove\_s: 1303 1304``` 1305errno_t memmove_s(void* dest,size_t destMax, const void* src, size_t count); 1306``` 1307 1308移动源缓冲区的数据到目的缓冲区 1309 1310> **注意:** 1311>- 与系统函数相比: 1312> - 多了一个参数:目的缓冲区总大小; 1313> - 系统函数返回值为指针,安全函数返回值为整型。 1314>- 调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。 1315>- 某些出错情况下,会对目的缓冲区清0,具体参考如上**表2**。 1316 1317- 示例 1318 1319<figure> 1320 1321``` 1322 #include "securec.h" 1323 #include <string.h> 1324 1325 #define BUFFER_SIZE 11 1326 1327 int main() 1328 { 1329 char str[BUFFER_SIZE] = "0123456789"; 1330 errno_t rc = EOK; 1331 1332 printf("Before: %s\n", str); 1333 1334 /* Move six bytes from the start of the string 1335 * to a new position shifted by one byte. To protect against 1336 * buffer overrun, the secure version of memmove requires the 1337 * the length of the destination string to be specified. 1338 */ 1339 1340 rc = memmove_s(str, BUFFER_SIZE, str + 1, 6); 1341 printf("After: rc = %d, %s\n", rc, str); 1342 1343 /* count is bigger than destMax, return ERANGE_AND_RESET and dest is reset. */ 1344 rc = memmove_s(str, BUFFER_SIZE, str + 1, BUFFER_SIZE + 100); 1345 printf("Later: rc = %d, %s\n", rc, str); 1346 1347 return 0; 1348 } 1349运行结果: 1350Before: 0123456789 1351After: rc = 0, 123456789 1352Later: rc = 162 1353``` 1354 1355</figure> 1356 1357### 内存初始化<a name="section9113185921817"></a> 1358 1359memset\_s: 1360 1361``` 1362errno_t memset_s(void* dest, size_t destMax, int c, size_t count); 1363``` 1364 1365复制源缓冲区的数据到目的缓冲区 1366 1367> **注意:** 1368>- 与系统函数相比:1)多了一个参数:目的缓冲区总大小; 2)系统函数返回值为指针,安全函数返回值为整型。 1369>- 调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。 1370 1371- 示例 1372 1373<figure> 1374 1375``` 1376 #include "securec.h" 1377 #include <string.h> 1378 1379 #define BUFFER_SIZE 40 1380 1381 int main() 1382 { 1383 char buffer[BUFFER_SIZE] = "This is a test of the memset function"; 1384 errno_t rc = EOK; 1385 1386 printf( "Before: %s\n", buffer ); 1387 1388 rc = memset_s(buffer, BUFFER_SIZE, '*', 20 ); 1389 printf( "After: rc = %d, %s\n", rc, buffer ); 1390 1391 /* count is bigger than destMax, return ERANGE_AND_RESET and destMax size is set. */ 1392 rc = memset_s(buffer, BUFFER_SIZE, '*', BUFFER_SIZE + 1 ); 1393 printf( "Later: rc = %d, %s\n", rc, buffer ); 1394 1395 return 0; 1396 } 1397 1398 运行结果: 1399 Before: This is a test of the memset function 1400 After: rc = 0, ********************e memset function 1401 Later: rc = 162, **************************************** 1402``` 1403 1404</figure> 1405 1406### 字符串复制<a name="section320518115198"></a> 1407 1408strcpy\_s: 1409 1410``` 1411errno_t strcpy_s(char* strDest, size_t destMax, const char* strSrc); 1412``` 1413 1414复制源字符串到目的缓冲区 1415 1416> **注意:** 1417>- 与系统函数相比:1)、多了一个参数:目的缓冲区总大小; 2)、系统函数返回值为指针,安全函数返回值为整型。 1418>- 调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。 1419>- 某些出错情况下,会对目的缓冲区首字符置0,具体参考如上**表1**。 1420>源字符串必须含有结束符。 1421 1422- 示例 1423 1424<figure> 1425 1426``` 1427 #include "securec.h" 1428 #include <stdio.h> 1429 1430 #define SMALL_BUF_SIZE 10 1431 #define BIG_BUF_SIZE 100 1432 1433 int main() 1434 { 1435 char str1[BIG_BUF_SIZE] = {0x00}; 1436 char str2[SMALL_BUF_SIZE] = {0x00}; 1437 char *str3 = str1 + 4; 1438 errno_t rc = EOK; 1439 1440 rc = strcpy_s(str1, BIG_BUF_SIZE, "Security Design Department"); 1441 printf("rc = %d, %s\n", rc, str1); 1442 1443 /* strSrc length + 1 is bigger than destMax, return ERANGE_AND_RESET and strDest is reset. */ 1444 rc = strcpy_s(str2, SMALL_BUF_SIZE, "Security Design"); 1445 printf("rc = %d, %s\n", rc, str2); 1446 1447 memset_s(str1, BIG_BUF_SIZE, 0x41, BIG_BUF_SIZE); 1448 /* overlap, return EOVERLAP_AND_RESET and strDest is reset. */ 1449 rc = strcpy_s(str1, BIG_BUF_SIZE, str3); 1450 printf("rc = %d, %s\n", rc, str1); 1451 1452 return 0; 1453 } 1454 1455运行结果: 1456rc = 0, Security Design Department 1457rc = 162, 1458rc = 182, 1459``` 1460 1461</figure> 1462 1463strncpy\_s: 1464 1465``` 1466errno_t strncpy_s(char* strDest, size_t destMax, const char* strSrc, size_t count); 1467``` 1468 1469复制指定长度的源字符串到目的缓冲区。 1470 1471> **注意:** 1472>- 与系统函数相比:1)多了一个参数:目的缓冲区总大小; 2)系统函数返回值为指针,安全函数返回值为整型。 1473>- 调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。 1474>- 某些出错情况下,会对目的缓冲区首字符置0,具体参考如上**表2**。 1475>- 源字符串必须含有结束符。 1476>- 调用该函数时建议传入的参数destMax 大于 count以保证有截断功能。 1477>- 安全函数strncpy\_s执行完后保证strDest有’\\0’结尾,而危险函数strncpy不保证。 1478>- 当 count 大于 strlen\(strSrc\) 时, strncpy函数会复制完字符串后在strDest中填充count-strlen\(strSrc\)个’\\0’字符,而strncpy\_s函数不做填充。 1479 1480- 示例 1481 1482<figure> 1483 1484``` 1485 #define SMALL_BUF_SIZE 10 1486 #define BIG_BUF_SIZE 100 1487 1488 int main() 1489 { 1490 char str1[BIG_BUF_SIZE] = {0x00}; 1491 char str2[BIG_BUF_SIZE] = "security design department"; 1492 char *str3 = str1 + 4; 1493 char str4[SMALL_BUF_SIZE] = {0x00}; 1494 errno_t rc = EOK; 1495 1496 rc = strncpy_s(str1, BIG_BUF_SIZE, str2, 15); 1497 printf("rc = %d, %s\n", rc, str1); 1498 1499 /* count is bigger than destMax, return ERANGE_AND_RESET and dest is reset. */ 1500 rc = strncpy_s(str4, SMALL_BUF_SIZE, "security Design Department", 15); 1501 printf("rc = %d, %s\n", rc, str4); 1502 1503 memset_s(str1, BIG_BUF_SIZE, 0x41, BIG_BUF_SIZE); 1504 /* overlap, return EOVERLAP_AND_RESET and dest is reset. */ 1505 rc = strncpy_s(str1, BIG_BUF_SIZE, str3, 15); 1506 printf("rc = %d, %s\n", rc, str1); 1507 1508 return 0; 1509 } 1510 1511运行结果: 1512rc = 0, security design 1513rc = 162, 1514rc = 182, 1515``` 1516 1517</figure> 1518 1519### 字符串连接<a name="section3307826101911"></a> 1520 1521strcat\_s: 1522 1523``` 1524errno_t strcat_s(char* strDest, size_t destMax, const char* strSrc); 1525``` 1526 1527将源字符串连接到目的字符串后面。 1528 1529> **注意:** 1530>- 与系统函数相比: 1531> - 多了一个参数:目的缓冲区总大小; 1532> - 系统函数返回值为指针,安全函数返回值为整型。 1533>- 调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。 1534>- 某些出错情况下,会对目的缓冲区的首字符置0,具体参考如上**表1**。 1535 1536- 示例 1537 1538<figure> 1539 1540``` 1541 #include "securec.h" 1542 #include <stdio.h> 1543 1544 #define BUFFER_SIZE 64 1545 1546 int main() 1547 { 1548 char str1[BUFFER_SIZE] = {’’}; 1549 char str2[BUFFER_SIZE] = {’b’}; 1550 errno_t rc = EOK; 1551 1552 rc = strcat_s(str1, 3, str2); 1553 printf("rc = %d, %s\n", rc, str1); 1554 1555 1556 /*strdest in destMax don’t have ‘\0’*/ 1557 memset_s(str1, BUFFER_SIZE,'a',4); 1558 memset_s(str2, BUFFER_SIZE,'b',4); 1559 rc = strcat_s(str1, 4, str2); 1560 printf("rc = %d, %s\n", rc, str1); 1561 1562 /*destmax isn’t enough for strSrc*/ 1563 memset_s(str1, BUFFER_SIZE,'a',4); 1564 memset_s(str2, BUFFER_SIZE,'b',4); 1565 rc = strcat_s(str1,8, str2); 1566 printf("rc = %d, %s\n", rc, str1); 1567 1568 /*dest , src overlap*/ 1569 rc = strncat_s(str2,8, str2+2,1); 1570 printf("rc = %d, %s\n", rc, str2); 1571 1572 return 0; 1573 } 1574 1575运行结果: 1576rc = 0, ab 1577rc = 150, 1578rc = 162, 1579rc = 182, 1580``` 1581 1582</figure> 1583 1584strncat\_s: 1585 1586``` 1587errno_t strncat_s(char* strDest, size_t destMax, const char* strSrc, size_t count); 1588``` 1589 1590将指定长度的源字符串连接到目的字符串后面。 1591 1592> **注意:** 1593>- 与系统函数相比: 1594> - 多了一个参数:目的缓冲区总大小; 1595> - 系统函数返回值为指针,安全函数返回值为整型。 1596>- 调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。 1597>- 某些出错情况下,会对目的缓冲区的首字符置0,具体参考如上**表2**。 1598 1599- 示例 1600 1601<figure> 1602 1603``` 1604 #include "securec.h" 1605 #include <stdio.h> 1606 1607 #define BUFFER_SIZE 64 1608 1609 int main() 1610 { 1611 char str1[BUFFER_SIZE] = {’’}; 1612 char str2[BUFFER_SIZE] = {’b’}; 1613 errno_t rc = EOK; 1614 1615 rc = strncat_s(str1, 3, str2, 1); 1616 printf("rc = %d, %s\n", rc , str1); 1617 1618 /*strdest in destMax don’t have ‘\0’*/ 1619 memset_s(str1, BUFFER_SIZE,’a’,4); 1620 memset_s(str2, BUFFER_SIZE,’b’,4); 1621 rc = strncat_s(str1, 4, str2, 2); 1622 printf("rc = %d, %s\n", rc , str1); 1623 1624 /*destmax isn’t enough for strSrc*/ 1625 memset_s(str1, BUFFER_SIZE,’a’,4); 1626 memset_s(str2, BUFFER_SIZE,’b’,4); 1627 rc = strncat_s(str1,8, str2,5); 1628 printf("rc = %d, %s\n", rc , str1); 1629 1630 /*dest , src overlap*/ 1631 rc = strncat_s(str2,8, str2+2,1); 1632 printf("rc = %d, %s\n", rc , str2); 1633 1634 return 0; 1635 } 1636 1637运行结果: 1638rc = 0, ab 1639rc = 150, 1640rc = 162, 1641rc = 182, 1642``` 1643 1644</figure> 1645 1646### 字符串分割<a name="section85731515152610"></a> 1647 1648strtok\_s: 1649 1650``` 1651errno_t strtok_s(char* strToken, const char* strDelimit, char** context); 1652``` 1653 1654将字符串按照指定的分隔符分割成子字符串。 1655 1656> **注意:** 1657>- 与系统函数相比:多了一个参数context:保存调用strtok\_s后的下个子字符串的首地址,当不再有子字符串时,context指向被分割字符串结尾。 1658>- 当在被分割字符串中没有找到分隔符时,如果被分割字符串长度大于0,会返回被分割字符串首地址,否则返回NULL。 1659>- 以逗号分隔符为例,顺序调用strtok\_s\(str,&p\), strtok\_s\(NULL,&p\), strtok\_s\(NULL,&p\)函数的返回值与不同分割字符串的关系如下: 1660 1661**表 11** 返回值与字符串关系 1662 1663<a name="table18556455195912"></a> 1664<table><tbody><tr id="row7556165595917"><td class="cellrowborder" rowspan="2" valign="top"><p id="p156641710803"><a name="p156641710803"></a><a name="p156641710803"></a><strong id="b86641109012"><a name="b86641109012"></a><a name="b86641109012"></a><span>被分割字符串</span></strong></p> 1665</td> 1666<td class="cellrowborder" colspan="3" valign="top"><p id="p1766414101808"><a name="p1766414101808"></a><a name="p1766414101808"></a><strong id="b1866414101608"><a name="b1866414101608"></a><a name="b1866414101608"></a><span>返回值</span></strong></p> 1667</td> 1668</tr> 1669<tr id="row155765565917"><td class="cellrowborder" valign="top"><p id="p146654101808"><a name="p146654101808"></a><a name="p146654101808"></a>strtok_s(str,&p)</p> 1670</td> 1671<td class="cellrowborder" valign="top"><p id="p15665610307"><a name="p15665610307"></a><a name="p15665610307"></a>strtok_s(NULL,&p)</p> 1672</td> 1673<td class="cellrowborder" valign="top"><p id="p17665111019017"><a name="p17665111019017"></a><a name="p17665111019017"></a>strtok_s(NULL,&p)</p> 1674</td> 1675</tr> 1676<tr id="row955745525914"><td class="cellrowborder" valign="top" width="25%"><p id="p19665171014011"><a name="p19665171014011"></a><a name="p19665171014011"></a>str = "aaa"</p> 1677</td> 1678<td class="cellrowborder" valign="top" width="25%"><p id="p46652010100"><a name="p46652010100"></a><a name="p46652010100"></a>"aaa"</p> 1679</td> 1680<td class="cellrowborder" valign="top" width="25%"><p id="p06652101907"><a name="p06652101907"></a><a name="p06652101907"></a>NULL</p> 1681</td> 1682<td class="cellrowborder" valign="top" width="25%"><p id="p466511105013"><a name="p466511105013"></a><a name="p466511105013"></a>_</p> 1683</td> 1684</tr> 1685<tr id="row75571655115910"><td class="cellrowborder" valign="top" width="25%"><p id="p1066512101208"><a name="p1066512101208"></a><a name="p1066512101208"></a><span>str =</span> <span>""</span></p> 1686</td> 1687<td class="cellrowborder" valign="top" width="25%"><p id="p4665181017014"><a name="p4665181017014"></a><a name="p4665181017014"></a><span>NULL</span></p> 1688</td> 1689<td class="cellrowborder" valign="top" width="25%"><p id="p166654101307"><a name="p166654101307"></a><a name="p166654101307"></a>_</p> 1690</td> 1691<td class="cellrowborder" valign="top" width="25%"><p id="p17665111018016"><a name="p17665111018016"></a><a name="p17665111018016"></a>_</p> 1692</td> 1693</tr> 1694<tr id="row4557145516596"><td class="cellrowborder" valign="top" width="25%"><p id="p176651510509"><a name="p176651510509"></a><a name="p176651510509"></a><span>str =</span> <span>","</span></p> 1695</td> 1696<td class="cellrowborder" valign="top" width="25%"><p id="p766510101102"><a name="p766510101102"></a><a name="p766510101102"></a><span>NULL</span></p> 1697</td> 1698<td class="cellrowborder" valign="top" width="25%"><p id="p0665610101"><a name="p0665610101"></a><a name="p0665610101"></a>_</p> 1699</td> 1700<td class="cellrowborder" valign="top" width="25%"><p id="p106657106015"><a name="p106657106015"></a><a name="p106657106015"></a>_</p> 1701</td> 1702</tr> 1703<tr id="row195571055105919"><td class="cellrowborder" valign="top" width="25%"><p id="p26651510407"><a name="p26651510407"></a><a name="p26651510407"></a><span>str =</span> <span>",,"</span></p> 1704</td> 1705<td class="cellrowborder" valign="top" width="25%"><p id="p9665510409"><a name="p9665510409"></a><a name="p9665510409"></a><span>NULL</span></p> 1706</td> 1707<td class="cellrowborder" valign="top" width="25%"><p id="p206657101204"><a name="p206657101204"></a><a name="p206657101204"></a>_</p> 1708</td> 1709<td class="cellrowborder" valign="top" width="25%"><p id="p066541016017"><a name="p066541016017"></a><a name="p066541016017"></a>_</p> 1710</td> 1711</tr> 1712<tr id="row6558115516595"><td class="cellrowborder" valign="top" width="25%"><p id="p1866520102008"><a name="p1866520102008"></a><a name="p1866520102008"></a><span>str =</span> <span>",aaa"</span></p> 1713</td> 1714<td class="cellrowborder" valign="top" width="25%"><p id="p96655102010"><a name="p96655102010"></a><a name="p96655102010"></a><span>"aaa"</span></p> 1715</td> 1716<td class="cellrowborder" valign="top" width="25%"><p id="p06651101902"><a name="p06651101902"></a><a name="p06651101902"></a><span>NULL</span></p> 1717</td> 1718<td class="cellrowborder" valign="top" width="25%"><p id="p18666121018017"><a name="p18666121018017"></a><a name="p18666121018017"></a>_</p> 1719</td> 1720</tr> 1721<tr id="row1955865511594"><td class="cellrowborder" valign="top" width="25%"><p id="p166671012013"><a name="p166671012013"></a><a name="p166671012013"></a><span>str =</span> <span>",,aaa"</span></p> 1722</td> 1723<td class="cellrowborder" valign="top" width="25%"><p id="p1666611018017"><a name="p1666611018017"></a><a name="p1666611018017"></a><span>"aaa"</span></p> 1724</td> 1725<td class="cellrowborder" valign="top" width="25%"><p id="p76665101802"><a name="p76665101802"></a><a name="p76665101802"></a><span>NULL</span></p> 1726</td> 1727<td class="cellrowborder" valign="top" width="25%"><p id="p106666102015"><a name="p106666102015"></a><a name="p106666102015"></a>_</p> 1728</td> 1729</tr> 1730<tr id="row1955805514595"><td class="cellrowborder" valign="top" width="25%"><p id="p466618103014"><a name="p466618103014"></a><a name="p466618103014"></a><span>str =</span> <span>"aaa,"</span></p> 1731</td> 1732<td class="cellrowborder" valign="top" width="25%"><p id="p566615101006"><a name="p566615101006"></a><a name="p566615101006"></a><span>"aaa"</span></p> 1733</td> 1734<td class="cellrowborder" valign="top" width="25%"><p id="p12666210206"><a name="p12666210206"></a><a name="p12666210206"></a><span>NULL</span></p> 1735</td> 1736<td class="cellrowborder" valign="top" width="25%"><p id="p1566617101809"><a name="p1566617101809"></a><a name="p1566617101809"></a>_</p> 1737</td> 1738</tr> 1739<tr id="row755810558594"><td class="cellrowborder" valign="top" width="25%"><p id="p146661510301"><a name="p146661510301"></a><a name="p146661510301"></a><span>str =</span> <span>"aaa,,"</span></p> 1740</td> 1741<td class="cellrowborder" valign="top" width="25%"><p id="p1566641012015"><a name="p1566641012015"></a><a name="p1566641012015"></a><span>"aaa"</span></p> 1742</td> 1743<td class="cellrowborder" valign="top" width="25%"><p id="p1966613107017"><a name="p1966613107017"></a><a name="p1966613107017"></a><span>NULL</span></p> 1744</td> 1745<td class="cellrowborder" valign="top" width="25%"><p id="p1166611108010"><a name="p1166611108010"></a><a name="p1166611108010"></a>_</p> 1746</td> 1747</tr> 1748<tr id="row155915515598"><td class="cellrowborder" valign="top" width="25%"><p id="p1666611101603"><a name="p1666611101603"></a><a name="p1666611101603"></a><span>str =</span> <span>"aaa,bbb"</span></p> 1749</td> 1750<td class="cellrowborder" valign="top" width="25%"><p id="p106663101504"><a name="p106663101504"></a><a name="p106663101504"></a><span>"aaa"</span></p> 1751</td> 1752<td class="cellrowborder" valign="top" width="25%"><p id="p13666610804"><a name="p13666610804"></a><a name="p13666610804"></a><span>"bbb"</span></p> 1753</td> 1754<td class="cellrowborder" valign="top" width="25%"><p id="p126663101003"><a name="p126663101003"></a><a name="p126663101003"></a><span>NULL</span></p> 1755</td> 1756</tr> 1757<tr id="row9559555135919"><td class="cellrowborder" valign="top" width="25%"><p id="p13666131015010"><a name="p13666131015010"></a><a name="p13666131015010"></a><span>str =</span> <span>"aaa,,bbb"</span></p> 1758</td> 1759<td class="cellrowborder" valign="top" width="25%"><p id="p176668102003"><a name="p176668102003"></a><a name="p176668102003"></a><span>"aaa"</span></p> 1760</td> 1761<td class="cellrowborder" valign="top" width="25%"><p id="p196661108012"><a name="p196661108012"></a><a name="p196661108012"></a><span>"bbb"</span></p> 1762</td> 1763<td class="cellrowborder" valign="top" width="25%"><p id="p1366601016011"><a name="p1366601016011"></a><a name="p1366601016011"></a><span>NULL</span></p> 1764</td> 1765</tr> 1766<tr id="row1455915555596"><td class="cellrowborder" valign="top" width="25%"><p id="p8667510002"><a name="p8667510002"></a><a name="p8667510002"></a><span>str =</span> <span>"aaa,bbb,"</span></p> 1767</td> 1768<td class="cellrowborder" valign="top" width="25%"><p id="p196672010506"><a name="p196672010506"></a><a name="p196672010506"></a><span>"aaa"</span></p> 1769</td> 1770<td class="cellrowborder" valign="top" width="25%"><p id="p6667201020015"><a name="p6667201020015"></a><a name="p6667201020015"></a><span>"bbb"</span></p> 1771</td> 1772<td class="cellrowborder" valign="top" width="25%"><p id="p13667161011011"><a name="p13667161011011"></a><a name="p13667161011011"></a><span>NULL</span></p> 1773</td> 1774</tr> 1775<tr id="row175591455145914"><td class="cellrowborder" valign="top" width="25%"><p id="p466713102019"><a name="p466713102019"></a><a name="p466713102019"></a><span>str =</span> <span>"aaa,bbb,,"</span></p> 1776</td> 1777<td class="cellrowborder" valign="top" width="25%"><p id="p1166751019014"><a name="p1166751019014"></a><a name="p1166751019014"></a><span>"aaa"</span></p> 1778</td> 1779<td class="cellrowborder" valign="top" width="25%"><p id="p9667010504"><a name="p9667010504"></a><a name="p9667010504"></a><span>"bbb"</span></p> 1780</td> 1781<td class="cellrowborder" valign="top" width="25%"><p id="p16667910402"><a name="p16667910402"></a><a name="p16667910402"></a><span>NULL</span></p> 1782</td> 1783</tr> 1784</tbody> 1785</table> 1786 1787- 示例 1788 1789<figure> 1790 1791``` 1792 #include "securec.h" 1793 #include <stdio.h> 1794 1795 int main() 1796 { 1797 char string1[64] = "A string\tof ,,tokens\nand some more tokens"; 1798 char string2[64] = "Another string\n\tparsed at the same time."; 1799 char seps[] = " ,\t\n"; 1800 char *token1 = NULL; 1801 char *token2 = NULL; 1802 char *next_token1 = NULL; 1803 char *next_token2= NULL; 1804 1805 printf( "Tokens:\n" ); 1806 1807 /* Establish string and get the first token: */ 1808 token1 = strtok_s(string1, seps, &next_token1); 1809 token2 = strtok_s(string2, seps, &next_token2); 1810 1811 /* While there are tokens in "string1" or "string2" */ 1812 while ((token1 != NULL) || (token2 != NULL)) 1813 { 1814 /* Get next token: */ 1815 if (token1 != NULL) 1816 { 1817 printf(" %s\n", token1); 1818 token1 = strtok_s(NULL, seps, &next_token1); 1819 } 1820 if (token2 != NULL) 1821 { 1822 printf(" %s\n", token2); 1823 token2 = strtok_s (NULL, seps, &next_token2); 1824 } 1825 } 1826 1827 return 0; 1828 } 1829 1830运行结果: 1831Tokens: 1832more 1833same 1834some 1835the 1836and 1837at 1838tokens 1839parsed 1840of 1841string 1842string 1843Another 1844time. 1845tokens 1846``` 1847 1848</figure> 1849 1850### 格式化输出<a name="section1696173315284"></a> 1851 1852snprintf\_s: 1853 1854``` 1855int snprintf_s(char* strDest, size_t destMax, size_t count, const char* format, ...); 1856``` 1857 1858将数据按照指定长度格式化输出到目的缓冲区。 1859 1860> **注意:** 1861>- 与系统函数相比: 1862> - 多了一个参数:目的缓冲区总大小; 1863> - count参数与系统函数的用法存在差异,参见参数表。 1864>- 调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。 1865>- 某些出错情况下,会对目的缓冲区首字符清0,具体参考如上**表1**。 1866>- 调用该函数时建议传入的参数destMax 大于 count以保证有截断功能。 1867>- 确保输入的源数据与目标缓冲区不存在重叠。 1868>- 输入源数据中若是字符串则必须含有结束符。 1869>输入源数据的类型、个数必须与格式化控制字符串(format)中的类型、个数保持一致。 1870 1871- 示例 1872 1873<figure> 1874 1875``` 1876 #include "securec.h" 1877 1878 void snprintf_sample() 1879 { 1880 char buffer[200]={0}; 1881 char *string = "computer"; 1882 wchar_t *wstring = L"Unicode"; 1883 1884 /* format strings. */ 1885 int iRet = snprintf_s( buffer, 200, 20, "%s,%ls", string, wstring); 1886 printf("iRet = %d, buffer = %s.\n", iRet, buffer); 1887 1888 /* test edge. */ 1889 printf("------------------\n"); 1890 iRet = snprintf_s( buffer, 3, 3, "%s", "123"); 1891 printf("iRet = %d, buffer = %s.\n", iRet, buffer); 1892 1893 /* test edge. */ 1894 printf("------------------\n"); 1895 iRet = snprintf_s( buffer, 3, 2, "%s", "123"); 1896 printf("iRet = %d, buffer = %s.\n", iRet, buffer); 1897 1898 1899 return; 1900 } 1901 1902 int main() 1903 { 1904 snprintf_sample (); 1905 return 0; 1906 } 1907 1908运行结果: 1909iRet = 16, buffer = computer,Unicode. 1910iRet = -1, buffer = . 1911 1912iRet = -1, buffer = 12. 1913``` 1914 1915</figure> 1916 1917vsnprintf\_s: 1918 1919``` 1920int vsnprintf_s(char* strDest, size_t destMax, size_t count, const char* format, va_list arglis); 1921``` 1922 1923将参数列表\(_va\_list_\)数据按照指定长度格式化输出到目的缓冲区。 1924 1925> **注意:** 1926>- 与系统函数相比: 1927> - 多了一个参数:目的缓冲区总大小; 1928> - count参数与系统函数的用法存在差异,参见参数表。 1929>- 调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。 1930>- 某些出错情况下,会对目的缓冲区首字符清0,具体参考如上表2。 1931>- 调用该函数时建议传入的参数destMax 大于 count以保证有截断功能。 1932>- 确保输入的源数据与目标缓冲区不存在重叠。 1933>- 输入源数据中若是字符串则必须含有结束符。 1934>- 输入源数据的类型、个数必须与格式化控制字符串(format)中的类型、个数保持一致。 1935 1936- 示例1 1937 1938<figure> 1939 1940``` 1941 #include "securec.h" 1942 1943 void FormatOutput(char* formatstring, ...) 1944 { 1945 va_list args; 1946 int nSize = 0; 1947 char buff[10]; 1948 memset_s(buff,sizeof(buff), 0, sizeof(buff)); 1949 va_start(args, formatstring); 1950 nSize = vsnprintf_s( buff, sizeof(buff), 8, formatstring, args); 1951 printf("nSize: %d, buff: %s\n", nSize, buff); 1952 } 1953 1954 int main() 1955 { 1956 FormatOutput("%s %s", "Hi", "there"); 1957 FormatOutput("%s %s", "Hi", "there!"); 1958 1959 return 0; 1960 } 1961 1962运行结果: 1963nSize: 8, buff: Hi there 1964nSize: -1, buff: Hi there 1965``` 1966 1967</figure> 1968 1969- 示例2 1970 1971<figure> 1972 1973``` 1974 void vsnprintf_base(char * format, ...) 1975 { 1976 va_list args; 1977 char buffer[100]; 1978 int iRet = -1; 1979 1980 va_start(args, format); 1981 iRet = vsnprintf_s(buffer, 100, 20, format, args); 1982 printf("iRet = %d, buffer = %s.\n", iRet, buffer); 1983 1984 return; 1985 } 1986 void vsnprintf_sample(void) 1987 { 1988 char *string = "computer"; 1989 wchar_t *wstring = L"Unicode"; 1990 1991 /* format strings. */ 1992 vsnprintf_base("%s,%ls", string, wstring); 1993 1994 /* test edge.*/ 1995 printf("------------------\n"); 1996 vsnprintf_base("%s", "12345678901234567890a"); 1997 1998 return; 1999 } 2000 2001 int main() 2002 { 2003 vsnprintf_sample(); 2004 return 0; 2005 } 2006 2007运行结果: 2008iRet = 16, buffer = computer,Unicode. 2009iRet = -1, buffer = 12345678901234567890. 2010``` 2011 2012</figure> 2013 2014