第 5 章 补充主题

5.1. 编译器和开发工具中的兼容性破坏更改

非常量 PTHREAD_STACK_MINMINSIGSTKSZSIGSTKSZ

为了更好地支持需要可扩展向量寄存器的变量堆栈大小、PTHREAD_STACK_MINMINSIGSTKSZSIGSTKSZ 宏的常量值,如 sysconf 调用。

您不再以将 PTHREAD_STACK_MINMINSIGSTKSZSIGSTKSZ 宏视为像常量值的方式使用它们。PTHREAD_STACK_MINMINSIGSTKSZSIGSTKSZ 宏返回的值现在是较长的数据类型,并可能会在与未签名值(如 size_t )相比生成编译器警告。

库合并到 libc.so.6

有了这个更新,以下库已合并到 libc 库中,以提供更顺畅的原位升级体验,支持进程在任何时候安全使用线程,并简化内部实现:

  • libpthread
  • libdl
  • libutil
  • libanl

另外,libresolv 库的一部分已移到 libc 中,以支持将名称切换服务(NSS)文件和域名系统(DNS)插件直接移到 libc 库中。NSS 文件和 DNS 插件现在直接构建到 libc 库中,并可在升级期间使用或跨 chroot 或容器边界使用。它们在 chroot 或容器边界的使用,支持从这些源安全地查询身份管理(IdM)数据。

zdump 工具的新位置

/usr/bin/zdumpzdump 工具的新位置。

弃用 sys_siglist_sys_siglistsys_sigabbrev 符号

sys_siglist_sys_siglistsys_sigabbrev 符号仅被导出为兼容性符号,以支持旧的二进制文件。所有程序都应该使用 strsignal 符号。

使用 sys_siglist_sys_siglistsys_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_npsigdescr_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_errlistsys_nerr_sys_nerr 符号

sys_errlist_sys_errlistsys_nerr_sys_nerr 符号仅被导出兼容性符号,以支持旧的二进制文件。所有程序都应该使用 strerrorstrerror_r 符号。

使用 sys_errlist_sys_errlistsys_nerr_sys_nerr 符号会导致问题,如复制重新定位和对阵列访问没有显式绑定检查的易出问题的 ABI。

这个更改可能会影响从源构建某些软件包。要解决这个问题,请使用 strerrorstrerror_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_npstrerrordesc_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, 更改

mallwatchtr_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_statemalloc_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.somalloc 目前支持 hook,并可预先加载以恢复旧程序的功能。但是,这是一个过渡措施,可能会在以后的 GNU C 库发行版本中删除。您可以通过编写和预先加载您自己的 malloc 组成库来从这些 hook 中移植出去。

lazy 绑定失败终止了进程

如果在 dlopen 函数期间发生了 lazy 绑定失败,则在 ELF 构造器执行过程中,进程现在被终止。在以前的版本中,动态加载程序从 dlopen 返回 NULL,并显示 dlerror 消息中捕获的 lazy 绑定错误。通常,这是不安全的,因为无法在任意函数调用中重置堆栈。

弃用 stime 功能

stime 函数不再对新链接的二进制文件可用,其声明已从 <time.h> 中删除。对于设置系统时间的程序,使用 clock_settime 函数。

popensystem 函数不再运行 fork 处理程序

虽然可能违反 POSIX ,但 pthread_atfork 文档中关于 atfork 处理程序的 POSIX 原理是在多线程进程中的 fork 调用后处理不一致的排它锁锁状态。在 popensystem 函数中,无法直接访问用户定义的排它锁。

C++ 标准库中已弃用的功能

  • 如果使用小于字符串的当前容量的参数调用,std::string::reserve (n) 将不再减少字符串的容量。可以通过调用不带参数的 reserve()来减少字符串的容量,但该形式已弃用。应该改为使用等同的 shrink_to_fit ()
  • 非标准 std::__is_nullptr_t 类型特征已弃用。应该改为使用标准的 std::is_null_pointer 特征。