#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
#else
__RCSID("$NetBSD: ctype_.c,v 1.24 2025/09/15 00:11:54 riastradh Exp $");
#endif
#endif
#include <sys/ctype_bits.h>
#include <sys/mman.h>
#include <stdio.h>
#include <string.h>
#include "ctype_guard.h"
#include "ctype_local.h"
#if EOF != -1
#error "EOF != -1"
#endif
#ifdef __BUILD_LEGACY
#define _C _COMPAT_C
#define _S _COMPAT_S
#define _U _COMPAT_U
#define _X _COMPAT_X
#define _L _COMPAT_L
#define _P _COMPAT_P
#define _B _COMPAT_B
#define _N _COMPAT_N
__ctype_table
static
const unsigned char _C_compat_bsdctype_guarded[_C_COMPAT_BSDCTYPE_GUARD +
1 + _CTYPE_NUM_CHARS] = {
_CTYPE_GUARD_INIT(_C_COMPAT_BSDCTYPE_GUARD, -1)
[_C_COMPAT_BSDCTYPE_GUARD] = 0,
_C, _C, _C, _C, _C, _C, _C, _C,
_C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C,
_C, _C, _C, _C, _C, _C, _C, _C,
_C, _C, _C, _C, _C, _C, _C, _C,
_S|_B, _P, _P, _P, _P, _P, _P, _P,
_P, _P, _P, _P, _P, _P, _P, _P,
_N, _N, _N, _N, _N, _N, _N, _N,
_N, _N, _P, _P, _P, _P, _P, _P,
_P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U,
_U, _U, _U, _U, _U, _U, _U, _U,
_U, _U, _U, _U, _U, _U, _U, _U,
_U, _U, _U, _P, _P, _P, _P, _P,
_P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L,
_L, _L, _L, _L, _L, _L, _L, _L,
_L, _L, _L, _L, _L, _L, _L, _L,
_L, _L, _L, _P, _P, _P, _P, _C
};
__ctype_table_guarded(_C_compat_bsdctype, _C_compat_bsdctype_guarded,
1 + _CTYPE_NUM_CHARS, 1);
#undef _C
#undef _S
#undef _U
#undef _X
#undef _L
#undef _P
#undef _B
#undef _N
#ifdef __weak_alias
__weak_alias(_C_ctype_, _C_compat_bsdctype)
#endif
const unsigned char *_ctype_ = &_C_compat_bsdctype[0];
#endif
#define _A _CTYPE_A
#define _BL _CTYPE_BL
#define _C _CTYPE_C
#define _D _CTYPE_D
#define _G _CTYPE_G
#define _L _CTYPE_L
#define _P _CTYPE_P
#define _R _CTYPE_R
#define _S _CTYPE_S
#define _U _CTYPE_U
#define _X _CTYPE_X
__ctype_table
static const unsigned short _C_ctype_tab_guarded_[_C_CTYPE_TAB_GUARD +
1 + _CTYPE_NUM_CHARS] = {
_CTYPE_GUARD_INIT(_C_CTYPE_TAB_GUARD, -1)
[_C_CTYPE_TAB_GUARD] = 0,
_C, _C, _C, _C,
_C, _C, _C, _C,
_C, _BL|_C|_S, _C|_S, _C|_S,
_C|_S, _C|_S, _C, _C,
_C, _C, _C, _C,
_C, _C, _C, _C,
_C, _C, _C, _C,
_C, _C, _C, _C,
_BL|_R|_S, _G|_R|_P, _G|_R|_P, _G|_R|_P,
_G|_R|_P, _G|_R|_P, _G|_R|_P, _G|_R|_P,
_G|_R|_P, _G|_R|_P, _G|_R|_P, _G|_R|_P,
_G|_R|_P, _G|_R|_P, _G|_R|_P, _G|_R|_P,
_D|_G|_R|_X, _D|_G|_R|_X, _D|_G|_R|_X, _D|_G|_R|_X,
_D|_G|_R|_X, _D|_G|_R|_X, _D|_G|_R|_X, _D|_G|_R|_X,
_D|_G|_R|_X, _D|_G|_R|_X, _G|_R|_P, _G|_R|_P,
_G|_R|_P, _G|_R|_P, _G|_R|_P, _G|_R|_P,
_G|_R|_P, _A|_G|_R|_U|_X, _A|_G|_R|_U|_X, _A|_G|_R|_U|_X,
_A|_G|_R|_U|_X, _A|_G|_R|_U|_X, _A|_G|_R|_U|_X, _A|_G|_R|_U,
_A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U,
_A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U,
_A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U,
_A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U,
_A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, _G|_R|_P,
_G|_R|_P, _G|_R|_P, _G|_R|_P, _G|_R|_P,
_G|_R|_P, _A|_G|_L|_R|_X, _A|_G|_L|_R|_X, _A|_G|_L|_R|_X,
_A|_G|_L|_R|_X, _A|_G|_L|_R|_X, _A|_G|_L|_R|_X, _A|_G|_L|_R,
_A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R,
_A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R,
_A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R,
_A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R,
_A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, _G|_R|_P,
_G|_R|_P, _G|_R|_P, _G|_R|_P, _C,
};
__ctype_table_guarded(_C_ctype_tab_, _C_ctype_tab_guarded_,
1 + _CTYPE_NUM_CHARS, __SIZEOF_SHORT__);
#undef _A
#undef _BL
#undef _C
#undef _D
#undef _G
#undef _L
#undef _P
#undef _R
#undef _S
#undef _U
#undef _X
const unsigned short *_ctype_tab_ = &_C_ctype_tab_[0];
#ifndef RTLD_LOADER
#include "extern.h"
static bool
_allow_ctype_abuse(void)
{
const char vareq[] = "LIBC_ALLOWCTYPEABUSE=";
char *const *envp;
for (envp = environ; *envp != NULL; envp++) {
if (strncmp(*envp, vareq, strlen(vareq)) == 0) {
return true;
}
}
return false;
}
#endif
#if _CTYPE_GUARD_PAGE
static enum {
ABUSE_UNDETERMINED = 0,
ABUSE_ALLOWED,
ABUSE_TRAPPED,
} allow_ctype_abuse_cache;
__dso_hidden
bool
allow_ctype_abuse(void)
{
if (allow_ctype_abuse_cache != ABUSE_UNDETERMINED)
return allow_ctype_abuse_cache == ABUSE_ALLOWED;
return _allow_ctype_abuse();
}
__dso_hidden
bool
constructor_allow_ctype_abuse(void)
{
if (allow_ctype_abuse_cache != ABUSE_UNDETERMINED)
return allow_ctype_abuse_cache == ABUSE_ALLOWED;
if (_allow_ctype_abuse()) {
allow_ctype_abuse_cache = ABUSE_ALLOWED;
return true;
} else {
allow_ctype_abuse_cache = ABUSE_TRAPPED;
return false;
}
}
__attribute__((constructor))
static void
_C_ctype_tab_guard_init(void)
{
if (constructor_allow_ctype_abuse())
return;
#ifdef __BUILD_LEGACY
(void)mprotect(__UNCONST(_C_compat_bsdctype_guarded),
_CTYPE_GUARD_SIZE, PROT_NONE);
#endif
(void)mprotect(__UNCONST(_C_ctype_tab_guarded_),
_CTYPE_GUARD_SIZE, PROT_NONE);
}
#else
#ifndef RTLD_LOADER
__dso_hidden
bool
allow_ctype_abuse(void)
{
return _allow_ctype_abuse();
}
#endif
#endif