第 5 章 补充主题
5.1. 编译器和开发工具中的兼容性破坏更改
非常量 PTHREAD_STACK_MIN
、MINSIGSTKSZ
和 SIGSTKSZ
宏
为了更好地支持需要一个用于可扩展向量寄存器的变量堆栈大小、PTHREAD_STACK_MIN
、MINSIGSTKSZ
和 SIGSTKSZ
宏的常量值已变为一个非常量值,如 sysconf
调用。
您不再以将 PTHREAD_STACK_MIN
、MINSIGSTKSZ
和 SIGSTKSZ
宏视为像常量值的方式使用它们。PTHREAD_STACK_MIN
、MINSIGSTKSZ
和 SIGSTKSZ
宏返回的值现在是长数据类型,并可能在与无符号值(如 size_t
)进行比较时产生编译器警告。
库合并到 libc.so.6
有了这个更新,以下库已合并到 libc
库中,以提供更顺畅的原位升级体验,支持进程在任何时候安全使用线程,并简化内部实现:
-
libpthread
-
libdl
-
libutil
-
libanl
另外,libresolv
库的一部分已移到 libc 中,以支持将名称切换服务(NSS)文件和域名系统(DNS)插件直接移到 libc
库中。NSS 文件和 DNS 插件现在直接构建到 libc
库中,并可在升级期间使用或跨 chroot
或容器边界使用。它们在 chroot
或容器边界的使用,支持从这些源安全地查询身份管理(IdM)数据。
zdump
工具的新位置
/usr/bin/zdump
是 zdump
工具的新位置。
弃用 sys_siglist
、_sys_siglist
和 sys_sigabbrev
符号
sys_siglist
、_sys_siglist
和 sys_sigabbrev
符号仅被导出为兼容性符号,以支持旧的二进制文件。所有程序都应该使用 strsignal
符号。
使用 sys_siglist
、_sys_siglist
和 sys_sigabbrev
符号会产生问题,如复制重新定位和对阵列访问没有显式绑定检查的容易出错的应用程序二进制接口(ABI)。
这个更改可能会影响从源构建某些软件包。要修复问题,请重写程序以使用 strsignal
符号。例如:
#include <signal.h> #include <stdio.h> static const char *strsig (int sig) { return sys_siglist[sig]; } int main (int argc, char *argv[]) { printf ("%s\n", strsig (SIGINT)); return 0; }
应该调整为:
#include <signal.h> #include <stdio.h> #include <string.h> static const char *strsig (int sig) { return strsignal(sig); } int main (int argc, char *argv[]) { printf ("%s\n", strsig (SIGINT)); return 0; }
或者,使用 glibc-2.32
GNU 扩展 sigabbrev_np
或 sigdescr_np
:
#define _GNU_SOURCE #include <signal.h> #include <stdio.h> #include <string.h> static const char *strsig (int sig) { const char *r = sigdescr_np (sig); return r == NULL ? "Unknown signal" : r; } int main (int argc, char *argv[]) { printf ("%s\n", strsig (SIGINT)); printf ("%s\n", strsig (-1)); return 0; }
这两个扩展都是 async-signal-safe 和 multithread-safe。
弃用 sys_errlist
、_sys_errlist
、sys_nerr
和 _sys_nerr
符号
sys_errlist
、_sys_errlist
、sys_nerr
和 _sys_nerr
符号仅被导出兼容性符号,以支持旧的二进制文件。所有程序都应该使用 strerror
或 strerror_r
符号。
使用 sys_errlist
、_sys_errlist
、sys_nerr
和 _sys_nerr
符号会导致问题,如复制重新定位和对阵列访问没有显式绑定检查的易出问题的 ABI。
这个更改可能会影响从源构建某些软件包。要解决这个问题,请使用 strerror
或 strerror_r
符号重写程序。例如:
#include <stdio.h> #include <errno.h> static const char *strerr (int err) { if (err < 0 || err > sys_nerr) return "Unknown"; return sys_errlist[err]; } int main (int argc, char *argv[]) { printf ("%s\n", strerr (-1)); printf ("%s\n", strerr (EINVAL)); return 0; }
应该调整为:
#include <stdio.h> #include <errno.h> static const char *strerr (int err) { return strerror (err); } int main (int argc, char *argv[]) { printf ("%s\n", strerr (-1)); printf ("%s\n", strerr (EINVAL)); return 0; }
或者,使用 glibc-2.32
GNU 扩展 strerrorname_np
或 strerrordesc_np
:
#define _GNU_SOURCE #include <stdio.h> #include <errno.h> #include <string.h> static const char *strerr (int err) { const char *r = strerrordesc_np (err); return r == NULL ? "Unknown error" : r; } int main (int argc, char *argv[]) { printf ("%s\n", strerr (-1)); printf ("%s\n", strerr (EINVAL)); return 0; }
这两个扩展都是 async-signal-safe 和 multithread-safe。
用户空间内存分配器, malloc
, 更改
mallwatch
和 tr_break
符号现已弃用,不再在 mtrace
函数中使用。您可以使用 GDB 中 mtrace
函数中的条件断点来实现类似的功能。
__morecore
和 __after_morecore_hook
malloc
hook 和默认实现 __default_morecore
已从 API 中删除。现有应用程序将继续链接到这些符号,但接口不再对 malloc
产生任何影响。
现在,默认在 C 主库中禁用了 malloc
中的调试功能,如 MALLOC_CHECK_
环境变量(或 glibc.malloc.check
可调整变量)、mtrace
() 和 mcheck ()
。要使用这些功能,请预先加载新的 libc_malloc_debug.so
调试 DSO。
弃用的函数 malloc_get_state
和 malloc_set_state
已从核心 C 库移到 libc_malloc_debug.so
库。仍使用这些函数的传统应用程序现在必需使用 LD_PRELOAD
环境变量在其环境中预先加载 libc_malloc_debug.so
库。
弃用的内存分配 hook __malloc_hook
、__realloc_hook
、__memalign_hook
和 __free_hook
现在已从 API 中删除。存在兼容性符号来支持旧程序,但新应用程序可以不再链接到这些符号。这些 hook 不再对 glibc
功能有任何影响。调试 DSO libc_malloc_debug.so
的malloc
目前支持 hook,并可预先加载以恢复旧程序的功能。但是,这是一个过渡措施,可能会在以后的 GNU C 库发行版本中删除。您可以通过编写和预先加载您自己的 malloc
组成库来从这些 hook 中移植出去。
lazy 绑定失败终止了进程
如果在 dlopen
函数期间发生了 lazy 绑定失败,则在 ELF 构造器执行过程中,进程现在被终止。在以前的版本中,动态加载程序从 dlopen
返回 NULL
,并显示 dlerror
消息中捕获的 lazy 绑定错误。通常,这是不安全的,因为无法在任意函数调用中重置堆栈。
弃用 stime
功能
stime
函数不再对新链接的二进制文件可用,其声明已从 <time.h>
中删除。对于设置系统时间的程序,使用 clock_settime
函数。
popen
和 system
函数不再运行 fork
处理程序
虽然可能违反 POSIX ,但 pthread_atfork
文档中关于 atfork
处理程序的 POSIX 原理是在多线程进程中的 fork 调用后处理不一致的排它锁锁状态。在 popen
和 system
函数中,无法直接访问用户定义的排它锁。
C++ 标准库中已弃用的功能
-
如果使用小于字符串的当前容量的参数调用,
std::string::reserve (n)
将不再减少字符串的容量。可以通过调用不带参数的reserve()
来减少字符串的容量,但该形式已弃用。应该改为使用等同的shrink_to_fit ()
。 -
非标准
std::__is_nullptr_t
类型特征已弃用。应该改为使用标准的std::is_null_pointer
特征。