Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d65988fcf0 | ||
|
|
4360d2fd2e | ||
|
|
da11edfa02 | ||
|
|
1c8ee1fa29 | ||
|
|
9fa28ece75 | ||
|
|
1347154cdc | ||
|
|
149d872970 | ||
|
|
19f9aeaaba | ||
|
|
56df2e1fc1 | ||
|
|
bb5693fa5e | ||
|
|
9355c44311 | ||
|
|
b5146b83ab | ||
|
|
38b00812ef | ||
|
|
b37d241dfe | ||
|
|
5c901bb360 | ||
|
|
4268281ab4 | ||
|
|
5c26c890ed | ||
|
|
475334f2db | ||
|
|
9ed6813222 | ||
|
|
58c7494c47 | ||
|
|
ccca821d4e | ||
|
|
1d717f1afd | ||
|
|
8043aba13f | ||
|
|
e7e10be26a |
@@ -17,7 +17,7 @@ includedir = $(prefix)/include
|
||||
libdir = $(prefix)/lib
|
||||
syslibdir = /lib
|
||||
|
||||
MALLOC_DIR = mallocng
|
||||
MALLOC_DIR = rpmalloc
|
||||
SRC_DIRS = $(addprefix $(srcdir)/,src/* src/malloc/$(MALLOC_DIR) crt ldso $(COMPAT_SRC_DIRS))
|
||||
BASE_GLOBS = $(addsuffix /*.c,$(SRC_DIRS))
|
||||
ARCH_GLOBS = $(addsuffix /$(ARCH)/*.[csS],$(SRC_DIRS))
|
||||
@@ -44,9 +44,8 @@ LIBCC = -lgcc
|
||||
CPPFLAGS =
|
||||
CFLAGS =
|
||||
CFLAGS_AUTO = -Os -pipe
|
||||
CFLAGS_C99FSE = -std=c99 -ffreestanding -nostdinc
|
||||
|
||||
CFLAGS_ALL = $(CFLAGS_C99FSE)
|
||||
CFLAGS_ALL = -std=c17 -ffreestanding -nostdinc
|
||||
CFLAGS_ALL += -D_XOPEN_SOURCE=700 -I$(srcdir)/arch/$(ARCH) -I$(srcdir)/arch/generic -Iobj/src/internal -I$(srcdir)/src/include -I$(srcdir)/src/internal -Iobj/include -I$(srcdir)/include
|
||||
CFLAGS_ALL += $(CPPFLAGS) $(CFLAGS_AUTO) $(CFLAGS)
|
||||
|
||||
|
||||
@@ -2438,3 +2438,56 @@ arch-specific bugs fixed:
|
||||
- riscv64 icache flush operation was non-functional
|
||||
- sh sigsetjmp failed to properly restore call-saved register r8 on return
|
||||
- sh dlsym RTLD_NEXT did not identify calling module correctly
|
||||
|
||||
|
||||
|
||||
1.2.6 release notes
|
||||
|
||||
new features:
|
||||
- posix_getdents interface (new in POSIX-2024)
|
||||
- renameat2 interface (linux extension)
|
||||
- iconv support for CP858
|
||||
- vdso clock_gettime for riscv{32,64}, powerpc{,64}, and s390x
|
||||
- loongarch64 TLSDESC support
|
||||
- exposed __getauxval for compiler runtime use detecting cpu features
|
||||
|
||||
compatibility:
|
||||
- initgroups no longer artificially limits number of supplementary groups
|
||||
- getusershell now skips blank lines and comments
|
||||
- exit is now explicitly thread-safe (possible future requirement)
|
||||
- atexit now fails rather than deadlocking if called from late dtor
|
||||
- strerror now has error strings for EUCLEAN and ENAVAIL
|
||||
- isatty no longer collapses errors to ENOTTY
|
||||
- sched.h namespace pollution with _GNU_SOURCE is reduced
|
||||
- hasmntopt now matches only whole options, not arbitrary substrings
|
||||
- shadow.h no longer declares an unimplemented sgetspent interface
|
||||
- vdso with missing sysv hash table (only gnu hash) is now supported
|
||||
|
||||
conformance:
|
||||
- pwrite now handles O_APPEND correctly, reports error if it can't
|
||||
- mbnrtowcs now conforms to new POSIX-2024 requirement for partial character
|
||||
- iconv GBK now properly includes euro symbol
|
||||
- strptime now accepts conversion specifiers added in POSIX-2024
|
||||
- inet_ntop IPv6 "zero compression" now conforms to RFC 5952
|
||||
|
||||
bugs fixed:
|
||||
- iconv euc-kr decoder could do oob writes on invalid inputs (CVE-2025-26519)
|
||||
- iconv shift_jis decoder could produce wrong outputs for some invalid inputs
|
||||
- printf did not honor hex float precision correctly in some cases
|
||||
- lost or delayed wakes in sem_post under race condition
|
||||
- termios input speed handling was wrong
|
||||
- strcasestr failed to match zero-length needle
|
||||
- fma handled corner case with negative zero wrongly
|
||||
- syslog LOG_MAKEPRI macro was incorrect
|
||||
- timer_create is no longer affected by known pthread_barrier bugs
|
||||
- sysconf(_SC_MINSIGSTKSZ) computed min size incorrectly
|
||||
- statx emulation left some fields uninitialized
|
||||
- mntent wrongly included final newline in parsed field output
|
||||
- SIGEV_THREAD timers could abort process if SIGTIMER became unblocked
|
||||
- bind_textdomain_codeset returned wrong value
|
||||
|
||||
arch-specific bugs fixed:
|
||||
- early dynamic linker handled page size wrong on dynamic pagesize archs
|
||||
- arm and aarch64 crti/n files had wrong alignment
|
||||
- m68k POLLWRNORM and POLLWRBAND values were incorrect
|
||||
- x32 mq ABI was mismatched
|
||||
|
||||
@@ -296,12 +296,32 @@
|
||||
#define __NR_process_madvise 440
|
||||
#define __NR_epoll_pwait2 441
|
||||
#define __NR_mount_setattr 442
|
||||
#define __NR_quotactl_fd 443
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
#define __NR_memfd_secret 447
|
||||
#define __NR_process_mrelease 448
|
||||
#define __NR_futex_waitv 449
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
|
||||
@@ -396,6 +396,7 @@
|
||||
#define __NR_process_madvise 440
|
||||
#define __NR_epoll_pwait2 441
|
||||
#define __NR_mount_setattr 442
|
||||
#define __NR_quotactl_fd 443
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
@@ -404,6 +405,24 @@
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
#define __ARM_NR_breakpoint 0x0f0001
|
||||
#define __ARM_NR_cacheflush 0x0f0002
|
||||
|
||||
@@ -433,6 +433,7 @@
|
||||
#define __NR_process_madvise 440
|
||||
#define __NR_epoll_pwait2 441
|
||||
#define __NR_mount_setattr 442
|
||||
#define __NR_quotactl_fd 443
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
@@ -442,4 +443,22 @@
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
#endif
|
||||
|
||||
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
|
||||
#define SC_USED_FP (1U << 0)
|
||||
#define SC_ADDRERR_RD (1U << 30)
|
||||
#define SC_ADDRERR_WR (1U << 31)
|
||||
|
||||
typedef unsigned long greg_t, gregset_t[32];
|
||||
|
||||
struct sigcontext {
|
||||
@@ -26,6 +30,45 @@ struct sigcontext {
|
||||
unsigned sc_flags;
|
||||
unsigned long sc_extcontext[] __attribute__((__aligned__(16)));
|
||||
};
|
||||
|
||||
#define CONTEXT_INFO_ALIGN 16
|
||||
struct sctx_info {
|
||||
unsigned magic;
|
||||
unsigned size;
|
||||
unsigned long padding;
|
||||
};
|
||||
|
||||
#define FPU_CTX_MAGIC 0x46505501
|
||||
#define FPU_CTX_ALIGN 8
|
||||
struct fpu_context {
|
||||
unsigned long regs[32];
|
||||
unsigned long fcc;
|
||||
unsigned fcsr;
|
||||
};
|
||||
|
||||
#define LSX_CTX_MAGIC 0x53580001
|
||||
#define LSX_CTX_ALIGN 16
|
||||
struct lsx_context {
|
||||
unsigned long regs[2*32];
|
||||
unsigned long fcc;
|
||||
unsigned fcsr;
|
||||
};
|
||||
|
||||
#define LASX_CTX_MAGIC 0x41535801
|
||||
#define LASX_CTX_ALIGN 32
|
||||
struct lasx_context {
|
||||
unsigned long regs[4*32];
|
||||
unsigned long fcc;
|
||||
unsigned fcsr;
|
||||
};
|
||||
|
||||
#define LBT_CTX_MAGIC 0x42540001
|
||||
#define LBT_CTX_ALIGN 8
|
||||
struct lbt_context {
|
||||
unsigned long regs[4];
|
||||
unsigned eflags;
|
||||
unsigned ftop;
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -305,6 +305,20 @@
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
#define __NR_fcntl __NR3264_fcntl
|
||||
#define __NR_statfs __NR3264_statfs
|
||||
#define __NR_fstatfs __NR3264_fstatfs
|
||||
|
||||
@@ -22,3 +22,17 @@ typedef union {
|
||||
float f;
|
||||
} elf_fpreg_t;
|
||||
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
|
||||
|
||||
typedef union
|
||||
{
|
||||
__attribute__((__aligned__(16)))
|
||||
double d[2];
|
||||
float f[4];
|
||||
} elf_lsxregset_t[32];
|
||||
|
||||
typedef union
|
||||
{
|
||||
__attribute__((__aligned__(32)))
|
||||
double d[4];
|
||||
float f[8];
|
||||
} elf_lasxregset_t[32];
|
||||
|
||||
@@ -413,6 +413,7 @@
|
||||
#define __NR_process_madvise 440
|
||||
#define __NR_epoll_pwait2 441
|
||||
#define __NR_mount_setattr 442
|
||||
#define __NR_quotactl_fd 443
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
@@ -421,3 +422,21 @@
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
@@ -434,6 +434,7 @@
|
||||
#define __NR_process_madvise 440
|
||||
#define __NR_epoll_pwait2 441
|
||||
#define __NR_mount_setattr 442
|
||||
#define __NR_quotactl_fd 443
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
@@ -442,4 +443,22 @@
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
|
||||
@@ -415,6 +415,7 @@
|
||||
#define __NR_process_madvise 4440
|
||||
#define __NR_epoll_pwait2 4441
|
||||
#define __NR_mount_setattr 4442
|
||||
#define __NR_quotactl_fd 4443
|
||||
#define __NR_landlock_create_ruleset 4444
|
||||
#define __NR_landlock_add_rule 4445
|
||||
#define __NR_landlock_restrict_self 4446
|
||||
@@ -423,4 +424,22 @@
|
||||
#define __NR_set_mempolicy_home_node 4450
|
||||
#define __NR_cachestat 4451
|
||||
#define __NR_fchmodat2 4452
|
||||
#define __NR_map_shadow_stack 4453
|
||||
#define __NR_futex_wake 4454
|
||||
#define __NR_futex_wait 4455
|
||||
#define __NR_futex_requeue 4456
|
||||
#define __NR_statmount 4457
|
||||
#define __NR_listmount 4458
|
||||
#define __NR_lsm_get_self_attr 4459
|
||||
#define __NR_lsm_set_self_attr 4460
|
||||
#define __NR_lsm_list_modules 4461
|
||||
#define __NR_mseal 4462
|
||||
#define __NR_setxattrat 4463
|
||||
#define __NR_getxattrat 4464
|
||||
#define __NR_listxattrat 4465
|
||||
#define __NR_removexattrat 4466
|
||||
#define __NR_open_tree_attr 4467
|
||||
#define __NR_file_getattr 4468
|
||||
#define __NR_file_setattr 4469
|
||||
#define __NR_listns 4470
|
||||
|
||||
|
||||
@@ -345,6 +345,7 @@
|
||||
#define __NR_process_madvise 5440
|
||||
#define __NR_epoll_pwait2 5441
|
||||
#define __NR_mount_setattr 5442
|
||||
#define __NR_quotactl_fd 5443
|
||||
#define __NR_landlock_create_ruleset 5444
|
||||
#define __NR_landlock_add_rule 5445
|
||||
#define __NR_landlock_restrict_self 5446
|
||||
@@ -353,4 +354,22 @@
|
||||
#define __NR_set_mempolicy_home_node 5450
|
||||
#define __NR_cachestat 5451
|
||||
#define __NR_fchmodat2 5452
|
||||
#define __NR_map_shadow_stack 5453
|
||||
#define __NR_futex_wake 5454
|
||||
#define __NR_futex_wait 5455
|
||||
#define __NR_futex_requeue 5456
|
||||
#define __NR_statmount 5457
|
||||
#define __NR_listmount 5458
|
||||
#define __NR_lsm_get_self_attr 5459
|
||||
#define __NR_lsm_set_self_attr 5460
|
||||
#define __NR_lsm_list_modules 5461
|
||||
#define __NR_mseal 5462
|
||||
#define __NR_setxattrat 5463
|
||||
#define __NR_getxattrat 5464
|
||||
#define __NR_listxattrat 5465
|
||||
#define __NR_removexattrat 5466
|
||||
#define __NR_open_tree_attr 5467
|
||||
#define __NR_file_getattr 5468
|
||||
#define __NR_file_setattr 5469
|
||||
#define __NR_listns 5470
|
||||
|
||||
|
||||
@@ -369,6 +369,7 @@
|
||||
#define __NR_process_madvise 6440
|
||||
#define __NR_epoll_pwait2 6441
|
||||
#define __NR_mount_setattr 6442
|
||||
#define __NR_quotactl_fd 6443
|
||||
#define __NR_landlock_create_ruleset 6444
|
||||
#define __NR_landlock_add_rule 6445
|
||||
#define __NR_landlock_restrict_self 6446
|
||||
@@ -377,4 +378,22 @@
|
||||
#define __NR_set_mempolicy_home_node 6450
|
||||
#define __NR_cachestat 6451
|
||||
#define __NR_fchmodat2 6452
|
||||
#define __NR_map_shadow_stack 6453
|
||||
#define __NR_futex_wake 6454
|
||||
#define __NR_futex_wait 6455
|
||||
#define __NR_futex_requeue 6456
|
||||
#define __NR_statmount 6457
|
||||
#define __NR_listmount 6458
|
||||
#define __NR_lsm_get_self_attr 6459
|
||||
#define __NR_lsm_set_self_attr 6460
|
||||
#define __NR_lsm_list_modules 6461
|
||||
#define __NR_mseal 6462
|
||||
#define __NR_setxattrat 6463
|
||||
#define __NR_getxattrat 6464
|
||||
#define __NR_listxattrat 6465
|
||||
#define __NR_removexattrat 6466
|
||||
#define __NR_open_tree_attr 6467
|
||||
#define __NR_file_getattr 6468
|
||||
#define __NR_file_setattr 6469
|
||||
#define __NR_listns 6470
|
||||
|
||||
|
||||
@@ -318,6 +318,7 @@
|
||||
#define __NR_process_madvise 440
|
||||
#define __NR_epoll_pwait2 441
|
||||
#define __NR_mount_setattr 442
|
||||
#define __NR_quotactl_fd 443
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
@@ -326,4 +327,22 @@
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
|
||||
@@ -422,6 +422,7 @@
|
||||
#define __NR_process_madvise 440
|
||||
#define __NR_epoll_pwait2 441
|
||||
#define __NR_mount_setattr 442
|
||||
#define __NR_quotactl_fd 443
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
@@ -430,4 +431,22 @@
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
|
||||
@@ -394,6 +394,7 @@
|
||||
#define __NR_process_madvise 440
|
||||
#define __NR_epoll_pwait2 441
|
||||
#define __NR_mount_setattr 442
|
||||
#define __NR_quotactl_fd 443
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
@@ -402,4 +403,22 @@
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
|
||||
@@ -289,12 +289,32 @@
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
#define __NR_memfd_secret 447
|
||||
#define __NR_process_mrelease 448
|
||||
#define __NR_futex_waitv 449
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex __NR_futex_time64
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
#define __NR_sysriscv __NR_arch_specific_syscall
|
||||
#define __NR_riscv_flush_icache (__NR_sysriscv + 15)
|
||||
#define __NR_riscv_hwprobe (__NR_sysriscv + 14)
|
||||
|
||||
@@ -296,14 +296,35 @@
|
||||
#define __NR_process_madvise 440
|
||||
#define __NR_epoll_pwait2 441
|
||||
#define __NR_mount_setattr 442
|
||||
#define __NR_quotactl_fd 443
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
#define __NR_memfd_secret 447
|
||||
#define __NR_process_mrelease 448
|
||||
#define __NR_futex_waitv 449
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
#define __NR_sysriscv __NR_arch_specific_syscall
|
||||
#define __NR_riscv_flush_icache (__NR_sysriscv + 15)
|
||||
#define __NR_riscv_hwprobe (__NR_sysriscv + 14)
|
||||
|
||||
@@ -359,6 +359,7 @@
|
||||
#define __NR_process_madvise 440
|
||||
#define __NR_epoll_pwait2 441
|
||||
#define __NR_mount_setattr 442
|
||||
#define __NR_quotactl_fd 443
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
@@ -368,4 +369,22 @@
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
|
||||
@@ -357,6 +357,7 @@
|
||||
#define __NR_pkey_alloc 385
|
||||
#define __NR_pkey_free 386
|
||||
#define __NR_rseq 387
|
||||
#define __NR_sync_file_range2 388
|
||||
#define __NR_semget 393
|
||||
#define __NR_semctl 394
|
||||
#define __NR_shmget 395
|
||||
@@ -406,6 +407,7 @@
|
||||
#define __NR_process_madvise 440
|
||||
#define __NR_epoll_pwait2 441
|
||||
#define __NR_mount_setattr 442
|
||||
#define __NR_quotactl_fd 443
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
@@ -414,4 +416,22 @@
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
|
||||
@@ -286,6 +286,8 @@
|
||||
#define __NR_statx (0x40000000 + 332)
|
||||
#define __NR_io_pgetevents (0x40000000 + 333)
|
||||
#define __NR_rseq (0x40000000 + 334)
|
||||
#define __NR_uretprobe (0x40000000 + 335)
|
||||
#define __NR_uprobe (0x40000000 + 336)
|
||||
#define __NR_pidfd_send_signal (0x40000000 + 424)
|
||||
#define __NR_io_uring_setup (0x40000000 + 425)
|
||||
#define __NR_io_uring_enter (0x40000000 + 426)
|
||||
@@ -305,6 +307,7 @@
|
||||
#define __NR_process_madvise (0x40000000 + 440)
|
||||
#define __NR_epoll_pwait2 (0x40000000 + 441)
|
||||
#define __NR_mount_setattr (0x40000000 + 442)
|
||||
#define __NR_quotactl_fd (0x40000000 + 443)
|
||||
#define __NR_landlock_create_ruleset (0x40000000 + 444)
|
||||
#define __NR_landlock_add_rule (0x40000000 + 445)
|
||||
#define __NR_landlock_restrict_self (0x40000000 + 446)
|
||||
@@ -314,6 +317,24 @@
|
||||
#define __NR_set_mempolicy_home_node (0x40000000 + 450)
|
||||
#define __NR_cachestat (0x40000000 + 451)
|
||||
#define __NR_fchmodat2 (0x40000000 + 452)
|
||||
#define __NR_map_shadow_stack (0x40000000 + 453)
|
||||
#define __NR_futex_wake (0x40000000 + 454)
|
||||
#define __NR_futex_wait (0x40000000 + 455)
|
||||
#define __NR_futex_requeue (0x40000000 + 456)
|
||||
#define __NR_statmount (0x40000000 + 457)
|
||||
#define __NR_listmount (0x40000000 + 458)
|
||||
#define __NR_lsm_get_self_attr (0x40000000 + 459)
|
||||
#define __NR_lsm_set_self_attr (0x40000000 + 460)
|
||||
#define __NR_lsm_list_modules (0x40000000 + 461)
|
||||
#define __NR_mseal (0x40000000 + 462)
|
||||
#define __NR_setxattrat (0x40000000 + 463)
|
||||
#define __NR_getxattrat (0x40000000 + 464)
|
||||
#define __NR_listxattrat (0x40000000 + 465)
|
||||
#define __NR_removexattrat (0x40000000 + 466)
|
||||
#define __NR_open_tree_attr (0x40000000 + 467)
|
||||
#define __NR_file_getattr (0x40000000 + 468)
|
||||
#define __NR_file_setattr (0x40000000 + 469)
|
||||
#define __NR_listns (0x40000000 + 470)
|
||||
|
||||
|
||||
#define __NR_rt_sigaction (0x40000000 + 512)
|
||||
|
||||
@@ -333,6 +333,8 @@
|
||||
#define __NR_statx 332
|
||||
#define __NR_io_pgetevents 333
|
||||
#define __NR_rseq 334
|
||||
#define __NR_uretprobe 335
|
||||
#define __NR_uprobe 336
|
||||
#define __NR_pidfd_send_signal 424
|
||||
#define __NR_io_uring_setup 425
|
||||
#define __NR_io_uring_enter 426
|
||||
@@ -352,6 +354,7 @@
|
||||
#define __NR_process_madvise 440
|
||||
#define __NR_epoll_pwait2 441
|
||||
#define __NR_mount_setattr 442
|
||||
#define __NR_quotactl_fd 443
|
||||
#define __NR_landlock_create_ruleset 444
|
||||
#define __NR_landlock_add_rule 445
|
||||
#define __NR_landlock_restrict_self 446
|
||||
@@ -361,4 +364,22 @@
|
||||
#define __NR_set_mempolicy_home_node 450
|
||||
#define __NR_cachestat 451
|
||||
#define __NR_fchmodat2 452
|
||||
#define __NR_map_shadow_stack 453
|
||||
#define __NR_futex_wake 454
|
||||
#define __NR_futex_wait 455
|
||||
#define __NR_futex_requeue 456
|
||||
#define __NR_statmount 457
|
||||
#define __NR_listmount 458
|
||||
#define __NR_lsm_get_self_attr 459
|
||||
#define __NR_lsm_set_self_attr 460
|
||||
#define __NR_lsm_list_modules 461
|
||||
#define __NR_mseal 462
|
||||
#define __NR_setxattrat 463
|
||||
#define __NR_getxattrat 464
|
||||
#define __NR_listxattrat 465
|
||||
#define __NR_removexattrat 466
|
||||
#define __NR_open_tree_attr 467
|
||||
#define __NR_file_getattr 468
|
||||
#define __NR_file_setattr 469
|
||||
#define __NR_listns 470
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ Optional features:
|
||||
--disable-static inhibit building static library [enabled]
|
||||
|
||||
Optional packages:
|
||||
--with-malloc=... choose malloc implementation [mallocng]
|
||||
--with-malloc=... choose malloc implementation [rpmalloc]
|
||||
|
||||
Some influential environment variables:
|
||||
CC C compiler command [detected]
|
||||
@@ -142,7 +142,7 @@ static=yes
|
||||
wrapper=auto
|
||||
gcc_wrapper=no
|
||||
clang_wrapper=no
|
||||
malloc_dir=mallocng
|
||||
malloc_dir=rpmalloc
|
||||
|
||||
for arg ; do
|
||||
case "$arg" in
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@
|
||||
#include "crt_arch.h"
|
||||
|
||||
int main();
|
||||
weak void _init();
|
||||
weak void _fini();
|
||||
__weak void _init();
|
||||
__weak void _fini();
|
||||
int __libc_start_main(int (*)(), int, char **,
|
||||
void (*)(), void(*)(), void(*)());
|
||||
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
#include "../ldso/dlstart.c"
|
||||
|
||||
int main();
|
||||
weak void _init();
|
||||
weak void _fini();
|
||||
__weak void _init();
|
||||
__weak void _fini();
|
||||
int __libc_start_main(int (*)(), int, char **,
|
||||
void (*)(), void(*)(), void(*)());
|
||||
|
||||
|
||||
@@ -712,6 +712,8 @@ typedef struct {
|
||||
#define NT_LOONGARCH_LSX 0xa02
|
||||
#define NT_LOONGARCH_LASX 0xa03
|
||||
#define NT_LOONGARCH_LBT 0xa04
|
||||
#define NT_LOONGARCH_HW_BREAK 0xa05
|
||||
#define NT_LOONGARCH_HW_WATCH 0xa06
|
||||
|
||||
|
||||
|
||||
@@ -3408,6 +3410,32 @@ enum
|
||||
#define R_LARCH_TLS_GD_HI20 98
|
||||
#define R_LARCH_32_PCREL 99
|
||||
#define R_LARCH_RELAX 100
|
||||
#define R_LARCH_DELETE 101
|
||||
#define R_LARCH_ALIGN 102
|
||||
#define R_LARCH_PCREL20_S2 103
|
||||
#define R_LARCH_CFA 104
|
||||
#define R_LARCH_ADD6 105
|
||||
#define R_LARCH_SUB6 106
|
||||
#define R_LARCH_ADD_ULEB128 107
|
||||
#define R_LARCH_SUB_ULEB128 108
|
||||
#define R_LARCH_64_PCREL 109
|
||||
#define R_LARCH_CALL36 110
|
||||
#define R_LARCH_TLS_DESC_PC_HI20 111
|
||||
#define R_LARCH_TLS_DESC_PC_LO12 112
|
||||
#define R_LARCH_TLS_DESC64_PC_LO20 113
|
||||
#define R_LARCH_TLS_DESC64_PC_HI12 114
|
||||
#define R_LARCH_TLS_DESC_HI20 115
|
||||
#define R_LARCH_TLS_DESC_LO12 116
|
||||
#define R_LARCH_TLS_DESC64_LO20 117
|
||||
#define R_LARCH_TLS_DESC64_HI12 118
|
||||
#define R_LARCH_TLS_DESC_LD 119
|
||||
#define R_LARCH_TLS_DESC_CALL 120
|
||||
#define R_LARCH_TLS_LE_HI20_R 121
|
||||
#define R_LARCH_TLS_LE_ADD_R 122
|
||||
#define R_LARCH_TLS_LE_LO12_R 123
|
||||
#define R_LARCH_TLS_LD_PCREL20_S2 124
|
||||
#define R_LARCH_TLS_GD_PCREL20_S2 125
|
||||
#define R_LARCH_TLS_DESC_PCREL20_S2 126
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ typedef struct __res_state {
|
||||
#define __RES 19960801
|
||||
|
||||
#ifndef _PATH_RESCONF
|
||||
#define _PATH_RESCONF "/etc/resolv.conf"
|
||||
#define _PATH_RESCONF "/var/config/network/resolv.conf"
|
||||
#endif
|
||||
|
||||
struct res_sym {
|
||||
|
||||
@@ -0,0 +1,346 @@
|
||||
/*-
|
||||
* Copyright (c) 2011 Ed Schouten <[email protected]>
|
||||
* David Chisnall <[email protected]>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD: src/include/stdatomic.h,v 1.10.2.2 2012/05/30 19:21:54 theraven Exp $
|
||||
*/
|
||||
#ifndef _STDATOMIC_H_
|
||||
#define _STDATOMIC_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined(__has_feature)
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
#if !defined(__has_builtin)
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
#if !defined(__GNUC_PREREQ__)
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||
#define __GNUC_PREREQ__(maj, min) \
|
||||
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
|
||||
#else
|
||||
#define __GNUC_PREREQ__(maj, min) 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(__CLANG_ATOMICS) && !defined(__GNUC_ATOMICS)
|
||||
#if __GNUC_PREREQ__(4, 7)
|
||||
#define __GNUC_ATOMICS
|
||||
#elif __has_feature(c_atomic)
|
||||
#define __CLANG_ATOMICS
|
||||
#elif !defined(__GNUC__)
|
||||
#error "stdatomic.h does not support your compiler"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 7.17.2 Initialization.
|
||||
*/
|
||||
|
||||
#if defined(__CLANG_ATOMICS)
|
||||
#define ATOMIC_VAR_INIT(value) (value)
|
||||
#define atomic_init(obj, value) __c11_atomic_init(obj, value)
|
||||
#else
|
||||
#define ATOMIC_VAR_INIT(value) (value)
|
||||
#define atomic_init(obj, value) do { \
|
||||
*(obj) = (value); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Clang and recent GCC both provide predefined macros for the memory
|
||||
* orderings. If we are using a compiler that doesn't define them, use the
|
||||
* clang values - these will be ignored in the fallback path.
|
||||
*/
|
||||
|
||||
#ifndef __ATOMIC_RELAXED
|
||||
#define __ATOMIC_RELAXED 0
|
||||
#endif
|
||||
#ifndef __ATOMIC_CONSUME
|
||||
#define __ATOMIC_CONSUME 1
|
||||
#endif
|
||||
#ifndef __ATOMIC_ACQUIRE
|
||||
#define __ATOMIC_ACQUIRE 2
|
||||
#endif
|
||||
#ifndef __ATOMIC_RELEASE
|
||||
#define __ATOMIC_RELEASE 3
|
||||
#endif
|
||||
#ifndef __ATOMIC_ACQ_REL
|
||||
#define __ATOMIC_ACQ_REL 4
|
||||
#endif
|
||||
#ifndef __ATOMIC_SEQ_CST
|
||||
#define __ATOMIC_SEQ_CST 5
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 7.17.3 Order and consistency.
|
||||
*
|
||||
* The memory_order_* constants that denote the barrier behaviour of the
|
||||
* atomic operations.
|
||||
*/
|
||||
|
||||
enum memory_order {
|
||||
memory_order_relaxed = __ATOMIC_RELAXED,
|
||||
memory_order_consume = __ATOMIC_CONSUME,
|
||||
memory_order_acquire = __ATOMIC_ACQUIRE,
|
||||
memory_order_release = __ATOMIC_RELEASE,
|
||||
memory_order_acq_rel = __ATOMIC_ACQ_REL,
|
||||
memory_order_seq_cst = __ATOMIC_SEQ_CST
|
||||
};
|
||||
|
||||
typedef enum memory_order memory_order;
|
||||
|
||||
/*
|
||||
* 7.17.4 Fences.
|
||||
*/
|
||||
|
||||
#ifdef __CLANG_ATOMICS
|
||||
#define atomic_thread_fence(order) __c11_atomic_thread_fence(order)
|
||||
#define atomic_signal_fence(order) __c11_atomic_signal_fence(order)
|
||||
#elif defined(__GNUC_ATOMICS)
|
||||
#define atomic_thread_fence(order) __atomic_thread_fence(order)
|
||||
#define atomic_signal_fence(order) __atomic_signal_fence(order)
|
||||
#else
|
||||
#define atomic_thread_fence(order) __sync_synchronize()
|
||||
#define atomic_signal_fence(order) __asm volatile ("" : : : "memory")
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 7.17.5 Lock-free property.
|
||||
*/
|
||||
|
||||
#if defined(__CLANG_ATOMICS)
|
||||
#define atomic_is_lock_free(obj) \
|
||||
__c11_atomic_is_lock_free(sizeof(obj))
|
||||
#elif defined(__GNUC_ATOMICS)
|
||||
#define atomic_is_lock_free(obj) \
|
||||
__atomic_is_lock_free(sizeof((obj)->__val))
|
||||
#else
|
||||
#define atomic_is_lock_free(obj) \
|
||||
(sizeof((obj)->__val) <= sizeof(void *))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 7.17.6 Atomic integer types.
|
||||
*/
|
||||
|
||||
typedef _Atomic(_Bool) atomic_bool;
|
||||
typedef _Atomic(char) atomic_char;
|
||||
typedef _Atomic(signed char) atomic_schar;
|
||||
typedef _Atomic(unsigned char) atomic_uchar;
|
||||
typedef _Atomic(short) atomic_short;
|
||||
typedef _Atomic(unsigned short) atomic_ushort;
|
||||
typedef _Atomic(int) atomic_int;
|
||||
typedef _Atomic(unsigned int) atomic_uint;
|
||||
typedef _Atomic(long) atomic_long;
|
||||
typedef _Atomic(unsigned long) atomic_ulong;
|
||||
typedef _Atomic(long long) atomic_llong;
|
||||
typedef _Atomic(unsigned long long) atomic_ullong;
|
||||
#if 0
|
||||
typedef _Atomic(char16_t) atomic_char16_t;
|
||||
typedef _Atomic(char32_t) atomic_char32_t;
|
||||
#endif
|
||||
typedef _Atomic(wchar_t) atomic_wchar_t;
|
||||
typedef _Atomic(int_least8_t) atomic_int_least8_t;
|
||||
typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
|
||||
typedef _Atomic(int_least16_t) atomic_int_least16_t;
|
||||
typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
|
||||
typedef _Atomic(int_least32_t) atomic_int_least32_t;
|
||||
typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
|
||||
typedef _Atomic(int_least64_t) atomic_int_least64_t;
|
||||
typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
|
||||
typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
|
||||
typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
|
||||
typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
|
||||
typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
|
||||
typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
|
||||
typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
|
||||
typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
|
||||
typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
|
||||
typedef _Atomic(intptr_t) atomic_intptr_t;
|
||||
typedef _Atomic(uintptr_t) atomic_uintptr_t;
|
||||
typedef _Atomic(size_t) atomic_size_t;
|
||||
typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
|
||||
typedef _Atomic(intmax_t) atomic_intmax_t;
|
||||
typedef _Atomic(uintmax_t) atomic_uintmax_t;
|
||||
|
||||
/*
|
||||
* 7.17.7 Operations on atomic types.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Compiler-specific operations.
|
||||
*/
|
||||
|
||||
#if defined(__CLANG_ATOMICS)
|
||||
#define atomic_compare_exchange_strong_explicit(object, expected, \
|
||||
desired, success, failure) \
|
||||
__c11_atomic_compare_exchange_strong(object, expected, desired, \
|
||||
success, failure)
|
||||
#define atomic_compare_exchange_weak_explicit(object, expected, \
|
||||
desired, success, failure) \
|
||||
__c11_atomic_compare_exchange_weak(object, expected, desired, \
|
||||
success, failure)
|
||||
#define atomic_exchange_explicit(object, desired, order) \
|
||||
__c11_atomic_exchange(object, desired, order)
|
||||
#define atomic_fetch_add_explicit(object, operand, order) \
|
||||
__c11_atomic_fetch_add(object, operand, order)
|
||||
#define atomic_fetch_and_explicit(object, operand, order) \
|
||||
__c11_atomic_fetch_and(object, operand, order)
|
||||
#define atomic_fetch_or_explicit(object, operand, order) \
|
||||
__c11_atomic_fetch_or(object, operand, order)
|
||||
#define atomic_fetch_sub_explicit(object, operand, order) \
|
||||
__c11_atomic_fetch_sub(object, operand, order)
|
||||
#define atomic_fetch_xor_explicit(object, operand, order) \
|
||||
__c11_atomic_fetch_xor(object, operand, order)
|
||||
#define atomic_load_explicit(object, order) \
|
||||
__c11_atomic_load(object, order)
|
||||
#define atomic_store_explicit(object, desired, order) \
|
||||
__c11_atomic_store(object, desired, order)
|
||||
#elif defined(__GNUC_ATOMICS)
|
||||
#define atomic_compare_exchange_strong_explicit(object, expected, \
|
||||
desired, success, failure) \
|
||||
__atomic_compare_exchange_n(object, expected, \
|
||||
desired, 0, success, failure)
|
||||
#define atomic_compare_exchange_weak_explicit(object, expected, \
|
||||
desired, success, failure) \
|
||||
__atomic_compare_exchange_n(object, expected, \
|
||||
desired, 1, success, failure)
|
||||
#define atomic_exchange_explicit(object, desired, order) \
|
||||
__atomic_exchange_n(object, desired, order)
|
||||
#define atomic_fetch_add_explicit(object, operand, order) \
|
||||
__atomic_fetch_add(object, operand, order)
|
||||
#define atomic_fetch_and_explicit(object, operand, order) \
|
||||
__atomic_fetch_and(object, operand, order)
|
||||
#define atomic_fetch_or_explicit(object, operand, order) \
|
||||
__atomic_fetch_or(object, operand, order)
|
||||
#define atomic_fetch_sub_explicit(object, operand, order) \
|
||||
__atomic_fetch_sub(object, operand, order)
|
||||
#define atomic_fetch_xor_explicit(object, operand, order) \
|
||||
__atomic_fetch_xor(object, operand, order)
|
||||
#define atomic_load_explicit(object, order) \
|
||||
__atomic_load_n(object, order)
|
||||
#define atomic_store_explicit(object, desired, order) \
|
||||
__atomic_store_n(object, desired, order)
|
||||
#else
|
||||
#define atomic_compare_exchange_strong_explicit(object, expected, \
|
||||
desired, success, failure) ({ \
|
||||
__typeof__(*(object)) __v; \
|
||||
_Bool __r; \
|
||||
__v = __sync_val_compare_and_swap(object, \
|
||||
*(expected), desired); \
|
||||
__r = *(expected) == __v; \
|
||||
*(expected) = __v; \
|
||||
__r; \
|
||||
})
|
||||
|
||||
#define atomic_compare_exchange_weak_explicit(object, expected, \
|
||||
desired, success, failure) \
|
||||
atomic_compare_exchange_strong_explicit(object, expected, \
|
||||
desired, success, failure)
|
||||
#if __has_builtin(__sync_swap)
|
||||
/* Clang provides a full-barrier atomic exchange - use it if available. */
|
||||
#define atomic_exchange_explicit(object, desired, order) \
|
||||
__sync_swap(object, desired)
|
||||
#else
|
||||
/*
|
||||
* __sync_lock_test_and_set() is only an acquire barrier in theory (although in
|
||||
* practice it is usually a full barrier) so we need an explicit barrier after
|
||||
* it.
|
||||
*/
|
||||
#define atomic_exchange_explicit(object, desired, order) ({ \
|
||||
__typeof__(*(object)) __v; \
|
||||
__v = __sync_lock_test_and_set(object, desired); \
|
||||
__sync_synchronize(); \
|
||||
__v; \
|
||||
})
|
||||
#endif
|
||||
#define atomic_fetch_add_explicit(object, operand, order) \
|
||||
__sync_fetch_and_add(object, operand)
|
||||
#define atomic_fetch_and_explicit(object, operand, order) \
|
||||
__sync_fetch_and_and(object, operand)
|
||||
#define atomic_fetch_or_explicit(object, operand, order) \
|
||||
__sync_fetch_and_or(object, operand)
|
||||
#define atomic_fetch_sub_explicit(object, operand, order) \
|
||||
__sync_fetch_and_sub(object, operand)
|
||||
#define atomic_fetch_xor_explicit(object, operand, order) \
|
||||
__sync_fetch_and_xor(object, operand)
|
||||
#define atomic_load_explicit(object, order) \
|
||||
__sync_fetch_and_add(object, 0)
|
||||
#define atomic_store_explicit(object, desired, order) do { \
|
||||
__sync_synchronize(); \
|
||||
*(object) = (desired); \
|
||||
__sync_synchronize(); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Convenience functions.
|
||||
*/
|
||||
|
||||
#define atomic_compare_exchange_strong(object, expected, desired) \
|
||||
atomic_compare_exchange_strong_explicit(object, expected, \
|
||||
desired, memory_order_seq_cst, memory_order_seq_cst)
|
||||
#define atomic_compare_exchange_weak(object, expected, desired) \
|
||||
atomic_compare_exchange_weak_explicit(object, expected, \
|
||||
desired, memory_order_seq_cst, memory_order_seq_cst)
|
||||
#define atomic_exchange(object, desired) \
|
||||
atomic_exchange_explicit(object, desired, memory_order_seq_cst)
|
||||
#define atomic_fetch_add(object, operand) \
|
||||
atomic_fetch_add_explicit(object, operand, memory_order_seq_cst)
|
||||
#define atomic_fetch_and(object, operand) \
|
||||
atomic_fetch_and_explicit(object, operand, memory_order_seq_cst)
|
||||
#define atomic_fetch_or(object, operand) \
|
||||
atomic_fetch_or_explicit(object, operand, memory_order_seq_cst)
|
||||
#define atomic_fetch_sub(object, operand) \
|
||||
atomic_fetch_sub_explicit(object, operand, memory_order_seq_cst)
|
||||
#define atomic_fetch_xor(object, operand) \
|
||||
atomic_fetch_xor_explicit(object, operand, memory_order_seq_cst)
|
||||
#define atomic_load(object) \
|
||||
atomic_load_explicit(object, memory_order_seq_cst)
|
||||
#define atomic_store(object, desired) \
|
||||
atomic_store_explicit(object, desired, memory_order_seq_cst)
|
||||
|
||||
/*
|
||||
* 7.17.8 Atomic flag type and operations.
|
||||
*/
|
||||
|
||||
typedef atomic_bool atomic_flag;
|
||||
|
||||
#define ATOMIC_FLAG_INIT ATOMIC_VAR_INIT(0)
|
||||
|
||||
#define atomic_flag_clear_explicit(object, order) \
|
||||
atomic_store_explicit(object, 0, order)
|
||||
#define atomic_flag_test_and_set_explicit(object, order) \
|
||||
atomic_compare_exchange_strong_explicit(object, 0, 1, order, order)
|
||||
|
||||
#define atomic_flag_clear(object) \
|
||||
atomic_flag_clear_explicit(object, memory_order_seq_cst)
|
||||
#define atomic_flag_test_and_set(object) \
|
||||
atomic_flag_test_and_set_explicit(object, memory_order_seq_cst)
|
||||
|
||||
#endif /* !_STDATOMIC_H_ */
|
||||
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright 2023 Justine Alexandra Roberts Tunney
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview C23 Checked Arithmetic
|
||||
*
|
||||
* This header defines three type generic functions:
|
||||
*
|
||||
* - `bool ckd_add(res, a, b)`
|
||||
* - `bool ckd_sub(res, a, b)`
|
||||
* - `bool ckd_mul(res, a, b)`
|
||||
*
|
||||
* Which allow integer arithmetic errors to be detected. There are many
|
||||
* kinds of integer errors, e.g. overflow, truncation, etc. These funcs
|
||||
* catch them all. Here's an example of how it works:
|
||||
*
|
||||
* uint32_t c;
|
||||
* int32_t a = 0x7fffffff;
|
||||
* int32_t b = 2;
|
||||
* assert(!ckd_add(&c, a, b));
|
||||
* assert(c == 0x80000001u);
|
||||
*
|
||||
* Experienced C / C++ users should find this example counter-intuitive
|
||||
* because the expression `0x7fffffff + 2` not only overflows it's also
|
||||
* undefined behavior. However here we see it's specified, and does not
|
||||
* result in an error. That's because C23 checked arithmetic is not the
|
||||
* arithmetic you're used to. The new standard changes the mathematics.
|
||||
*
|
||||
* C23 checked arithmetic is defined as performing the arithmetic using
|
||||
* infinite precision and then checking if the resulting value will fit
|
||||
* in the output type. Our example above did not result in an error due
|
||||
* to `0x80000001` being a legal value for `uint32_t`.
|
||||
*
|
||||
* This implementation will use the GNU compiler builtins, when they're
|
||||
* available, only if you don't use build flags like `-std=c11` because
|
||||
* they define `__STRICT_ANSI__` and GCC extensions aren't really ANSI.
|
||||
* Instead, you'll get a pretty good pure C11 and C++11 implementation.
|
||||
*
|
||||
* @see https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf
|
||||
* @version 1.0 (2024-12-07)
|
||||
*/
|
||||
|
||||
#ifndef STDCKDINT_H_
|
||||
#define STDCKDINT_H_
|
||||
|
||||
#define __STDC_VERSION_STDCKDINT_H__ 202311L
|
||||
|
||||
#if (!defined(__STRICT_ANSI__) && defined(__SIZEOF_INT128__))
|
||||
#define __ckd_have_int128
|
||||
#define __ckd_intmax __int128
|
||||
#elif ((defined(__cplusplus) && __cplusplus >= 201103L) || \
|
||||
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L))
|
||||
#define __ckd_intmax long long
|
||||
#else
|
||||
#define __ckd_intmax long
|
||||
#endif
|
||||
|
||||
typedef signed __ckd_intmax __ckd_intmax_t;
|
||||
typedef unsigned __ckd_intmax __ckd_uintmax_t;
|
||||
|
||||
#ifdef __has_builtin
|
||||
#define __ckd_has_builtin(x) __has_builtin(x)
|
||||
#else
|
||||
#define __ckd_has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
#if (!defined(__STRICT_ANSI__) && \
|
||||
((defined(__GNUC__) && __GNUC__ >= 5 && !defined(__ICC)) || \
|
||||
(__ckd_has_builtin(__builtin_add_overflow) && \
|
||||
__ckd_has_builtin(__builtin_sub_overflow) && \
|
||||
__ckd_has_builtin(__builtin_mul_overflow))))
|
||||
#define ckd_add(res, x, y) __builtin_add_overflow((x), (y), (res))
|
||||
#define ckd_sub(res, x, y) __builtin_sub_overflow((x), (y), (res))
|
||||
#define ckd_mul(res, x, y) __builtin_mul_overflow((x), (y), (res))
|
||||
|
||||
#else
|
||||
|
||||
#define ckd_add(res, a, b) __ckd_expr(add, (res), (a), (b))
|
||||
#define ckd_sub(res, a, b) __ckd_expr(sub, (res), (a), (b))
|
||||
#define ckd_mul(res, a, b) __ckd_expr(mul, (res), (a), (b))
|
||||
|
||||
#if defined(__GNUC__) || defined(__llvm__)
|
||||
#define __ckd_inline \
|
||||
extern __inline __attribute__((__gnu_inline__, \
|
||||
__always_inline__, \
|
||||
__artificial__))
|
||||
#else
|
||||
#define __ckd_inline static inline
|
||||
#endif
|
||||
|
||||
#ifdef __ckd_have_int128
|
||||
#define __ckd_generic_int128(x, y) , signed __int128: x, unsigned __int128: y
|
||||
#else
|
||||
#define __ckd_generic_int128(x, y)
|
||||
#endif
|
||||
|
||||
#define __ckd_sign(T) \
|
||||
((T)1 << (sizeof(T) * 8 - 1))
|
||||
|
||||
#define __ckd_is_signed(x) \
|
||||
_Generic(x, \
|
||||
signed char: 1, \
|
||||
unsigned char: 0, \
|
||||
signed short: 1, \
|
||||
unsigned short: 0, \
|
||||
signed int: 1, \
|
||||
unsigned int: 0, \
|
||||
signed long: 1, \
|
||||
unsigned long: 0, \
|
||||
signed long long: 1, \
|
||||
unsigned long long: 0 \
|
||||
__ckd_generic_int128(1, 0))
|
||||
|
||||
#define __ckd_expr(op, res, a, b) \
|
||||
(_Generic(*res, \
|
||||
signed char: __ckd_##op##_schar, \
|
||||
unsigned char: __ckd_##op##_uchar, \
|
||||
signed short: __ckd_##op##_sshort, \
|
||||
unsigned short: __ckd_##op##_ushort, \
|
||||
signed int: __ckd_##op##_sint, \
|
||||
unsigned int: __ckd_##op##_uint, \
|
||||
signed long: __ckd_##op##_slong, \
|
||||
unsigned long: __ckd_##op##_ulong, \
|
||||
signed long long: __ckd_##op##_slonger, \
|
||||
unsigned long long: __ckd_##op##_ulonger \
|
||||
__ckd_generic_int128( \
|
||||
__ckd_##op##_sint128, \
|
||||
__ckd_##op##_uint128))( \
|
||||
res, a, b, \
|
||||
__ckd_is_signed(a), \
|
||||
__ckd_is_signed(b)))
|
||||
|
||||
#define __ckd_declare_add(S, T) \
|
||||
__ckd_inline char S(void *__res, \
|
||||
__ckd_uintmax_t __x, \
|
||||
__ckd_uintmax_t __y, \
|
||||
char __a_signed, \
|
||||
char __b_signed) { \
|
||||
__ckd_uintmax_t __z = __x + __y; \
|
||||
*(T *)__res = (T)__z; \
|
||||
char __truncated = 0; \
|
||||
if (sizeof(T) < sizeof(__ckd_intmax_t)) { \
|
||||
__truncated = __z != (__ckd_uintmax_t)(T)__z; \
|
||||
} \
|
||||
switch (__ckd_is_signed((T)0) << 2 | \
|
||||
__a_signed << 1 | __b_signed) { \
|
||||
case 0: /* u = u + u */ \
|
||||
return __truncated | (__z < __x); \
|
||||
case 1: /* u = u + s */ \
|
||||
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)((__z ^ __x) & \
|
||||
(__z ^ __y)) < 0); \
|
||||
case 2: /* u = s + u */ \
|
||||
__x ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)((__z ^ __x) & \
|
||||
(__z ^ __y)) < 0); \
|
||||
case 3: /* u = s + s */ \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)(((__z | __x) & __y) | \
|
||||
((__z & __x) & ~__y)) < 0); \
|
||||
case 4: /* s = u + u */ \
|
||||
return __truncated | (__z < __x) | ((__ckd_intmax_t)__z < 0); \
|
||||
case 5: /* s = u + s */ \
|
||||
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | (__x + __y < __y); \
|
||||
case 6: /* s = s + u */ \
|
||||
__x ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | (__x + __y < __x); \
|
||||
case 7: /* s = s + s */ \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)((__z ^ __x) & \
|
||||
(__z ^ __y)) < 0); \
|
||||
default: \
|
||||
for (;;) (void)0; \
|
||||
} \
|
||||
}
|
||||
|
||||
__ckd_declare_add(__ckd_add_schar, signed char)
|
||||
__ckd_declare_add(__ckd_add_uchar, unsigned char)
|
||||
__ckd_declare_add(__ckd_add_sshort, signed short)
|
||||
__ckd_declare_add(__ckd_add_ushort, unsigned short)
|
||||
__ckd_declare_add(__ckd_add_sint, signed int)
|
||||
__ckd_declare_add(__ckd_add_uint, unsigned int)
|
||||
__ckd_declare_add(__ckd_add_slong, signed long)
|
||||
__ckd_declare_add(__ckd_add_ulong, unsigned long)
|
||||
__ckd_declare_add(__ckd_add_slonger, signed long long)
|
||||
__ckd_declare_add(__ckd_add_ulonger, unsigned long long)
|
||||
#ifdef __ckd_have_int128
|
||||
__ckd_declare_add(__ckd_add_sint128, signed __int128)
|
||||
__ckd_declare_add(__ckd_add_uint128, unsigned __int128)
|
||||
#endif
|
||||
|
||||
#define __ckd_declare_sub(S, T) \
|
||||
__ckd_inline char S(void *__res, \
|
||||
__ckd_uintmax_t __x, \
|
||||
__ckd_uintmax_t __y, \
|
||||
char __a_signed, \
|
||||
char __b_signed) { \
|
||||
__ckd_uintmax_t __z = __x - __y; \
|
||||
*(T *)__res = (T)__z; \
|
||||
char __truncated = 0; \
|
||||
if (sizeof(T) < sizeof(__ckd_intmax_t)) { \
|
||||
__truncated = __z != (__ckd_uintmax_t)(T)__z; \
|
||||
} \
|
||||
switch (__ckd_is_signed((T)0) << 2 | \
|
||||
__a_signed << 1 | __b_signed) { \
|
||||
case 0: /* u = u - u */ \
|
||||
return __truncated | (__x < __y); \
|
||||
case 1: /* u = u - s */ \
|
||||
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)((__x ^ __y) & \
|
||||
(__z ^ __x)) < 0); \
|
||||
case 2: /* u = s - u */ \
|
||||
return __truncated | (__y > __x) | ((__ckd_intmax_t)__x < 0); \
|
||||
case 3: /* u = s - s */ \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)(((__z & __x) & __y) | \
|
||||
((__z | __x) & ~__y)) < 0); \
|
||||
case 4: /* s = u - u */ \
|
||||
return __truncated | ((__x < __y) ^ ((__ckd_intmax_t)__z < 0)); \
|
||||
case 5: /* s = u - s */ \
|
||||
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | (__x >= __y); \
|
||||
case 6: /* s = s - u */ \
|
||||
__x ^= __ckd_sign(__ckd_uintmax_t); \
|
||||
return __truncated | (__x < __y); \
|
||||
case 7: /* s = s - s */ \
|
||||
return __truncated | \
|
||||
((__ckd_intmax_t)((__x ^ __y) & \
|
||||
(__z ^ __x)) < 0); \
|
||||
default: \
|
||||
for (;;) (void)0; \
|
||||
} \
|
||||
}
|
||||
|
||||
__ckd_declare_sub(__ckd_sub_schar, signed char)
|
||||
__ckd_declare_sub(__ckd_sub_uchar, unsigned char)
|
||||
__ckd_declare_sub(__ckd_sub_sshort, signed short)
|
||||
__ckd_declare_sub(__ckd_sub_ushort, unsigned short)
|
||||
__ckd_declare_sub(__ckd_sub_sint, signed int)
|
||||
__ckd_declare_sub(__ckd_sub_uint, unsigned int)
|
||||
__ckd_declare_sub(__ckd_sub_slong, signed long)
|
||||
__ckd_declare_sub(__ckd_sub_ulong, unsigned long)
|
||||
__ckd_declare_sub(__ckd_sub_slonger, signed long long)
|
||||
__ckd_declare_sub(__ckd_sub_ulonger, unsigned long long)
|
||||
#ifdef __ckd_have_int128
|
||||
__ckd_declare_sub(__ckd_sub_sint128, signed __int128)
|
||||
__ckd_declare_sub(__ckd_sub_uint128, unsigned __int128)
|
||||
#endif
|
||||
|
||||
#define __ckd_declare_mul(S, T) \
|
||||
__ckd_inline char S(void *__res, \
|
||||
__ckd_uintmax_t __x, \
|
||||
__ckd_uintmax_t __y, \
|
||||
char __a_signed, \
|
||||
char __b_signed) { \
|
||||
switch (__ckd_is_signed((T)0) << 2 | \
|
||||
__a_signed << 1 | __b_signed) { \
|
||||
case 0: { /* u = u * u */ \
|
||||
__ckd_uintmax_t __z = __x * __y; \
|
||||
int __o = __x && __z / __x != __y; \
|
||||
*(T *)__res = (T)__z; \
|
||||
return __o | (sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t)*(T *)__res); \
|
||||
} \
|
||||
case 1: { /* u = u * s */ \
|
||||
__ckd_uintmax_t __z = __x * __y; \
|
||||
int __o = __x && __z / __x != __y; \
|
||||
*(T *)__res = (T)__z; \
|
||||
return (__o | (((__ckd_intmax_t)__y < 0) & !!__x) | \
|
||||
(sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t)*(T *)__res)); \
|
||||
} \
|
||||
case 2: { /* u = s * u */ \
|
||||
__ckd_uintmax_t __z = __x * __y; \
|
||||
int __o = __x && __z / __x != __y; \
|
||||
*(T *)__res = (T)__z; \
|
||||
return (__o | (((__ckd_intmax_t)__x < 0) & !!__y) | \
|
||||
(sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t)*(T *)__res)); \
|
||||
} \
|
||||
case 3: { /* u = s * s */ \
|
||||
int __o = 0; \
|
||||
if ((__ckd_intmax_t)(__x & __y) < 0) { \
|
||||
__x = 0 - __x; \
|
||||
__y = 0 - __y; \
|
||||
} else if ((__ckd_intmax_t)(__x ^ __y) < 0) { \
|
||||
__o = __x && __y; \
|
||||
} \
|
||||
__ckd_uintmax_t __z = __x * __y; \
|
||||
__o |= __x && __z / __x != __y; \
|
||||
*(T *)__res = (T)__z; \
|
||||
return __o | (sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t)*(T *)__res); \
|
||||
} \
|
||||
case 4: { /* s = u * u */ \
|
||||
__ckd_uintmax_t __z = __x * __y; \
|
||||
int __o = __x && __z / __x != __y; \
|
||||
*(T *)__res = (T)__z; \
|
||||
return (__o | ((__ckd_intmax_t)(__z) < 0) | \
|
||||
(sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t)*(T *)__res)); \
|
||||
} \
|
||||
case 5: { /* s = u * s */ \
|
||||
__ckd_uintmax_t __t = 0 - __y; \
|
||||
__t = (__ckd_intmax_t)(__t) < 0 ? __y : __t; \
|
||||
__ckd_uintmax_t __p = __t * __x; \
|
||||
int __o = __t && __p / __t != __x; \
|
||||
int __n = (__ckd_intmax_t)__y < 0; \
|
||||
__ckd_uintmax_t __z = __n ? 0 - __p : __p; \
|
||||
*(T *)__res = (T)__z; \
|
||||
__ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \
|
||||
return (__o | (__p > __m + __n) | \
|
||||
(sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t)*(T *)__res)); \
|
||||
} \
|
||||
case 6: { /* s = s * u */ \
|
||||
__ckd_uintmax_t __t = 0 - __x; \
|
||||
__t = (__ckd_intmax_t)(__t) < 0 ? __x : __t; \
|
||||
__ckd_uintmax_t __p = __t * __y; \
|
||||
int __o = __t && __p / __t != __y; \
|
||||
int __n = (__ckd_intmax_t)__x < 0; \
|
||||
__ckd_uintmax_t __z = __n ? 0 - __p : __p; \
|
||||
*(T *)__res = (T)__z; \
|
||||
__ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \
|
||||
return (__o | (__p > __m + __n) | \
|
||||
(sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t)*(T *)__res)); \
|
||||
} \
|
||||
case 7: { /* s = s * s */ \
|
||||
__ckd_uintmax_t __z = __x * __y; \
|
||||
*(T *)__res = (T)__z; \
|
||||
return (((((__ckd_intmax_t)__y < 0) && \
|
||||
(__x == __ckd_sign(__ckd_uintmax_t))) || \
|
||||
(__y && (((__ckd_intmax_t)__z / \
|
||||
(__ckd_intmax_t)__y) != \
|
||||
(__ckd_intmax_t)__x))) | \
|
||||
(sizeof(T) < sizeof(__z) && \
|
||||
__z != (__ckd_uintmax_t)*(T *)__res)); \
|
||||
} \
|
||||
default: \
|
||||
for (;;) (void)0; \
|
||||
} \
|
||||
}
|
||||
|
||||
__ckd_declare_mul(__ckd_mul_schar, signed char)
|
||||
__ckd_declare_mul(__ckd_mul_uchar, unsigned char)
|
||||
__ckd_declare_mul(__ckd_mul_sshort, signed short)
|
||||
__ckd_declare_mul(__ckd_mul_ushort, unsigned short)
|
||||
__ckd_declare_mul(__ckd_mul_sint, signed int)
|
||||
__ckd_declare_mul(__ckd_mul_uint, unsigned int)
|
||||
__ckd_declare_mul(__ckd_mul_slong, signed long)
|
||||
__ckd_declare_mul(__ckd_mul_ulong, unsigned long)
|
||||
__ckd_declare_mul(__ckd_mul_slonger, signed long long)
|
||||
__ckd_declare_mul(__ckd_mul_ulonger, unsigned long long)
|
||||
#ifdef __ckd_have_int128
|
||||
__ckd_declare_mul(__ckd_mul_sint128, signed __int128)
|
||||
__ckd_declare_mul(__ckd_mul_uint128, unsigned __int128)
|
||||
#endif
|
||||
|
||||
#endif /* GNU */
|
||||
#endif /* STDCKDINT_H_ */
|
||||
@@ -95,6 +95,10 @@ extern "C" {
|
||||
#define MADV_KEEPONFORK 19
|
||||
#define MADV_COLD 20
|
||||
#define MADV_PAGEOUT 21
|
||||
#define MADV_POPULATE_READ 22
|
||||
#define MADV_POPULATE_WRITE 23
|
||||
#define MADV_DONTNEED_LOCKED 24
|
||||
#define MADV_COLLAPSE 25
|
||||
#define MADV_HWPOISON 100
|
||||
#define MADV_SOFT_OFFLINE 101
|
||||
#endif
|
||||
|
||||
+3
-1
@@ -159,7 +159,7 @@ static struct fdpic_dummy_loadmap app_dummy_loadmap;
|
||||
|
||||
struct debug *_dl_debug_addr = &debug;
|
||||
|
||||
extern weak hidden char __ehdr_start[];
|
||||
extern __weak hidden char __ehdr_start[];
|
||||
|
||||
extern hidden int __malloc_replaced;
|
||||
|
||||
@@ -1782,6 +1782,8 @@ void __dls3(size_t *sp, size_t *auxv)
|
||||
libc.secure = ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID]
|
||||
|| aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]);
|
||||
|
||||
__malloc_process_init();
|
||||
|
||||
/* Only trust user/env if kernel says we're not suid/sgid */
|
||||
if (!libc.secure) {
|
||||
env_path = getenv("LD_LIBRARY_PATH");
|
||||
|
||||
Vendored
+1
-1
@@ -77,7 +77,7 @@ typedef Elf32_Phdr Phdr;
|
||||
typedef Elf64_Phdr Phdr;
|
||||
#endif
|
||||
|
||||
extern weak hidden const size_t _DYNAMIC[];
|
||||
extern __weak hidden const size_t _DYNAMIC[];
|
||||
|
||||
static void static_init_tls(size_t *aux)
|
||||
{
|
||||
|
||||
Vendored
+3
-1
@@ -10,7 +10,7 @@
|
||||
static void dummy(void) {}
|
||||
weak_alias(dummy, _init);
|
||||
|
||||
extern weak hidden void (*const __init_array_start)(void), (*const __init_array_end)(void);
|
||||
extern __weak hidden void (*const __init_array_start)(void), (*const __init_array_end)(void);
|
||||
|
||||
static void dummy1(void *p) {}
|
||||
weak_alias(dummy1, __init_ssp);
|
||||
@@ -39,6 +39,8 @@ void __init_libc(char **envp, char *pn)
|
||||
__init_tls(aux);
|
||||
__init_ssp((void *)aux[AT_RANDOM]);
|
||||
|
||||
__malloc_process_init();
|
||||
|
||||
if (aux[AT_UID]==aux[AT_EUID] && aux[AT_GID]==aux[AT_EGID]
|
||||
&& !aux[AT_SECURE]) return;
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ weak_alias(dummy, __funcs_on_exit);
|
||||
weak_alias(dummy, __stdio_exit);
|
||||
weak_alias(dummy, _fini);
|
||||
|
||||
extern weak hidden void (*const __fini_array_start)(void), (*const __fini_array_end)(void);
|
||||
extern __weak hidden void (*const __fini_array_start)(void), (*const __fini_array_end)(void);
|
||||
|
||||
static void libc_exit_fini(void)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifdef __loongarch_soft_float
|
||||
#include "../fenv.c"
|
||||
#endif
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "../../include/features.h"
|
||||
|
||||
#define weak __attribute__((__weak__))
|
||||
#define __weak __attribute__((__weak__))
|
||||
#define hidden __attribute__((__visibility__("hidden")))
|
||||
#define weak_alias(old, new) \
|
||||
extern __typeof(old) new __attribute__((__weak__, __alias__(#old)))
|
||||
|
||||
@@ -15,5 +15,8 @@ hidden void *__libc_malloc_impl(size_t);
|
||||
hidden void *__libc_calloc(size_t, size_t);
|
||||
hidden void *__libc_realloc(void *, size_t);
|
||||
hidden void __libc_free(void *);
|
||||
hidden void __malloc_process_init();
|
||||
hidden void __malloc_thread_init();
|
||||
hidden void __malloc_thread_done();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -32,6 +32,7 @@ struct pthread {
|
||||
#endif
|
||||
|
||||
/* Part 2 -- implementation details, non-ABI. */
|
||||
void *theap;
|
||||
int tid;
|
||||
int errno_val;
|
||||
volatile int detach_state;
|
||||
|
||||
+26
-2
@@ -40,6 +40,24 @@ static int checkver(Verdef *def, int vsym, const char *vername, char *strings)
|
||||
#define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON)
|
||||
#define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK | 1<<STB_GNU_UNIQUE)
|
||||
|
||||
static size_t count_syms_gnu(uint32_t *gh)
|
||||
{
|
||||
size_t nsym, i;
|
||||
uint32_t *buckets = gh + 4 + (gh[2]*sizeof(size_t)/4);
|
||||
uint32_t *hashval;
|
||||
for (i = nsym = 0; i < gh[0]; i++) {
|
||||
if (buckets[i] > nsym)
|
||||
nsym = buckets[i];
|
||||
}
|
||||
if (nsym) {
|
||||
hashval = buckets + gh[0] + (nsym - gh[1]);
|
||||
do nsym++;
|
||||
while (!(*hashval++ & 1));
|
||||
}
|
||||
return nsym;
|
||||
}
|
||||
|
||||
|
||||
void *__vdsosym(const char *vername, const char *name)
|
||||
{
|
||||
size_t i;
|
||||
@@ -60,6 +78,7 @@ void *__vdsosym(const char *vername, const char *name)
|
||||
char *strings = 0;
|
||||
Sym *syms = 0;
|
||||
Elf_Symndx *hashtab = 0;
|
||||
uint32_t *ghashtab = 0;
|
||||
uint16_t *versym = 0;
|
||||
Verdef *verdef = 0;
|
||||
|
||||
@@ -69,15 +88,20 @@ void *__vdsosym(const char *vername, const char *name)
|
||||
case DT_STRTAB: strings = p; break;
|
||||
case DT_SYMTAB: syms = p; break;
|
||||
case DT_HASH: hashtab = p; break;
|
||||
case DT_GNU_HASH: ghashtab = p; break;
|
||||
case DT_VERSYM: versym = p; break;
|
||||
case DT_VERDEF: verdef = p; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strings || !syms || !hashtab) return 0;
|
||||
if (!strings || !syms) return 0;
|
||||
if (!verdef) versym = 0;
|
||||
size_t nsym = 0;
|
||||
|
||||
for (i=0; i<hashtab[1]; i++) {
|
||||
if (hashtab) nsym = hashtab[1];
|
||||
else if (ghashtab) nsym = count_syms_gnu(ghashtab);
|
||||
|
||||
for (i=0; i<nsym; i++) {
|
||||
if (!(1<<(syms[i].st_info&0xf) & OK_TYPES)) continue;
|
||||
if (!(1<<(syms[i].st_info>>4) & OK_BINDS)) continue;
|
||||
if (!syms[i].st_shndx) continue;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#define AUX_CNT 38
|
||||
|
||||
extern weak hidden const size_t _DYNAMIC[];
|
||||
extern __weak hidden const size_t _DYNAMIC[];
|
||||
|
||||
static int static_dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void *data), void *data)
|
||||
{
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@
|
||||
#define ICONV_ERR_ILLEGAL_OPCODE -4
|
||||
#define ICONV_ERR_MEMORY_OVERFLOW -5
|
||||
|
||||
#define ICONV_CHARSET_PATH_PREFIX "/etc/iconv/"
|
||||
#define ICONV_CHARSET_PATH_PREFIX "/share/iconv/"
|
||||
|
||||
static const uint8_t vm_binary_magic[4] = { 'S', 'I', 'C', 'V' };
|
||||
|
||||
|
||||
@@ -116,3 +116,8 @@ static void *default_malloc(size_t n)
|
||||
}
|
||||
|
||||
weak_alias(default_malloc, malloc);
|
||||
|
||||
static void dummy(void) {}
|
||||
weak_alias(dummy, __malloc_process_init);
|
||||
weak_alias(dummy, __malloc_thread_init);
|
||||
weak_alias(dummy, __malloc_thread_done);
|
||||
|
||||
@@ -62,8 +62,8 @@ __attribute__((__visibility__("hidden")))
|
||||
extern int __malloc_lock[1];
|
||||
|
||||
#define LOCK_OBJ_DEF \
|
||||
int __malloc_lock[1]; \
|
||||
void __malloc_atfork(int who) { malloc_atfork(who); }
|
||||
void __malloc_atfork(int who) { malloc_atfork(who); } \
|
||||
int __malloc_lock[1]
|
||||
|
||||
static inline void rdlock()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
void __malloc_process_init()
|
||||
{
|
||||
}
|
||||
|
||||
void __malloc_thread_init()
|
||||
{
|
||||
}
|
||||
|
||||
void __malloc_thread_done()
|
||||
{
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include "malloc_impl.h"
|
||||
|
||||
void *aligned_alloc(size_t align, size_t len)
|
||||
{
|
||||
unsigned char *mem, *new;
|
||||
|
||||
if ((align & -align) != align) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len > SIZE_MAX - align ||
|
||||
(__malloc_replaced && !__aligned_alloc_replaced)) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (align <= SIZE_ALIGN)
|
||||
return malloc(len);
|
||||
|
||||
if (!(mem = malloc(len + align-1)))
|
||||
return 0;
|
||||
|
||||
new = (void *)((uintptr_t)mem + align-1 & -align);
|
||||
if (new == mem) return mem;
|
||||
|
||||
struct chunk *c = MEM_TO_CHUNK(mem);
|
||||
struct chunk *n = MEM_TO_CHUNK(new);
|
||||
|
||||
if (IS_MMAPPED(c)) {
|
||||
/* Apply difference between aligned and original
|
||||
* address to the "extra" field of mmapped chunk. */
|
||||
n->psize = c->psize + (new-mem);
|
||||
n->csize = c->csize - (new-mem);
|
||||
return new;
|
||||
}
|
||||
|
||||
struct chunk *t = NEXT_CHUNK(c);
|
||||
|
||||
/* Split the allocated chunk into two chunks. The aligned part
|
||||
* that will be used has the size in its footer reduced by the
|
||||
* difference between the aligned and original addresses, and
|
||||
* the resulting size copied to its header. A new header and
|
||||
* footer are written for the split-off part to be freed. */
|
||||
n->psize = c->csize = C_INUSE | (new-mem);
|
||||
n->csize = t->psize -= new-mem;
|
||||
|
||||
__bin_chunk(c);
|
||||
return new;
|
||||
}
|
||||
@@ -1,556 +0,0 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include "libc.h"
|
||||
#include "atomic.h"
|
||||
#include "pthread_impl.h"
|
||||
#include "malloc_impl.h"
|
||||
#include "fork_impl.h"
|
||||
|
||||
#define malloc __libc_malloc_impl
|
||||
#define realloc __libc_realloc
|
||||
#define free __libc_free
|
||||
|
||||
#if defined(__GNUC__) && defined(__PIC__)
|
||||
#define inline inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
volatile uint64_t binmap;
|
||||
struct bin bins[64];
|
||||
volatile int split_merge_lock[2];
|
||||
} mal;
|
||||
|
||||
/* Synchronization tools */
|
||||
|
||||
static inline void lock(volatile int *lk)
|
||||
{
|
||||
int need_locks = libc.need_locks;
|
||||
if (need_locks) {
|
||||
while(a_swap(lk, 1)) __wait(lk, lk+1, 1, 1);
|
||||
if (need_locks < 0) libc.need_locks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void unlock(volatile int *lk)
|
||||
{
|
||||
if (lk[0]) {
|
||||
a_store(lk, 0);
|
||||
if (lk[1]) __wake(lk, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void lock_bin(int i)
|
||||
{
|
||||
lock(mal.bins[i].lock);
|
||||
if (!mal.bins[i].head)
|
||||
mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i);
|
||||
}
|
||||
|
||||
static inline void unlock_bin(int i)
|
||||
{
|
||||
unlock(mal.bins[i].lock);
|
||||
}
|
||||
|
||||
static int first_set(uint64_t x)
|
||||
{
|
||||
#if 1
|
||||
return a_ctz_64(x);
|
||||
#else
|
||||
static const char debruijn64[64] = {
|
||||
0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
|
||||
62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
|
||||
63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
|
||||
51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
|
||||
};
|
||||
static const char debruijn32[32] = {
|
||||
0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13,
|
||||
31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14
|
||||
};
|
||||
if (sizeof(long) < 8) {
|
||||
uint32_t y = x;
|
||||
if (!y) {
|
||||
y = x>>32;
|
||||
return 32 + debruijn32[(y&-y)*0x076be629 >> 27];
|
||||
}
|
||||
return debruijn32[(y&-y)*0x076be629 >> 27];
|
||||
}
|
||||
return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58];
|
||||
#endif
|
||||
}
|
||||
|
||||
static const unsigned char bin_tab[60] = {
|
||||
32,33,34,35,36,36,37,37,38,38,39,39,
|
||||
40,40,40,40,41,41,41,41,42,42,42,42,43,43,43,43,
|
||||
44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45,
|
||||
46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47,
|
||||
};
|
||||
|
||||
static int bin_index(size_t x)
|
||||
{
|
||||
x = x / SIZE_ALIGN - 1;
|
||||
if (x <= 32) return x;
|
||||
if (x < 512) return bin_tab[x/8-4];
|
||||
if (x > 0x1c00) return 63;
|
||||
return bin_tab[x/128-4] + 16;
|
||||
}
|
||||
|
||||
static int bin_index_up(size_t x)
|
||||
{
|
||||
x = x / SIZE_ALIGN - 1;
|
||||
if (x <= 32) return x;
|
||||
x--;
|
||||
if (x < 512) return bin_tab[x/8-4] + 1;
|
||||
return bin_tab[x/128-4] + 17;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void __dump_heap(int x)
|
||||
{
|
||||
struct chunk *c;
|
||||
int i;
|
||||
for (c = (void *)mal.heap; CHUNK_SIZE(c); c = NEXT_CHUNK(c))
|
||||
fprintf(stderr, "base %p size %zu (%d) flags %d/%d\n",
|
||||
c, CHUNK_SIZE(c), bin_index(CHUNK_SIZE(c)),
|
||||
c->csize & 15,
|
||||
NEXT_CHUNK(c)->psize & 15);
|
||||
for (i=0; i<64; i++) {
|
||||
if (mal.bins[i].head != BIN_TO_CHUNK(i) && mal.bins[i].head) {
|
||||
fprintf(stderr, "bin %d: %p\n", i, mal.bins[i].head);
|
||||
if (!(mal.binmap & 1ULL<<i))
|
||||
fprintf(stderr, "missing from binmap!\n");
|
||||
} else if (mal.binmap & 1ULL<<i)
|
||||
fprintf(stderr, "binmap wrongly contains %d!\n", i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This function returns true if the interval [old,new]
|
||||
* intersects the 'len'-sized interval below &libc.auxv
|
||||
* (interpreted as the main-thread stack) or below &b
|
||||
* (the current stack). It is used to defend against
|
||||
* buggy brk implementations that can cross the stack. */
|
||||
|
||||
static int traverses_stack_p(uintptr_t old, uintptr_t new)
|
||||
{
|
||||
const uintptr_t len = 8<<20;
|
||||
uintptr_t a, b;
|
||||
|
||||
b = (uintptr_t)libc.auxv;
|
||||
a = b > len ? b-len : 0;
|
||||
if (new>a && old<b) return 1;
|
||||
|
||||
b = (uintptr_t)&b;
|
||||
a = b > len ? b-len : 0;
|
||||
if (new>a && old<b) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Expand the heap in-place if brk can be used, or otherwise via mmap,
|
||||
* using an exponential lower bound on growth by mmap to make
|
||||
* fragmentation asymptotically irrelevant. The size argument is both
|
||||
* an input and an output, since the caller needs to know the size
|
||||
* allocated, which will be larger than requested due to page alignment
|
||||
* and mmap minimum size rules. The caller is responsible for locking
|
||||
* to prevent concurrent calls. */
|
||||
|
||||
static void *__expand_heap(size_t *pn)
|
||||
{
|
||||
static uintptr_t brk;
|
||||
static unsigned mmap_step;
|
||||
size_t n = *pn;
|
||||
|
||||
if (n > SIZE_MAX/2 - PAGE_SIZE) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
n += -n & PAGE_SIZE-1;
|
||||
|
||||
if (!brk) {
|
||||
brk = __syscall(SYS_brk, 0);
|
||||
brk += -brk & PAGE_SIZE-1;
|
||||
}
|
||||
|
||||
if (n < SIZE_MAX-brk && !traverses_stack_p(brk, brk+n)
|
||||
&& __syscall(SYS_brk, brk+n)==brk+n) {
|
||||
*pn = n;
|
||||
brk += n;
|
||||
return (void *)(brk-n);
|
||||
}
|
||||
|
||||
size_t min = (size_t)PAGE_SIZE << mmap_step/2;
|
||||
if (n < min) n = min;
|
||||
void *area = __mmap(0, n, PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
if (area == MAP_FAILED) return 0;
|
||||
*pn = n;
|
||||
mmap_step++;
|
||||
return area;
|
||||
}
|
||||
|
||||
static struct chunk *expand_heap(size_t n)
|
||||
{
|
||||
static void *end;
|
||||
void *p;
|
||||
struct chunk *w;
|
||||
|
||||
/* The argument n already accounts for the caller's chunk
|
||||
* overhead needs, but if the heap can't be extended in-place,
|
||||
* we need room for an extra zero-sized sentinel chunk. */
|
||||
n += SIZE_ALIGN;
|
||||
|
||||
p = __expand_heap(&n);
|
||||
if (!p) return 0;
|
||||
|
||||
/* If not just expanding existing space, we need to make a
|
||||
* new sentinel chunk below the allocated space. */
|
||||
if (p != end) {
|
||||
/* Valid/safe because of the prologue increment. */
|
||||
n -= SIZE_ALIGN;
|
||||
p = (char *)p + SIZE_ALIGN;
|
||||
w = MEM_TO_CHUNK(p);
|
||||
w->psize = 0 | C_INUSE;
|
||||
}
|
||||
|
||||
/* Record new heap end and fill in footer. */
|
||||
end = (char *)p + n;
|
||||
w = MEM_TO_CHUNK(end);
|
||||
w->psize = n | C_INUSE;
|
||||
w->csize = 0 | C_INUSE;
|
||||
|
||||
/* Fill in header, which may be new or may be replacing a
|
||||
* zero-size sentinel header at the old end-of-heap. */
|
||||
w = MEM_TO_CHUNK(p);
|
||||
w->csize = n | C_INUSE;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static int adjust_size(size_t *n)
|
||||
{
|
||||
/* Result of pointer difference must fit in ptrdiff_t. */
|
||||
if (*n-1 > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE) {
|
||||
if (*n) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
} else {
|
||||
*n = SIZE_ALIGN;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unbin(struct chunk *c, int i)
|
||||
{
|
||||
if (c->prev == c->next)
|
||||
a_and_64(&mal.binmap, ~(1ULL<<i));
|
||||
c->prev->next = c->next;
|
||||
c->next->prev = c->prev;
|
||||
c->csize |= C_INUSE;
|
||||
NEXT_CHUNK(c)->psize |= C_INUSE;
|
||||
}
|
||||
|
||||
static void bin_chunk(struct chunk *self, int i)
|
||||
{
|
||||
self->next = BIN_TO_CHUNK(i);
|
||||
self->prev = mal.bins[i].tail;
|
||||
self->next->prev = self;
|
||||
self->prev->next = self;
|
||||
if (self->prev == BIN_TO_CHUNK(i))
|
||||
a_or_64(&mal.binmap, 1ULL<<i);
|
||||
}
|
||||
|
||||
static void trim(struct chunk *self, size_t n)
|
||||
{
|
||||
size_t n1 = CHUNK_SIZE(self);
|
||||
struct chunk *next, *split;
|
||||
|
||||
if (n >= n1 - DONTCARE) return;
|
||||
|
||||
next = NEXT_CHUNK(self);
|
||||
split = (void *)((char *)self + n);
|
||||
|
||||
split->psize = n | C_INUSE;
|
||||
split->csize = n1-n;
|
||||
next->psize = n1-n;
|
||||
self->csize = n | C_INUSE;
|
||||
|
||||
int i = bin_index(n1-n);
|
||||
lock_bin(i);
|
||||
|
||||
bin_chunk(split, i);
|
||||
|
||||
unlock_bin(i);
|
||||
}
|
||||
|
||||
void *malloc(size_t n)
|
||||
{
|
||||
struct chunk *c;
|
||||
int i, j;
|
||||
uint64_t mask;
|
||||
|
||||
if (adjust_size(&n) < 0) return 0;
|
||||
|
||||
if (n > MMAP_THRESHOLD) {
|
||||
size_t len = n + OVERHEAD + PAGE_SIZE - 1 & -PAGE_SIZE;
|
||||
char *base = __mmap(0, len, PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
if (base == (void *)-1) return 0;
|
||||
c = (void *)(base + SIZE_ALIGN - OVERHEAD);
|
||||
c->csize = len - (SIZE_ALIGN - OVERHEAD);
|
||||
c->psize = SIZE_ALIGN - OVERHEAD;
|
||||
return CHUNK_TO_MEM(c);
|
||||
}
|
||||
|
||||
i = bin_index_up(n);
|
||||
if (i<63 && (mal.binmap & (1ULL<<i))) {
|
||||
lock_bin(i);
|
||||
c = mal.bins[i].head;
|
||||
if (c != BIN_TO_CHUNK(i) && CHUNK_SIZE(c)-n <= DONTCARE) {
|
||||
unbin(c, i);
|
||||
unlock_bin(i);
|
||||
return CHUNK_TO_MEM(c);
|
||||
}
|
||||
unlock_bin(i);
|
||||
}
|
||||
lock(mal.split_merge_lock);
|
||||
for (mask = mal.binmap & -(1ULL<<i); mask; mask -= (mask&-mask)) {
|
||||
j = first_set(mask);
|
||||
lock_bin(j);
|
||||
c = mal.bins[j].head;
|
||||
if (c != BIN_TO_CHUNK(j)) {
|
||||
unbin(c, j);
|
||||
unlock_bin(j);
|
||||
break;
|
||||
}
|
||||
unlock_bin(j);
|
||||
}
|
||||
if (!mask) {
|
||||
c = expand_heap(n);
|
||||
if (!c) {
|
||||
unlock(mal.split_merge_lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
trim(c, n);
|
||||
unlock(mal.split_merge_lock);
|
||||
return CHUNK_TO_MEM(c);
|
||||
}
|
||||
|
||||
int __malloc_allzerop(void *p)
|
||||
{
|
||||
return IS_MMAPPED(MEM_TO_CHUNK(p));
|
||||
}
|
||||
|
||||
void *realloc(void *p, size_t n)
|
||||
{
|
||||
struct chunk *self, *next;
|
||||
size_t n0, n1;
|
||||
void *new;
|
||||
|
||||
if (!p) return malloc(n);
|
||||
|
||||
if (adjust_size(&n) < 0) return 0;
|
||||
|
||||
self = MEM_TO_CHUNK(p);
|
||||
n1 = n0 = CHUNK_SIZE(self);
|
||||
|
||||
if (n<=n0 && n0-n<=DONTCARE) return p;
|
||||
|
||||
if (IS_MMAPPED(self)) {
|
||||
size_t extra = self->psize;
|
||||
char *base = (char *)self - extra;
|
||||
size_t oldlen = n0 + extra;
|
||||
size_t newlen = n + extra;
|
||||
/* Crash on realloc of freed chunk */
|
||||
if (extra & 1) a_crash();
|
||||
if (newlen < PAGE_SIZE && (new = malloc(n-OVERHEAD))) {
|
||||
n0 = n;
|
||||
goto copy_free_ret;
|
||||
}
|
||||
newlen = (newlen + PAGE_SIZE-1) & -PAGE_SIZE;
|
||||
if (oldlen == newlen) return p;
|
||||
base = __mremap(base, oldlen, newlen, MREMAP_MAYMOVE);
|
||||
if (base == (void *)-1)
|
||||
goto copy_realloc;
|
||||
self = (void *)(base + extra);
|
||||
self->csize = newlen - extra;
|
||||
return CHUNK_TO_MEM(self);
|
||||
}
|
||||
|
||||
next = NEXT_CHUNK(self);
|
||||
|
||||
/* Crash on corrupted footer (likely from buffer overflow) */
|
||||
if (next->psize != self->csize) a_crash();
|
||||
|
||||
if (n < n0) {
|
||||
int i = bin_index_up(n);
|
||||
int j = bin_index(n0);
|
||||
if (i<j && (mal.binmap & (1ULL << i)))
|
||||
goto copy_realloc;
|
||||
struct chunk *split = (void *)((char *)self + n);
|
||||
self->csize = split->psize = n | C_INUSE;
|
||||
split->csize = next->psize = n0-n | C_INUSE;
|
||||
__bin_chunk(split);
|
||||
return CHUNK_TO_MEM(self);
|
||||
}
|
||||
|
||||
lock(mal.split_merge_lock);
|
||||
|
||||
size_t nsize = next->csize & C_INUSE ? 0 : CHUNK_SIZE(next);
|
||||
if (n0+nsize >= n) {
|
||||
int i = bin_index(nsize);
|
||||
lock_bin(i);
|
||||
if (!(next->csize & C_INUSE)) {
|
||||
unbin(next, i);
|
||||
unlock_bin(i);
|
||||
next = NEXT_CHUNK(next);
|
||||
self->csize = next->psize = n0+nsize | C_INUSE;
|
||||
trim(self, n);
|
||||
unlock(mal.split_merge_lock);
|
||||
return CHUNK_TO_MEM(self);
|
||||
}
|
||||
unlock_bin(i);
|
||||
}
|
||||
unlock(mal.split_merge_lock);
|
||||
|
||||
copy_realloc:
|
||||
/* As a last resort, allocate a new chunk and copy to it. */
|
||||
new = malloc(n-OVERHEAD);
|
||||
if (!new) return 0;
|
||||
copy_free_ret:
|
||||
memcpy(new, p, (n<n0 ? n : n0) - OVERHEAD);
|
||||
free(CHUNK_TO_MEM(self));
|
||||
return new;
|
||||
}
|
||||
|
||||
void __bin_chunk(struct chunk *self)
|
||||
{
|
||||
struct chunk *next = NEXT_CHUNK(self);
|
||||
|
||||
/* Crash on corrupted footer (likely from buffer overflow) */
|
||||
if (next->psize != self->csize) a_crash();
|
||||
|
||||
lock(mal.split_merge_lock);
|
||||
|
||||
size_t osize = CHUNK_SIZE(self), size = osize;
|
||||
|
||||
/* Since we hold split_merge_lock, only transition from free to
|
||||
* in-use can race; in-use to free is impossible */
|
||||
size_t psize = self->psize & C_INUSE ? 0 : CHUNK_PSIZE(self);
|
||||
size_t nsize = next->csize & C_INUSE ? 0 : CHUNK_SIZE(next);
|
||||
|
||||
if (psize) {
|
||||
int i = bin_index(psize);
|
||||
lock_bin(i);
|
||||
if (!(self->psize & C_INUSE)) {
|
||||
struct chunk *prev = PREV_CHUNK(self);
|
||||
unbin(prev, i);
|
||||
self = prev;
|
||||
size += psize;
|
||||
}
|
||||
unlock_bin(i);
|
||||
}
|
||||
if (nsize) {
|
||||
int i = bin_index(nsize);
|
||||
lock_bin(i);
|
||||
if (!(next->csize & C_INUSE)) {
|
||||
unbin(next, i);
|
||||
next = NEXT_CHUNK(next);
|
||||
size += nsize;
|
||||
}
|
||||
unlock_bin(i);
|
||||
}
|
||||
|
||||
int i = bin_index(size);
|
||||
lock_bin(i);
|
||||
|
||||
self->csize = size;
|
||||
next->psize = size;
|
||||
bin_chunk(self, i);
|
||||
unlock(mal.split_merge_lock);
|
||||
|
||||
/* Replace middle of large chunks with fresh zero pages */
|
||||
if (size > RECLAIM && (size^(size-osize)) > size-osize) {
|
||||
uintptr_t a = (uintptr_t)self + SIZE_ALIGN+PAGE_SIZE-1 & -PAGE_SIZE;
|
||||
uintptr_t b = (uintptr_t)next - SIZE_ALIGN & -PAGE_SIZE;
|
||||
int e = errno;
|
||||
#if 1
|
||||
__madvise((void *)a, b-a, MADV_DONTNEED);
|
||||
#else
|
||||
__mmap((void *)a, b-a, PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
|
||||
#endif
|
||||
errno = e;
|
||||
}
|
||||
|
||||
unlock_bin(i);
|
||||
}
|
||||
|
||||
static void unmap_chunk(struct chunk *self)
|
||||
{
|
||||
size_t extra = self->psize;
|
||||
char *base = (char *)self - extra;
|
||||
size_t len = CHUNK_SIZE(self) + extra;
|
||||
/* Crash on double free */
|
||||
if (extra & 1) a_crash();
|
||||
int e = errno;
|
||||
__munmap(base, len);
|
||||
errno = e;
|
||||
}
|
||||
|
||||
void free(void *p)
|
||||
{
|
||||
if (!p) return;
|
||||
|
||||
struct chunk *self = MEM_TO_CHUNK(p);
|
||||
|
||||
if (IS_MMAPPED(self))
|
||||
unmap_chunk(self);
|
||||
else
|
||||
__bin_chunk(self);
|
||||
}
|
||||
|
||||
void __malloc_donate(char *start, char *end)
|
||||
{
|
||||
size_t align_start_up = (SIZE_ALIGN-1) & (-(uintptr_t)start - OVERHEAD);
|
||||
size_t align_end_down = (SIZE_ALIGN-1) & (uintptr_t)end;
|
||||
|
||||
/* Getting past this condition ensures that the padding for alignment
|
||||
* and header overhead will not overflow and will leave a nonzero
|
||||
* multiple of SIZE_ALIGN bytes between start and end. */
|
||||
if (end - start <= OVERHEAD + align_start_up + align_end_down)
|
||||
return;
|
||||
start += align_start_up + OVERHEAD;
|
||||
end -= align_end_down;
|
||||
|
||||
struct chunk *c = MEM_TO_CHUNK(start), *n = MEM_TO_CHUNK(end);
|
||||
c->psize = n->csize = C_INUSE;
|
||||
c->csize = n->psize = C_INUSE | (end-start);
|
||||
__bin_chunk(c);
|
||||
}
|
||||
|
||||
void __malloc_atfork(int who)
|
||||
{
|
||||
if (who<0) {
|
||||
lock(mal.split_merge_lock);
|
||||
for (int i=0; i<64; i++)
|
||||
lock(mal.bins[i].lock);
|
||||
} else if (!who) {
|
||||
for (int i=0; i<64; i++)
|
||||
unlock(mal.bins[i].lock);
|
||||
unlock(mal.split_merge_lock);
|
||||
} else {
|
||||
for (int i=0; i<64; i++)
|
||||
mal.bins[i].lock[0] = mal.bins[i].lock[1] = 0;
|
||||
mal.split_merge_lock[1] = 0;
|
||||
mal.split_merge_lock[0] = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#ifndef MALLOC_IMPL_H
|
||||
#define MALLOC_IMPL_H
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include "dynlink.h"
|
||||
|
||||
struct chunk {
|
||||
size_t psize, csize;
|
||||
struct chunk *next, *prev;
|
||||
};
|
||||
|
||||
struct bin {
|
||||
volatile int lock[2];
|
||||
struct chunk *head;
|
||||
struct chunk *tail;
|
||||
};
|
||||
|
||||
#define SIZE_ALIGN (4*sizeof(size_t))
|
||||
#define SIZE_MASK (-SIZE_ALIGN)
|
||||
#define OVERHEAD (2*sizeof(size_t))
|
||||
#define MMAP_THRESHOLD (0x1c00*SIZE_ALIGN)
|
||||
#define DONTCARE 16
|
||||
#define RECLAIM 163840
|
||||
|
||||
#define CHUNK_SIZE(c) ((c)->csize & -2)
|
||||
#define CHUNK_PSIZE(c) ((c)->psize & -2)
|
||||
#define PREV_CHUNK(c) ((struct chunk *)((char *)(c) - CHUNK_PSIZE(c)))
|
||||
#define NEXT_CHUNK(c) ((struct chunk *)((char *)(c) + CHUNK_SIZE(c)))
|
||||
#define MEM_TO_CHUNK(p) (struct chunk *)((char *)(p) - OVERHEAD)
|
||||
#define CHUNK_TO_MEM(c) (void *)((char *)(c) + OVERHEAD)
|
||||
#define BIN_TO_CHUNK(i) (MEM_TO_CHUNK(&mal.bins[i].head))
|
||||
|
||||
#define C_INUSE ((size_t)1)
|
||||
|
||||
#define IS_MMAPPED(c) !((c)->csize & (C_INUSE))
|
||||
|
||||
hidden void __bin_chunk(struct chunk *);
|
||||
|
||||
#endif
|
||||
@@ -1,9 +0,0 @@
|
||||
#include <malloc.h>
|
||||
#include "malloc_impl.h"
|
||||
|
||||
hidden void *(*const __realloc_dep)(void *, size_t) = realloc;
|
||||
|
||||
size_t malloc_usable_size(void *p)
|
||||
{
|
||||
return p ? CHUNK_SIZE(MEM_TO_CHUNK(p)) - OVERHEAD : 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "rpmalloc.h"
|
||||
#if (defined(__GNUC__) && __GNUC__ >= 9)
|
||||
#pragma GCC diagnostic ignored "-Wattributes" // or we get warnings that nodiscard is ignored on a forward
|
||||
#define hidden_alias(fun) __attribute__((alias(#fun), used, visibility("hidden"), copy(fun)));
|
||||
#define public_alias(fun) __attribute__((alias(#fun), used, visibility("default"), copy(fun)));
|
||||
#else
|
||||
#define hidden_alias(fun) __attribute__((alias(#fun), used, visibility("hidden")));
|
||||
#define public_alias(fun) __attribute__((alias(#fun), used, visibility("default"), copy(fun)));
|
||||
#endif
|
||||
|
||||
void* __libc_malloc_impl(size_t) hidden_alias(rpmalloc)
|
||||
void* __libc_realloc(void*, size_t) hidden_alias(rprealloc)
|
||||
void __libc_free(void*) hidden_alias(rpfree)
|
||||
void *aligned_alloc(size_t align, size_t size) public_alias(rpaligned_alloc)
|
||||
size_t malloc_usable_size(void * p) public_alias(rpmalloc_usable_size)
|
||||
|
||||
hidden void __malloc_atfork(int who) {}
|
||||
hidden void __malloc_donate(char *start, char *end) {}
|
||||
|
||||
hidden void __malloc_process_init() {
|
||||
rpmalloc_set_main_thread();
|
||||
if (rpmalloc_initialize() < 0) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
hidden void __malloc_thread_init() {
|
||||
rpmalloc_thread_initialize();
|
||||
}
|
||||
hidden void __malloc_thread_finalize() {
|
||||
rpmalloc_thread_finalize(1);
|
||||
}
|
||||
|
||||
#include "pthread_impl.h"
|
||||
|
||||
static inline heap_t* get_thread_heap_raw(void) {
|
||||
pthread_t self = __pthread_self();
|
||||
return (heap_t *) self->theap;
|
||||
}
|
||||
|
||||
static inline uintptr_t get_thread_id(void) {
|
||||
return (uintptr_t)__pthread_self()->self;
|
||||
}
|
||||
|
||||
static void set_thread_heap(heap_t* heap) {
|
||||
__pthread_self()->theap = (void *)heap;
|
||||
if (heap) heap->owner_thread = get_thread_id();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,362 @@
|
||||
/* rpmalloc.h - Memory allocator - Public Domain - 2016 Mattias Jansson
|
||||
*
|
||||
* This library provides a cross-platform lock free thread caching malloc implementation in C11.
|
||||
* The latest source code is always available at
|
||||
*
|
||||
* https://github.com/mjansson/rpmalloc
|
||||
*
|
||||
* This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
# define RPMALLOC_EXPORT static
|
||||
# define RPMALLOC_ALLOCATOR
|
||||
# if (defined(__clang_major__) && (__clang_major__ < 4)) || (defined(__GNUC__) && defined(ENABLE_PRELOAD) && ENABLE_PRELOAD)
|
||||
# define RPMALLOC_ATTRIB_MALLOC
|
||||
# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
|
||||
# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size)
|
||||
# else
|
||||
# define RPMALLOC_ATTRIB_MALLOC __attribute__((__malloc__))
|
||||
# define RPMALLOC_ATTRIB_ALLOC_SIZE(size) __attribute__((alloc_size(size)))
|
||||
# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) __attribute__((alloc_size(count, size)))
|
||||
# endif
|
||||
# define RPMALLOC_CDECL
|
||||
#elif defined(_MSC_VER)
|
||||
# define RPMALLOC_EXPORT
|
||||
# define RPMALLOC_ALLOCATOR __declspec(allocator) __declspec(restrict)
|
||||
# define RPMALLOC_ATTRIB_MALLOC
|
||||
# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
|
||||
# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)
|
||||
# define RPMALLOC_CDECL __cdecl
|
||||
#else
|
||||
# define RPMALLOC_EXPORT
|
||||
# define RPMALLOC_ALLOCATOR
|
||||
# define RPMALLOC_ATTRIB_MALLOC
|
||||
# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
|
||||
# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)
|
||||
# define RPMALLOC_CDECL
|
||||
#endif
|
||||
|
||||
//! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce
|
||||
// a very small overhead due to some size calculations not being compile time constants
|
||||
#ifndef RPMALLOC_CONFIGURABLE
|
||||
#define RPMALLOC_CONFIGURABLE 0
|
||||
#endif
|
||||
|
||||
//! Define RPMALLOC_FIRST_CLASS_HEAPS to enable heap based API (rpmalloc_heap_* functions).
|
||||
// Will introduce a very small overhead to track fully allocated spans in heaps
|
||||
#ifndef RPMALLOC_FIRST_CLASS_HEAPS
|
||||
#define RPMALLOC_FIRST_CLASS_HEAPS 0
|
||||
#endif
|
||||
|
||||
//! Flag to rpaligned_realloc to not preserve content in reallocation
|
||||
#define RPMALLOC_NO_PRESERVE 1
|
||||
//! Flag to rpaligned_realloc to fail and return null pointer if grow cannot be done in-place,
|
||||
// in which case the original pointer is still valid (just like a call to realloc which failes to allocate
|
||||
// a new block).
|
||||
#define RPMALLOC_GROW_OR_FAIL 2
|
||||
|
||||
typedef struct rpmalloc_global_statistics_t {
|
||||
//! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
|
||||
size_t mapped;
|
||||
//! Peak amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
|
||||
size_t mapped_peak;
|
||||
//! Current amount of memory in global caches for small and medium sizes (<32KiB)
|
||||
size_t cached;
|
||||
//! Current amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
|
||||
size_t huge_alloc;
|
||||
//! Peak amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
|
||||
size_t huge_alloc_peak;
|
||||
//! Total amount of memory mapped since initialization (only if ENABLE_STATISTICS=1)
|
||||
size_t mapped_total;
|
||||
//! Total amount of memory unmapped since initialization (only if ENABLE_STATISTICS=1)
|
||||
size_t unmapped_total;
|
||||
} rpmalloc_global_statistics_t;
|
||||
|
||||
typedef struct rpmalloc_thread_statistics_t {
|
||||
//! Current number of bytes available in thread size class caches for small and medium sizes (<32KiB)
|
||||
size_t sizecache;
|
||||
//! Current number of bytes available in thread span caches for small and medium sizes (<32KiB)
|
||||
size_t spancache;
|
||||
//! Total number of bytes transitioned from thread cache to global cache (only if ENABLE_STATISTICS=1)
|
||||
size_t thread_to_global;
|
||||
//! Total number of bytes transitioned from global cache to thread cache (only if ENABLE_STATISTICS=1)
|
||||
size_t global_to_thread;
|
||||
//! Per span count statistics (only if ENABLE_STATISTICS=1)
|
||||
struct {
|
||||
//! Currently used number of spans
|
||||
size_t current;
|
||||
//! High water mark of spans used
|
||||
size_t peak;
|
||||
//! Number of spans transitioned to global cache
|
||||
size_t to_global;
|
||||
//! Number of spans transitioned from global cache
|
||||
size_t from_global;
|
||||
//! Number of spans transitioned to thread cache
|
||||
size_t to_cache;
|
||||
//! Number of spans transitioned from thread cache
|
||||
size_t from_cache;
|
||||
//! Number of spans transitioned to reserved state
|
||||
size_t to_reserved;
|
||||
//! Number of spans transitioned from reserved state
|
||||
size_t from_reserved;
|
||||
//! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
|
||||
size_t map_calls;
|
||||
} span_use[64];
|
||||
//! Per size class statistics (only if ENABLE_STATISTICS=1)
|
||||
struct {
|
||||
//! Current number of allocations
|
||||
size_t alloc_current;
|
||||
//! Peak number of allocations
|
||||
size_t alloc_peak;
|
||||
//! Total number of allocations
|
||||
size_t alloc_total;
|
||||
//! Total number of frees
|
||||
size_t free_total;
|
||||
//! Number of spans transitioned to cache
|
||||
size_t spans_to_cache;
|
||||
//! Number of spans transitioned from cache
|
||||
size_t spans_from_cache;
|
||||
//! Number of spans transitioned from reserved state
|
||||
size_t spans_from_reserved;
|
||||
//! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
|
||||
size_t map_calls;
|
||||
} size_use[128];
|
||||
} rpmalloc_thread_statistics_t;
|
||||
|
||||
typedef struct rpmalloc_config_t {
|
||||
//! Map memory pages for the given number of bytes. The returned address MUST be
|
||||
// aligned to the rpmalloc span size, which will always be a power of two.
|
||||
// Optionally the function can store an alignment offset in the offset variable
|
||||
// in case it performs alignment and the returned pointer is offset from the
|
||||
// actual start of the memory region due to this alignment. The alignment offset
|
||||
// will be passed to the memory unmap function. The alignment offset MUST NOT be
|
||||
// larger than 65535 (storable in an uint16_t), if it is you must use natural
|
||||
// alignment to shift it into 16 bits. If you set a memory_map function, you
|
||||
// must also set a memory_unmap function or else the default implementation will
|
||||
// be used for both. This function must be thread safe, it can be called by
|
||||
// multiple threads simultaneously.
|
||||
void* (*memory_map)(size_t size, size_t* offset);
|
||||
//! Unmap the memory pages starting at address and spanning the given number of bytes.
|
||||
// If release is set to non-zero, the unmap is for an entire span range as returned by
|
||||
// a previous call to memory_map and that the entire range should be released. The
|
||||
// release argument holds the size of the entire span range. If release is set to 0,
|
||||
// the unmap is a partial decommit of a subset of the mapped memory range.
|
||||
// If you set a memory_unmap function, you must also set a memory_map function or
|
||||
// else the default implementation will be used for both. This function must be thread
|
||||
// safe, it can be called by multiple threads simultaneously.
|
||||
void (*memory_unmap)(void* address, size_t size, size_t offset, size_t release);
|
||||
//! Called when an assert fails, if asserts are enabled. Will use the standard assert()
|
||||
// if this is not set.
|
||||
void (*error_callback)(const char* message);
|
||||
//! Called when a call to map memory pages fails (out of memory). If this callback is
|
||||
// not set or returns zero the library will return a null pointer in the allocation
|
||||
// call. If this callback returns non-zero the map call will be retried. The argument
|
||||
// passed is the number of bytes that was requested in the map call. Only used if
|
||||
// the default system memory map function is used (memory_map callback is not set).
|
||||
int (*map_fail_callback)(size_t size);
|
||||
//! Size of memory pages. The page size MUST be a power of two. All memory mapping
|
||||
// requests to memory_map will be made with size set to a multiple of the page size.
|
||||
// Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used.
|
||||
size_t page_size;
|
||||
//! Size of a span of memory blocks. MUST be a power of two, and in [4096,262144]
|
||||
// range (unless 0 - set to 0 to use the default span size). Used if RPMALLOC_CONFIGURABLE
|
||||
// is defined to 1.
|
||||
size_t span_size;
|
||||
//! Number of spans to map at each request to map new virtual memory blocks. This can
|
||||
// be used to minimize the system call overhead at the cost of virtual memory address
|
||||
// space. The extra mapped pages will not be written until actually used, so physical
|
||||
// committed memory should not be affected in the default implementation. Will be
|
||||
// aligned to a multiple of spans that match memory page size in case of huge pages.
|
||||
size_t span_map_count;
|
||||
//! Enable use of large/huge pages. If this flag is set to non-zero and page size is
|
||||
// zero, the allocator will try to enable huge pages and auto detect the configuration.
|
||||
// If this is set to non-zero and page_size is also non-zero, the allocator will
|
||||
// assume huge pages have been configured and enabled prior to initializing the
|
||||
// allocator.
|
||||
// For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support
|
||||
// For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
|
||||
int enable_huge_pages;
|
||||
int unused;
|
||||
} rpmalloc_config_t;
|
||||
|
||||
//! Initialize allocator with default configuration
|
||||
RPMALLOC_EXPORT int
|
||||
rpmalloc_initialize(void);
|
||||
|
||||
//! Initialize allocator with given configuration
|
||||
RPMALLOC_EXPORT int
|
||||
rpmalloc_initialize_config(const rpmalloc_config_t* config);
|
||||
|
||||
//! Get allocator configuration
|
||||
RPMALLOC_EXPORT const rpmalloc_config_t*
|
||||
rpmalloc_config(void);
|
||||
|
||||
//! Finalize allocator
|
||||
RPMALLOC_EXPORT void
|
||||
rpmalloc_finalize(void);
|
||||
|
||||
//! Initialize allocator for calling thread
|
||||
RPMALLOC_EXPORT void
|
||||
rpmalloc_thread_initialize(void);
|
||||
|
||||
//! Finalize allocator for calling thread
|
||||
RPMALLOC_EXPORT void
|
||||
rpmalloc_thread_finalize(int release_caches);
|
||||
|
||||
//! Perform deferred deallocations pending for the calling thread heap
|
||||
RPMALLOC_EXPORT void
|
||||
rpmalloc_thread_collect(void);
|
||||
|
||||
//! Query if allocator is initialized for calling thread
|
||||
RPMALLOC_EXPORT int
|
||||
rpmalloc_is_thread_initialized(void);
|
||||
|
||||
//! Get per-thread statistics
|
||||
RPMALLOC_EXPORT void
|
||||
rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats);
|
||||
|
||||
//! Get global statistics
|
||||
RPMALLOC_EXPORT void
|
||||
rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats);
|
||||
|
||||
//! Dump all statistics in human readable format to file (should be a FILE*)
|
||||
RPMALLOC_EXPORT void
|
||||
rpmalloc_dump_statistics(void* file);
|
||||
|
||||
//! Allocate a memory block of at least the given size
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rpmalloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1);
|
||||
|
||||
//! Free the given memory block
|
||||
RPMALLOC_EXPORT void
|
||||
rpfree(void* ptr);
|
||||
|
||||
//! Allocate a memory block of at least the given size and zero initialize it
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rpcalloc(size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2);
|
||||
|
||||
//! Reallocate the given block to at least the given size
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rprealloc(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
|
||||
|
||||
//! Reallocate the given block to at least the given size and alignment,
|
||||
// with optional control flags (see RPMALLOC_NO_PRESERVE).
|
||||
// Alignment must be a power of two and a multiple of sizeof(void*),
|
||||
// and should ideally be less than memory page size. A caveat of rpmalloc
|
||||
// internals is that this must also be strictly less than the span size (default 64KiB)
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
|
||||
|
||||
//! Allocate a memory block of at least the given size and alignment.
|
||||
// Alignment must be a power of two and a multiple of sizeof(void*),
|
||||
// and should ideally be less than memory page size. A caveat of rpmalloc
|
||||
// internals is that this must also be strictly less than the span size (default 64KiB)
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
|
||||
|
||||
//! Allocate a memory block of at least the given size and alignment, and zero initialize it.
|
||||
// Alignment must be a power of two and a multiple of sizeof(void*),
|
||||
// and should ideally be less than memory page size. A caveat of rpmalloc
|
||||
// internals is that this must also be strictly less than the span size (default 64KiB)
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
|
||||
|
||||
//! Allocate a memory block of at least the given size and alignment.
|
||||
// Alignment must be a power of two and a multiple of sizeof(void*),
|
||||
// and should ideally be less than memory page size. A caveat of rpmalloc
|
||||
// internals is that this must also be strictly less than the span size (default 64KiB)
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
|
||||
|
||||
//! Allocate a memory block of at least the given size and alignment.
|
||||
// Alignment must be a power of two and a multiple of sizeof(void*),
|
||||
// and should ideally be less than memory page size. A caveat of rpmalloc
|
||||
// internals is that this must also be strictly less than the span size (default 64KiB)
|
||||
RPMALLOC_EXPORT int
|
||||
rpposix_memalign(void** memptr, size_t alignment, size_t size);
|
||||
|
||||
//! Query the usable size of the given memory block (from given pointer to the end of block)
|
||||
RPMALLOC_EXPORT size_t
|
||||
rpmalloc_usable_size(void* ptr);
|
||||
|
||||
#if RPMALLOC_FIRST_CLASS_HEAPS
|
||||
|
||||
//! Heap type
|
||||
typedef struct heap_t rpmalloc_heap_t;
|
||||
|
||||
//! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap
|
||||
// if none available. Heap API is implemented with the strict assumption that only one single
|
||||
// thread will call heap functions for a given heap at any given time, no functions are thread safe.
|
||||
RPMALLOC_EXPORT rpmalloc_heap_t*
|
||||
rpmalloc_heap_acquire(void);
|
||||
|
||||
//! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap).
|
||||
// Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer.
|
||||
RPMALLOC_EXPORT void
|
||||
rpmalloc_heap_release(rpmalloc_heap_t* heap);
|
||||
|
||||
//! Allocate a memory block of at least the given size using the given heap.
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
|
||||
|
||||
//! Allocate a memory block of at least the given size using the given heap. The returned
|
||||
// block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*),
|
||||
// and should ideally be less than memory page size. A caveat of rpmalloc
|
||||
// internals is that this must also be strictly less than the span size (default 64KiB).
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
|
||||
|
||||
//! Allocate a memory block of at least the given size using the given heap and zero initialize it.
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
|
||||
|
||||
//! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned
|
||||
// block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*),
|
||||
// and should ideally be less than memory page size. A caveat of rpmalloc
|
||||
// internals is that this must also be strictly less than the span size (default 64KiB).
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
|
||||
|
||||
//! Reallocate the given block to at least the given size. The memory block MUST be allocated
|
||||
// by the same heap given to this function.
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
|
||||
|
||||
//! Reallocate the given block to at least the given size. The memory block MUST be allocated
|
||||
// by the same heap given to this function. The returned block will have the requested alignment.
|
||||
// Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be
|
||||
// less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than
|
||||
// the span size (default 64KiB).
|
||||
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
|
||||
rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4);
|
||||
|
||||
//! Free the given memory block from the given heap. The memory block MUST be allocated
|
||||
// by the same heap given to this function.
|
||||
RPMALLOC_EXPORT void
|
||||
rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr);
|
||||
|
||||
//! Free all memory allocated by the heap
|
||||
RPMALLOC_EXPORT void
|
||||
rpmalloc_heap_free_all(rpmalloc_heap_t* heap);
|
||||
|
||||
//! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap
|
||||
// for a single thread, a heap can never be shared between multiple threads. The previous
|
||||
// current heap for the calling thread is released to be reused by other threads.
|
||||
RPMALLOC_EXPORT void
|
||||
rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -13,8 +13,8 @@
|
||||
|
||||
/* getifaddrs() reports hardware addresses with PF_PACKET that implies
|
||||
* struct sockaddr_ll. But e.g. Infiniband socket address length is
|
||||
* longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct
|
||||
* to extend ssl_addr - callers should be able to still use it. */
|
||||
* longer than sockaddr_ll.sll_addr[8] can hold. Use this hack struct
|
||||
* to extend sll_addr - callers should be able to still use it. */
|
||||
struct sockaddr_ll_hack {
|
||||
unsigned short sll_family, sll_protocol;
|
||||
int sll_ifindex;
|
||||
|
||||
@@ -47,7 +47,7 @@ static void reverse_hosts(char *buf, const unsigned char *a, unsigned scopeid, i
|
||||
char line[512], *p, *z;
|
||||
unsigned char _buf[1032], atmp[16];
|
||||
struct address iplit;
|
||||
FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf);
|
||||
FILE _f, *f = __fopen_rb_ca("/var/config/network/hosts", &_f, _buf, sizeof _buf);
|
||||
if (!f) return;
|
||||
if (family == AF_INET) {
|
||||
memcpy(atmp+12, a, 4);
|
||||
@@ -71,7 +71,7 @@ static void reverse_hosts(char *buf, const unsigned char *a, unsigned scopeid, i
|
||||
|
||||
if (memcmp(a, iplit.addr, 16) || iplit.scopeid != scopeid)
|
||||
continue;
|
||||
|
||||
|
||||
for (; *p && isspace(*p); p++);
|
||||
for (z=p; *z && !isspace(*z); z++);
|
||||
*z = 0;
|
||||
@@ -116,7 +116,7 @@ static int dns_parse_callback(void *c, int rr, const void *data, int len, const
|
||||
data, c, 256) <= 0)
|
||||
*(char *)c = 0;
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl,
|
||||
|
||||
@@ -52,7 +52,7 @@ static int name_from_hosts(struct address buf[static MAXADDRS], char canon[stati
|
||||
size_t l = strlen(name);
|
||||
int cnt = 0, badfam = 0, have_canon = 0;
|
||||
unsigned char _buf[1032];
|
||||
FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf);
|
||||
FILE _f, *f = __fopen_rb_ca("/var/config/network/hosts", &_f, _buf, sizeof _buf);
|
||||
if (!f) switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
|
||||
@@ -18,7 +18,7 @@ int __get_resolv_conf(struct resolvconf *conf, char *search, size_t search_sz)
|
||||
conf->attempts = 2;
|
||||
if (search) *search = 0;
|
||||
|
||||
f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
|
||||
f = __fopen_rb_ca("/var/config/network/resolv.conf", &_f, _buf, sizeof _buf);
|
||||
if (!f) switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
|
||||
@@ -0,0 +1,404 @@
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "spp.h"
|
||||
#include "json.h"
|
||||
|
||||
#ifndef _ACCOUNT_CLIENT
|
||||
#define _ACCOUNT_CLIENT
|
||||
|
||||
#define REQ2(condition, err) if (!(condition)) { errno = err; return -1; }
|
||||
#define REQ(condition) REQ2(condition, EPERM)
|
||||
#define REQP2(condition, err) if (!(condition)) { errno = err; return NULL; }
|
||||
#define REQP(condition) REQP2(condition, EPERM)
|
||||
#define ITEROBJ(obj, it) for (struct json_object_element_s *it = obj->start; it != NULL; it = it->next)
|
||||
#define DECLPOOL(pool, buf, size) struct account_memory_pool pool = { .ptr = buf, .len = size, .cursor = 0 }
|
||||
|
||||
#ifdef __linux__
|
||||
static inline int account_connect() {
|
||||
return spp_connect_linux("verified:org.semilabs.os/accountd");
|
||||
}
|
||||
#else
|
||||
static inline int account_connect() {
|
||||
return spp_connect_unix("/var/run/accountd.sock");
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
struct account_memory_pool {
|
||||
void *ptr;
|
||||
size_t cursor;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static inline void *account_allocate_pool(struct account_memory_pool *pool, size_t size) {
|
||||
if (!pool || !pool->ptr || size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (pool->cursor + size > pool->len) {
|
||||
return NULL;
|
||||
}
|
||||
void *result = (char *)pool->ptr + pool->cursor;
|
||||
pool->cursor += size;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int account_recordpw(
|
||||
struct json_value_s *root,
|
||||
struct passwd *passwd,
|
||||
struct account_memory_pool *pool
|
||||
) {
|
||||
passwd->pw_passwd = account_allocate_pool(pool, 2);
|
||||
REQ2(passwd->pw_passwd, ERANGE);
|
||||
strcpy(passwd->pw_passwd, "x");
|
||||
|
||||
passwd->pw_gecos = account_allocate_pool(pool, 1);
|
||||
REQ2(passwd->pw_gecos, ERANGE);
|
||||
strcpy(passwd->pw_gecos, "");
|
||||
|
||||
struct json_object_s *object = json_value_as_object(root);
|
||||
REQ(object);
|
||||
ITEROBJ(object, it) {
|
||||
const char *name = it->name->string;
|
||||
struct json_value_s *value = it->value;
|
||||
|
||||
if (strcmp(name, "username") == 0) {
|
||||
struct json_string_s *username = json_value_as_string(value);
|
||||
REQ(username);
|
||||
passwd->pw_name = account_allocate_pool(pool, username->string_size + 1);
|
||||
REQ2(passwd->pw_name, ERANGE);
|
||||
strcpy(passwd->pw_name, username->string);
|
||||
continue;
|
||||
}
|
||||
if (strcmp(name, "home_directory") == 0) {
|
||||
struct json_string_s *homedir = json_value_as_string(value);
|
||||
REQ(homedir);
|
||||
passwd->pw_dir = account_allocate_pool(pool, homedir->string_size + 1);
|
||||
REQ2(passwd->pw_dir, ERANGE);
|
||||
strcpy(passwd->pw_dir, homedir->string);
|
||||
continue;
|
||||
}
|
||||
if (strcmp(name, "defaults") == 0) {
|
||||
struct json_object_s *defaults = json_value_as_object(value);
|
||||
REQ(defaults);
|
||||
ITEROBJ(defaults, def) {
|
||||
name = def->name->string;
|
||||
value = def->value;
|
||||
if (strcmp(name, "CliLoginShell") == 0) {
|
||||
struct json_string_s *shell = json_value_as_string(value);
|
||||
REQ(shell);
|
||||
passwd->pw_shell = account_allocate_pool(pool, shell->string_size + 1);
|
||||
REQ2(passwd->pw_shell, ERANGE);
|
||||
strcpy(passwd->pw_shell, shell->string);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp(name, "host_uid") == 0) {
|
||||
struct json_number_s *uid = json_value_as_number(value);
|
||||
REQ(uid);
|
||||
passwd->pw_uid = atoi(uid->number);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int account_recordgr(
|
||||
struct json_value_s *root,
|
||||
struct group *group,
|
||||
struct account_memory_pool *pool
|
||||
) {
|
||||
group->gr_passwd = account_allocate_pool(pool, 2);
|
||||
REQ2(group->gr_passwd, ERANGE);
|
||||
strcpy(group->gr_passwd, "x");
|
||||
|
||||
struct json_object_s *object = json_value_as_object(root);
|
||||
REQ(object);
|
||||
ITEROBJ(object, it) {
|
||||
const char *name = it->name->string;
|
||||
struct json_value_s *value = it->value;
|
||||
|
||||
if (strcmp(name, "groupname") == 0) {
|
||||
struct json_string_s *groupname = json_value_as_string(value);
|
||||
REQ(groupname);
|
||||
group->gr_name = account_allocate_pool(pool, groupname->string_size + 1);
|
||||
REQ2(group->gr_name, ERANGE);
|
||||
strcpy(group->gr_name, groupname->string);
|
||||
continue;
|
||||
}
|
||||
if (strcmp(name, "host_gid") == 0) {
|
||||
struct json_number_s *gid = json_value_as_number(value);
|
||||
REQ(gid);
|
||||
group->gr_gid = atoi(gid->number);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*pwgr_parser_t)(struct json_value_s*, void*, struct account_memory_pool*);
|
||||
|
||||
static inline int account_getpwgrkey(
|
||||
int fd,
|
||||
const char *method,
|
||||
const char *key,
|
||||
const char *valueborder,
|
||||
const char *name,
|
||||
pwgr_parser_t parser,
|
||||
void *pwgr,
|
||||
struct account_memory_pool *pool
|
||||
) {
|
||||
int status;
|
||||
|
||||
const char *request_template = "{\"method\": \"%s\", \"params\": {\"%s\": %s%s%s}}";
|
||||
int request_need = snprintf(NULL, 0, request_template, method, key, valueborder, name, valueborder);
|
||||
REQ(request_need > 0);
|
||||
char *request_json = malloc(request_need + 1);
|
||||
REQ2(request_json, ENOMEM);
|
||||
snprintf(request_json, request_need + 1, request_template, method, key, valueborder, name, valueborder);
|
||||
status = spp_send(fd, request_json);
|
||||
free(request_json);
|
||||
REQ(status == 0);
|
||||
|
||||
const char *reply_str = spp_recv(fd);
|
||||
REQ(reply_str);
|
||||
|
||||
struct json_value_s *reply = json_parse(reply_str, strlen(reply_str));
|
||||
spp_free((void*)reply_str);
|
||||
REQ(reply);
|
||||
struct json_object_s *reply_object = json_value_as_object(reply);
|
||||
if (!reply_object) goto format_error;
|
||||
ITEROBJ(reply_object, it) {
|
||||
if (strcmp(it->name->string, "success") == 0) {
|
||||
if (json_value_is_false(it->value)) goto not_found;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(it->name->string, "value") == 0) {
|
||||
status = parser(it->value, pwgr, pool);
|
||||
if (status != 0) goto not_found;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
free(reply);
|
||||
return 0;
|
||||
|
||||
format_error:
|
||||
errno = EPERM;
|
||||
not_found:
|
||||
free(reply);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline char *account_list_uuid_next(
|
||||
int fd,
|
||||
const char *method,
|
||||
unsigned int no
|
||||
) {
|
||||
int status;
|
||||
|
||||
const char *request_template = "{\"method\": \"%s\", \"params\": {\"start\": %u, \"len\": 1}}";
|
||||
int request_need = snprintf(NULL, 0, request_template, method, no);
|
||||
REQP(request_need > 0);
|
||||
char *request_json = malloc(request_need + 1);
|
||||
REQP2(request_json, ENOMEM);
|
||||
snprintf(request_json, request_need + 1, request_template, method, no);
|
||||
status = spp_send(fd, request_json);
|
||||
free(request_json);
|
||||
REQP(status == 0);
|
||||
|
||||
const char *reply_str = spp_recv(fd);
|
||||
REQP(reply_str);
|
||||
|
||||
struct json_value_s *reply = json_parse(reply_str, strlen(reply_str));
|
||||
spp_free((void*)reply_str);
|
||||
REQP(reply);
|
||||
struct json_object_s *reply_object = json_value_as_object(reply);
|
||||
if (!reply_object) goto format_error;
|
||||
ITEROBJ(reply_object, it) {
|
||||
if (strcmp(it->name->string, "success") == 0) {
|
||||
if (json_value_is_false(it->value)) goto not_found;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(it->name->string, "value") == 0) {
|
||||
struct json_array_s *list = json_value_as_array(it->value);
|
||||
if (!list) goto not_found;
|
||||
struct json_array_element_s *first = list->start;
|
||||
if (!first) goto not_found;
|
||||
struct json_string_s *item = json_value_as_string(first->value);
|
||||
if (!item) goto format_error;
|
||||
return strdup(item->string);
|
||||
}
|
||||
}
|
||||
|
||||
free(reply);
|
||||
return NULL;
|
||||
|
||||
format_error:
|
||||
errno = EPERM;
|
||||
not_found:
|
||||
free(reply);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int account_getpwuid(
|
||||
int fd,
|
||||
uid_t uid,
|
||||
struct passwd *passwd,
|
||||
struct account_memory_pool *pool
|
||||
) {
|
||||
char uid_str[32];
|
||||
int len = snprintf(uid_str, sizeof(uid_str), "%u", (unsigned int)uid);
|
||||
REQ(len > 0 && (size_t)len < sizeof(uid_str));
|
||||
|
||||
return account_getpwgrkey(
|
||||
fd,
|
||||
"GetUserInfo",
|
||||
"host_uid",
|
||||
"",
|
||||
uid_str,
|
||||
(pwgr_parser_t)account_recordpw,
|
||||
passwd,
|
||||
pool
|
||||
);
|
||||
}
|
||||
|
||||
static inline int account_getpwnam(
|
||||
int fd,
|
||||
const char *name,
|
||||
struct passwd *passwd,
|
||||
struct account_memory_pool *pool
|
||||
) {
|
||||
return account_getpwgrkey(
|
||||
fd,
|
||||
"GetUserInfo",
|
||||
"username",
|
||||
"\"",
|
||||
name,
|
||||
(pwgr_parser_t)account_recordpw,
|
||||
passwd,
|
||||
pool
|
||||
);
|
||||
}
|
||||
|
||||
static inline int account_getpwuuid(
|
||||
int fd,
|
||||
const char *uuid,
|
||||
struct passwd *passwd,
|
||||
struct account_memory_pool *pool
|
||||
) {
|
||||
return account_getpwgrkey(
|
||||
fd,
|
||||
"GetUserInfo",
|
||||
"uuid",
|
||||
"\"",
|
||||
uuid,
|
||||
(pwgr_parser_t)account_recordpw,
|
||||
passwd,
|
||||
pool
|
||||
);
|
||||
}
|
||||
|
||||
static inline int account_getgrgid(
|
||||
int fd,
|
||||
gid_t gid,
|
||||
struct group *group,
|
||||
struct account_memory_pool *pool
|
||||
) {
|
||||
char gid_str[32];
|
||||
int len = snprintf(gid_str, sizeof(gid_str), "%u", (unsigned int)gid);
|
||||
REQ(len > 0 && (size_t)len < sizeof(gid_str));
|
||||
|
||||
return account_getpwgrkey(
|
||||
fd,
|
||||
"GetGroupInfo",
|
||||
"host_gid",
|
||||
"",
|
||||
gid_str,
|
||||
(pwgr_parser_t)account_recordgr,
|
||||
group,
|
||||
pool
|
||||
);
|
||||
}
|
||||
|
||||
static inline int account_getgrnam(
|
||||
int fd,
|
||||
const char *name,
|
||||
struct group *group,
|
||||
struct account_memory_pool *pool
|
||||
) {
|
||||
return account_getpwgrkey(
|
||||
fd,
|
||||
"GetGroupInfo",
|
||||
"groupname",
|
||||
"\"",
|
||||
name,
|
||||
(pwgr_parser_t)account_recordgr,
|
||||
group,
|
||||
pool
|
||||
);
|
||||
}
|
||||
|
||||
static inline int account_getgruuid(
|
||||
int fd,
|
||||
const char *uuid,
|
||||
struct group *group,
|
||||
struct account_memory_pool *pool
|
||||
) {
|
||||
return account_getpwgrkey(
|
||||
fd,
|
||||
"GetGroupInfo",
|
||||
"uuid",
|
||||
"\"",
|
||||
uuid,
|
||||
(pwgr_parser_t)account_recordgr,
|
||||
group,
|
||||
pool
|
||||
);
|
||||
}
|
||||
|
||||
static inline int account_getpwent(
|
||||
int fd,
|
||||
unsigned int *no,
|
||||
struct passwd *passwd,
|
||||
struct account_memory_pool *pool
|
||||
) {
|
||||
int status;
|
||||
|
||||
char *next_uuid = account_list_uuid_next(fd, "ListUser", *no);
|
||||
REQ2(next_uuid, errno);
|
||||
status = account_getpwuuid(fd, next_uuid, passwd, pool);
|
||||
free(next_uuid);
|
||||
REQ(status == 0);
|
||||
*no += 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int account_getgrent(
|
||||
int fd,
|
||||
unsigned int *no,
|
||||
struct group *group,
|
||||
struct account_memory_pool *pool
|
||||
) {
|
||||
int status;
|
||||
|
||||
char *next_uuid = account_list_uuid_next(fd, "ListGroup", *no);
|
||||
REQ2(next_uuid, errno);
|
||||
status = account_getgruuid(fd, next_uuid, group, pool);
|
||||
free(next_uuid);
|
||||
REQ(status == 0);
|
||||
*no += 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _ACCOUNT_CLIENT */
|
||||
+11
-1
@@ -71,6 +71,10 @@ int __getgr_a(const char *name, gid_t gid, struct group *gr, char **buf, size_t
|
||||
goto cleanup_f;
|
||||
}
|
||||
|
||||
if (groupbuf[GRMEMCNT] > (size_t)(INT32_MAX-1)) {
|
||||
rv = ENOMEM;
|
||||
goto cleanup_f;
|
||||
}
|
||||
if (groupbuf[GRNAMELEN] > SIZE_MAX - groupbuf[GRPASSWDLEN]) {
|
||||
rv = ENOMEM;
|
||||
goto cleanup_f;
|
||||
@@ -127,7 +131,13 @@ int __getgr_a(const char *name, gid_t gid, struct group *gr, char **buf, size_t
|
||||
if (groupbuf[GRMEMCNT]) {
|
||||
mem[0][0] = *buf + groupbuf[GRNAMELEN] + groupbuf[GRPASSWDLEN];
|
||||
for (ptr = mem[0][0], i = 0; ptr != mem[0][0]+grlist_len; ptr++)
|
||||
if (!*ptr) mem[0][++i] = ptr+1;
|
||||
if (!*ptr)
|
||||
if (i<groupbuf[GRMEMCNT]) {
|
||||
mem[0][++i] = ptr+1;
|
||||
} else {
|
||||
rv = EIO;
|
||||
goto cleanup_f;
|
||||
}
|
||||
mem[0][i] = 0;
|
||||
|
||||
if (i != groupbuf[GRMEMCNT]) {
|
||||
|
||||
+53
-40
@@ -1,49 +1,62 @@
|
||||
#include "pwf.h"
|
||||
#include <pthread.h>
|
||||
#include "account_client.h"
|
||||
#include <grp.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define FIX(x) (gr->gr_##x = gr->gr_##x-line+buf)
|
||||
|
||||
static int getgr_r(const char *name, gid_t gid, struct group *gr, char *buf, size_t size, struct group **res)
|
||||
{
|
||||
char *line = 0;
|
||||
size_t len = 0;
|
||||
char **mem = 0;
|
||||
size_t nmem = 0;
|
||||
int rv = 0;
|
||||
size_t i;
|
||||
int cs;
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||
|
||||
rv = __getgr_a(name, gid, gr, &line, &len, &mem, &nmem, res);
|
||||
if (*res && size < len + (nmem+1)*sizeof(char *) + 32) {
|
||||
*res = 0;
|
||||
rv = ERANGE;
|
||||
}
|
||||
if (*res) {
|
||||
buf += (16-(uintptr_t)buf)%16;
|
||||
gr->gr_mem = (void *)buf;
|
||||
buf += (nmem+1)*sizeof(char *);
|
||||
memcpy(buf, line, len);
|
||||
FIX(name);
|
||||
FIX(passwd);
|
||||
for (i=0; mem[i]; i++)
|
||||
gr->gr_mem[i] = mem[i]-line+buf;
|
||||
gr->gr_mem[i] = 0;
|
||||
}
|
||||
free(mem);
|
||||
free(line);
|
||||
pthread_setcancelstate(cs, 0);
|
||||
if (rv) errno = rv;
|
||||
return rv;
|
||||
}
|
||||
#define VERIFYPOOL(pool) if (!pool.ptr || pool.len == 0) { if (res) *res = NULL; return EINVAL; }
|
||||
|
||||
int getgrnam_r(const char *name, struct group *gr, char *buf, size_t size, struct group **res)
|
||||
{
|
||||
return getgr_r(name, 0, gr, buf, size, res);
|
||||
int ret;
|
||||
int saved_errno;
|
||||
|
||||
DECLPOOL(pool, buf, size);
|
||||
VERIFYPOOL(pool);
|
||||
|
||||
int fd = account_connect();
|
||||
if (fd < 0) {
|
||||
saved_errno = errno;
|
||||
*res = NULL;
|
||||
return saved_errno != 0 ? saved_errno : EIO;
|
||||
}
|
||||
|
||||
ret = account_getgrnam(fd, name, gr, &pool);
|
||||
saved_errno = errno;
|
||||
spp_close(fd);
|
||||
|
||||
if (ret != 0) {
|
||||
*res = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*res = gr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getgrgid_r(gid_t gid, struct group *gr, char *buf, size_t size, struct group **res)
|
||||
{
|
||||
return getgr_r(0, gid, gr, buf, size, res);
|
||||
int ret;
|
||||
int saved_errno;
|
||||
|
||||
DECLPOOL(pool, buf, size);
|
||||
VERIFYPOOL(pool);
|
||||
|
||||
int fd = account_connect();
|
||||
if (fd < 0) {
|
||||
saved_errno = errno;
|
||||
*res = NULL;
|
||||
return saved_errno != 0 ? saved_errno : EIO;
|
||||
}
|
||||
|
||||
ret = account_getgrgid(fd, gid, gr, &pool);
|
||||
saved_errno = errno;
|
||||
spp_close(fd);
|
||||
|
||||
if (ret != 0) {
|
||||
*res = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*res = gr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+50
-19
@@ -1,39 +1,70 @@
|
||||
#include "pwf.h"
|
||||
#include <grp.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "account_client.h"
|
||||
|
||||
static FILE *f;
|
||||
static char *line, **mem;
|
||||
static struct group gr;
|
||||
static char grs_buf[16384];
|
||||
unsigned int igrent = 0;
|
||||
|
||||
void setgrent()
|
||||
{
|
||||
if (f) fclose(f);
|
||||
f = 0;
|
||||
igrent = 0;
|
||||
}
|
||||
|
||||
weak_alias(setgrent, endgrent);
|
||||
|
||||
struct group *getgrent()
|
||||
{
|
||||
struct group *res;
|
||||
size_t size=0, nmem=0;
|
||||
if (!f) f = fopen("/etc/group", "rbe");
|
||||
if (!f) return 0;
|
||||
__getgrent_a(f, &gr, &line, &size, &mem, &nmem, &res);
|
||||
return res;
|
||||
memset(&gr, 0, sizeof(gr));
|
||||
memset(grs_buf, 0, sizeof(grs_buf));
|
||||
DECLPOOL(pool, grs_buf, sizeof(grs_buf));
|
||||
|
||||
int fd = account_connect();
|
||||
int status = account_getgrent(fd, &igrent, &gr, &pool);
|
||||
spp_close(fd);
|
||||
if (status != 0) return NULL;
|
||||
return &gr;
|
||||
}
|
||||
|
||||
struct group *getgrgid(gid_t gid)
|
||||
{
|
||||
struct group *res;
|
||||
size_t size=0, nmem=0;
|
||||
__getgr_a(0, gid, &gr, &line, &size, &mem, &nmem, &res);
|
||||
return res;
|
||||
struct group *result;
|
||||
int ret;
|
||||
|
||||
memset(&gr, 0, sizeof(gr));
|
||||
memset(grs_buf, 0, sizeof(grs_buf));
|
||||
|
||||
ret = getgrgid_r(gid, &gr, grs_buf, sizeof(grs_buf), &result);
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
return NULL;
|
||||
}
|
||||
if (result == NULL) {
|
||||
errno = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &gr;
|
||||
}
|
||||
|
||||
struct group *getgrnam(const char *name)
|
||||
{
|
||||
struct group *res;
|
||||
size_t size=0, nmem=0;
|
||||
__getgr_a(name, 0, &gr, &line, &size, &mem, &nmem, &res);
|
||||
return res;
|
||||
struct group *result;
|
||||
int ret;
|
||||
|
||||
memset(&gr, 0, sizeof(gr));
|
||||
memset(grs_buf, 0, sizeof(grs_buf));
|
||||
|
||||
ret = getgrnam_r(name, &gr, grs_buf, sizeof(grs_buf), &result);
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
return NULL;
|
||||
}
|
||||
if (result == NULL) {
|
||||
errno = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &gr;
|
||||
}
|
||||
|
||||
+53
-33
@@ -1,42 +1,62 @@
|
||||
#include "pwf.h"
|
||||
#include <pthread.h>
|
||||
#include "account_client.h"
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define FIX(x) (pw->pw_##x = pw->pw_##x-line+buf)
|
||||
|
||||
static int getpw_r(const char *name, uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **res)
|
||||
{
|
||||
char *line = 0;
|
||||
size_t len = 0;
|
||||
int rv = 0;
|
||||
int cs;
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||
|
||||
rv = __getpw_a(name, uid, pw, &line, &len, res);
|
||||
if (*res && size < len) {
|
||||
*res = 0;
|
||||
rv = ERANGE;
|
||||
}
|
||||
if (*res) {
|
||||
memcpy(buf, line, len);
|
||||
FIX(name);
|
||||
FIX(passwd);
|
||||
FIX(gecos);
|
||||
FIX(dir);
|
||||
FIX(shell);
|
||||
}
|
||||
free(line);
|
||||
pthread_setcancelstate(cs, 0);
|
||||
if (rv) errno = rv;
|
||||
return rv;
|
||||
}
|
||||
#define VERIFYPOOL(pool) if (!pool.ptr || pool.len == 0) { if (res) *res = NULL; return EINVAL; }
|
||||
|
||||
int getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t size, struct passwd **res)
|
||||
{
|
||||
return getpw_r(name, 0, pw, buf, size, res);
|
||||
int ret;
|
||||
int saved_errno;
|
||||
|
||||
DECLPOOL(pool, buf, size);
|
||||
VERIFYPOOL(pool);
|
||||
|
||||
int fd = account_connect();
|
||||
if (fd < 0) {
|
||||
saved_errno = errno;
|
||||
*res = NULL;
|
||||
return saved_errno != 0 ? saved_errno : EIO;
|
||||
}
|
||||
|
||||
ret = account_getpwnam(fd, name, pw, &pool);
|
||||
saved_errno = errno;
|
||||
spp_close(fd);
|
||||
|
||||
if (ret != 0) {
|
||||
*res = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*res = pw;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **res)
|
||||
{
|
||||
return getpw_r(0, uid, pw, buf, size, res);
|
||||
int ret;
|
||||
int saved_errno;
|
||||
|
||||
DECLPOOL(pool, buf, size);
|
||||
VERIFYPOOL(pool);
|
||||
|
||||
int fd = account_connect();
|
||||
if (fd < 0) {
|
||||
saved_errno = errno;
|
||||
*res = NULL;
|
||||
return saved_errno != 0 ? saved_errno : EIO;
|
||||
}
|
||||
|
||||
ret = account_getpwuid(fd, uid, pw, &pool);
|
||||
saved_errno = errno;
|
||||
spp_close(fd);
|
||||
|
||||
if (ret != 0) {
|
||||
*res = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*res = pw;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+50
-17
@@ -1,37 +1,70 @@
|
||||
#include "pwf.h"
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "account_client.h"
|
||||
|
||||
static FILE *f;
|
||||
static char *line;
|
||||
static struct passwd pw;
|
||||
static size_t size;
|
||||
static char pwr_buf[16384];
|
||||
unsigned int ipwent = 0;
|
||||
|
||||
void setpwent()
|
||||
{
|
||||
if (f) fclose(f);
|
||||
f = 0;
|
||||
ipwent = 0;
|
||||
}
|
||||
|
||||
weak_alias(setpwent, endpwent);
|
||||
|
||||
struct passwd *getpwent()
|
||||
{
|
||||
struct passwd *res;
|
||||
if (!f) f = fopen("/etc/passwd", "rbe");
|
||||
if (!f) return 0;
|
||||
__getpwent_a(f, &pw, &line, &size, &res);
|
||||
return res;
|
||||
memset(&pw, 0, sizeof(pw));
|
||||
memset(pwr_buf, 0, sizeof(pwr_buf));
|
||||
DECLPOOL(pool, pwr_buf, sizeof(pwr_buf));
|
||||
|
||||
int fd = account_connect();
|
||||
int status = account_getpwent(fd, &ipwent, &pw, &pool);
|
||||
spp_close(fd);
|
||||
if (status != 0) return NULL;
|
||||
return &pw;
|
||||
}
|
||||
|
||||
struct passwd *getpwuid(uid_t uid)
|
||||
{
|
||||
struct passwd *res;
|
||||
__getpw_a(0, uid, &pw, &line, &size, &res);
|
||||
return res;
|
||||
struct passwd *result;
|
||||
int ret;
|
||||
|
||||
memset(&pw, 0, sizeof(pw));
|
||||
memset(pwr_buf, 0, sizeof(pwr_buf));
|
||||
|
||||
ret = getpwuid_r(uid, &pw, pwr_buf, sizeof(pwr_buf), &result);
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
return NULL;
|
||||
}
|
||||
if (result == NULL) {
|
||||
errno = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &pw;
|
||||
}
|
||||
|
||||
struct passwd *getpwnam(const char *name)
|
||||
{
|
||||
struct passwd *res;
|
||||
__getpw_a(name, 0, &pw, &line, &size, &res);
|
||||
return res;
|
||||
struct passwd *result;
|
||||
int ret;
|
||||
|
||||
memset(&pw, 0, sizeof(pw));
|
||||
memset(pwr_buf, 0, sizeof(pwr_buf));
|
||||
|
||||
ret = getpwnam_r(name, &pw, pwr_buf, sizeof(pwr_buf), &result);
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
return NULL;
|
||||
}
|
||||
if (result == NULL) {
|
||||
errno = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &pw;
|
||||
}
|
||||
|
||||
+3516
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,124 @@
|
||||
#ifndef SPP_H
|
||||
#define SPP_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
static inline int write_all(int fd, const void *buf, size_t len)
|
||||
{
|
||||
const char *p = buf;
|
||||
size_t remaining = len;
|
||||
while (remaining > 0) {
|
||||
ssize_t n = write(fd, p, remaining);
|
||||
if (n <= 0) return -1;
|
||||
p += n;
|
||||
remaining -= (size_t)n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int read_all(int fd, void *buf, size_t len)
|
||||
{
|
||||
char *p = buf;
|
||||
size_t remaining = len;
|
||||
while (remaining > 0) {
|
||||
ssize_t n = read(fd, p, remaining);
|
||||
if (n <= 0) return -1;
|
||||
p += n;
|
||||
remaining -= (size_t)n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spp_connect_common(const char *path, int abstract)
|
||||
{
|
||||
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == -1) return -1;
|
||||
|
||||
struct sockaddr_un addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
|
||||
size_t len = strlen(path);
|
||||
if (len >= sizeof(addr.sun_path)) {
|
||||
close(fd);
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
socklen_t addrlen;
|
||||
|
||||
if (abstract) {
|
||||
addr.sun_path[0] = '\0';
|
||||
memcpy(addr.sun_path + 1, path, len);
|
||||
addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + len;
|
||||
} else {
|
||||
memcpy(addr.sun_path, path, len);
|
||||
addrlen = offsetof(struct sockaddr_un, sun_path) + len;
|
||||
}
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&addr, addrlen) == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static inline int spp_connect_unix(char *path)
|
||||
{
|
||||
return spp_connect_common(path, 0);
|
||||
}
|
||||
|
||||
static inline int spp_connect_linux(char *abstract_name)
|
||||
{
|
||||
return spp_connect_common(abstract_name, 1);
|
||||
}
|
||||
|
||||
static inline void spp_close(int fd)
|
||||
{
|
||||
if (fd >= 0) close(fd);
|
||||
}
|
||||
|
||||
static inline int spp_send(int fd, char *packet)
|
||||
{
|
||||
size_t data_len = strlen(packet);
|
||||
if (data_len > UINT32_MAX) return -1;
|
||||
|
||||
uint32_t len = (uint32_t)data_len;
|
||||
|
||||
if (write_all(fd, &len, sizeof(len)) == -1) return -1;
|
||||
if (data_len > 0 && write_all(fd, packet, data_len) == -1) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline char *spp_recv(int fd)
|
||||
{
|
||||
uint32_t len;
|
||||
if (read_all(fd, &len, sizeof(len)) == -1) return NULL;
|
||||
|
||||
char *buf = malloc(len + 1);
|
||||
if (!buf) return NULL;
|
||||
|
||||
if (len > 0 && read_all(fd, buf, len) == -1) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline void spp_free(void *p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -69,6 +69,8 @@ _Noreturn void __pthread_exit(void *result)
|
||||
|
||||
__pthread_tsd_run_dtors();
|
||||
|
||||
__malloc_thread_done();
|
||||
|
||||
__block_app_sigs(&set);
|
||||
|
||||
/* This atomic potentially competes with a concurrent pthread_detach
|
||||
@@ -204,6 +206,7 @@ static int start(void *p)
|
||||
}
|
||||
}
|
||||
__syscall(SYS_rt_sigprocmask, SIG_SETMASK, &args->sig_mask, 0, _NSIG/8);
|
||||
__malloc_thread_init();
|
||||
__pthread_exit(args->start_func(args->start_arg));
|
||||
return 0;
|
||||
}
|
||||
@@ -212,6 +215,7 @@ static int start_c11(void *p)
|
||||
{
|
||||
struct start_args *args = p;
|
||||
int (*start)(void*) = (int(*)(void*)) args->start_func;
|
||||
__malloc_thread_init();
|
||||
__pthread_exit((void *)(uintptr_t)start(args->start_arg));
|
||||
return 0;
|
||||
}
|
||||
|
||||
+3
-3
@@ -132,7 +132,7 @@ static void do_tzset()
|
||||
"/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0";
|
||||
|
||||
s = getenv("TZ");
|
||||
if (!s) s = "/etc/localtime";
|
||||
if (!s) s = "/var/config/localtime";
|
||||
if (!*s) s = __utc;
|
||||
|
||||
if (old_tz && !strcmp(s, old_tz)) return;
|
||||
@@ -163,7 +163,7 @@ static void do_tzset()
|
||||
|| !strcmp(dummy_name, "UTC")
|
||||
|| !strcmp(dummy_name, "GMT")))
|
||||
posix_form = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Non-suid can use an absolute tzfile pathname or a relative
|
||||
* pathame beginning with "."; in secure mode, only the
|
||||
@@ -171,7 +171,7 @@ static void do_tzset()
|
||||
if (!posix_form) {
|
||||
if (*s == ':') s++;
|
||||
if (*s == '/' || *s == '.') {
|
||||
if (!libc.secure || !strcmp(s, "/etc/localtime"))
|
||||
if (!libc.secure || !strcmp(s, "/var/config/localtime"))
|
||||
map = __map_file(s, &map_size);
|
||||
} else {
|
||||
size_t l = strlen(s);
|
||||
|
||||
@@ -11,8 +11,7 @@ fn main() {
|
||||
let dst = args.next().expect("please specify output file");
|
||||
|
||||
let mut octos = Vec::new();
|
||||
let src_content = std::fs::read_to_string(&src)
|
||||
.expect("cannot read source file");
|
||||
let src_content = std::fs::read_to_string(&src).expect("cannot read source file");
|
||||
let mut current_tag = None;
|
||||
for (nline, line) in src_content.lines().enumerate() {
|
||||
let line = line.trim();
|
||||
@@ -129,7 +128,9 @@ fn do_arg(s: &str, content: &mut [u8; 8], cursor: &mut usize) -> Option<(usize,
|
||||
_ => panic!("unknown radix"),
|
||||
};
|
||||
*cursor = 8;
|
||||
*content = u64::from_str_radix(&digit[1..], radix).unwrap().to_be_bytes();
|
||||
*content = u64::from_str_radix(&digit[1..], radix)
|
||||
.unwrap()
|
||||
.to_be_bytes();
|
||||
None
|
||||
} else if let Some(reg_id) = s.strip_prefix("&r") {
|
||||
content[*cursor] = reg_id.parse::<u8>().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user