HarmonyOS Next开发学习手册——C/C++标准库机制

概述

HarmonyOS NDK提供业界标准库 libc标准库 、 C++标准库,本文用于介绍C/C++标准库在HarmonyOS中的机制,开发者了解这些机制有助于在NDK开发过程中避免相关问题。

1. C++兼容性

在HarmonyOS系统中,系统库与应用Native库都在使用C++标准库(参考 libc++版本),系统库依赖的C++标准库随镜像版本升级,而应用Native库依赖的C++标准库随编译使用的SDK版本升级,两部分依赖的C++基础库会跨多个大版本,产生ABI兼容性问题。为了解决此问题,HarmonyOS上把两部分依赖的C++标准库进行了区分。

  • 系统库:使用libc++.so, 随系统镜像发布。
  • 应用Native库:使用libc++_shared.so,随应用发布。

两个库使用的C++命名空间不一样,libc++.so使用__h作为C++符号的命名空间,libc++_shared.so使用__n1作为C++符号的命名空间。

注意:系统和应用使用的C++标准库不能进行混用,Native API接口当前只能是C接口,可以通过这个接口隔离两边的C++运行环境。因此在使用共享库HAR包构建应用时,如果HAR包含的libc++_shared.so不同于应用使用的libc++_shared.so版本,那么只有其中一个版本会安装到应用里,可能会导致不兼容问题,可以使用相同的SDK版本更新HAR包解决此问题。

已知C++兼容性问题:应用启动或者dlopen时hilog报错symbol not found, s=__emutls_get_address,原因是API9及之前版本SDK中的libc++_shared.so无此符号,而API11之后版本SDK的libc++_shared.so是有此符号的。解决此问题需要更新应用或者共享库HAR包的SDK版本。

2. musl libc动态链接器

动态库加载命名空间隔离

动态库加载命名空间(namespace,下面统称为ns)是动态链接器设计的一个概念(区别于C++语言中的命名空间),其设计的主要目的是为了在进程中做native库资源访问的管控,以达到安全隔离的目的。例如系统native库允许加载系统目录(/system/lib64;/vendor/lib64等)下的native库,但是普通应用native库仅允许加载普通应用native库和ndk库,而不允许直接加载系统native库。

动态链接器无论是在加载编译依赖(DT_NEEDED)中指定的共享库,还是调用dlopen加载指定的共享库,都需要关联到具体的ns。

HarmonyOS中动态库加载namespace配置的情况

  • default ns:动态链接器启动时默认创建的ns,它可以搜索/system/lib{abi};/vendor/lib{abi}等系统目录路径下的so。

  • ndk ns:动态链接器启动时默认创建的ns,它可以搜索/system/lib{abi}/ndk目录下的so,主要是暴露了NDK接口的so。

  • app ns: 应用启动时创建的ns,它的搜索路径一般是应用的安装路径(可能为沙箱路径),即可加载应用的so。

当前这一套命名空间机制主要限制了应用native库和系统native库之间的调用,如图所示,具体规则为

  1. default ns和ndk ns可以互相访问全部so,不能访问app ns的so。
  2. app ns能访问ndk ns的全部so,不能访问default ns的so。

rpath机制

rpath(run-time path)是在运行时指定共享库搜索路径的机制。该机制允许在可执行文件或共享库中嵌入一个用于在运行时指定库的搜索路径的信息。

由于上文介绍的命名空间隔离机制,应用仅允许加载对应安装目录拼接native库路径下(例如arm64平台上为libs/arm64)的应用native库,当应用程序涉及加载较多的native库,期望创建多个native库加载路径方便管理,但是会导致无法加载新创建目录下的native库,这种情况可以通过rpath机制编译时指定搜索路径。

例如,应用安装目录lib/arm64下的libhello.so依赖新创建路径lib/arm64/module下的libworld.so,那么在应用的CMakeList.txt里设置上rpath编译选项后编译,使用readelf查看libhello.so的rpath配置如图所示,$ORIGIN为libhello.so所在路径,运行时即可正常加载module目录下的libworld.so。

SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
SET(CMAKE_INSTALL_RPATH "\${ORIGIN}/module")

支持dlclose

支持使用dlclose真实卸载动态库的能力。

支持symbol-version机制

symbol-version是libc在动态链接-符号重定位阶段的符号检索机制,支持不同版本的符号重定位,也可以帮助解决重复符号的问题。可参考 LD Version Scripts (GNU Gnulib)

网络接口select支持fd fortify检测

宏定义FD_SET/FD_CLR新增fd有效值检查,当传入的fd不在区间[0, 1024)中会触发abort crash。

宏定义FD_ISSET新增fd有效值检查,当传入的fd不在区间[0, 1024)中会返回false。

全球化支持

自API12起,newlocale及setlocale接口支持将locale设置C、C.UTF-8、en_US、en_US.UTF-8、zh_CN及zh_CN.UTF-8。新增在zh_CN及zh_CN.UTF-8的locale设置下对strtod_l、wcstod_l和localeconv的支持。注意strtod_l及wcstod_l不支持对十六进制及十六进制小数的转换。

fdsan功能

fdsan功能可以帮助检测文件的重复关闭和关闭后使用问题。

fdsan使用指南

1. 功能介绍

fdsan针对的操作对象是文件描述符,主要用于检测不同使用者对相同文件描述符的错误操作,包括多次关闭(double-close)和关闭后使用(use-after-close)。这些文件描述符可以是操作系统中的文件、目录、网络套接字和其他I/O设备等,在程序中,打开文件或套接字会生成一个文件描述符,如果此文件描述符在使用后出现反复关闭、或者关闭后使用等场景,就会造成内存泄露、文件句柄泄露等安全隐患问题。该类问题非常隐蔽,且难以排查,为了更好地检测此类问题,因此引入了此种针对文件描述符错误操作的检测工具fdsan。

2. 实现原理

设计思路:当打开已有文件或创建一个新文件的时候,在得到返回fd后,设置一个关联的tag,来标记fd的属主信息;关闭文件前,检测fd关联的tag,判断是否符合预期(属主信息一致),符合就继续走正常文件关闭流程;如果不符合就是检测到异常,根据设置,调用对应的异常处理。

tag由两部分组成,最高位的8-bit构成type,后面的56-bit构成value。

type,标识fd通过何种封装形式进行管理,例如 FDSAN_OWNER_TYPE_FILE就表示fd通过普通文件进行管理,type类型在 fdsan_owner_type进行定义。

value,则用于标识实际的owner tag。

tag构成图示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值