diff options
Diffstat (limited to 'contrib/libs/libc_compat')
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/README.md | 182 | ||||
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/aligned_alloc.c | 12 | ||||
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/c16rtomb.c | 70 | ||||
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/c32rtomb.c | 14 | ||||
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/features.h | 10 | ||||
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/getauxval.cpp | 20 | ||||
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/glibc.cpp | 222 | ||||
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/glibc.h | 40 | ||||
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/mbrtoc16.c | 60 | ||||
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/mbrtoc32.c | 26 | ||||
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/secure_getenv.cpp | 24 | ||||
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/timespec_get.c | 20 | ||||
-rw-r--r-- | contrib/libs/libc_compat/ubuntu_14/ya.make | 44 |
13 files changed, 372 insertions, 372 deletions
diff --git a/contrib/libs/libc_compat/ubuntu_14/README.md b/contrib/libs/libc_compat/ubuntu_14/README.md index 63dd8a22d9..f7b17a40cc 100644 --- a/contrib/libs/libc_compat/ubuntu_14/README.md +++ b/contrib/libs/libc_compat/ubuntu_14/README.md @@ -1,91 +1,91 @@ -## Общие соображения - -В библиотеку добавлены реализации символов, появившихся в `libc.so.6` Ubuntu -14.04 с момента Ubuntu 12.04. - -Если какой-либо объектный файл ссылается на один из таких символов, то при -компоновке этот символ будет взят из нашей библиотеки. В противном случае, -компоновщик сослался бы на такой символ из `libc.so.6`, добавив к исполняемому -файлу зависимость от новой версии динамической библиотеки (`GLIBC_2.16`, -`GLIBC_2.17` или `GLIBC_2.18`). Такой исполняемый файл не может быть запущен на -Ubuntu 12.04, даже если ни один из новых символов не используется в runtime. - -На Ubuntu 14.04 или более новых, в случае если процесс загружает `libc.so.6`, мы -будем в runtime иметь две реализации символов, нашу и libc. Но все добавленные -функции не имеют какого-либо состояния и никакими деталями внутренней реализации -не связаны с другими. Нет разницы, какую из реализаций использовать, и даже -попеременное использование различных реализаций в одном и том же контексте не -должно приводить к некорректной работе. - -В какой-то момент этот слой совместимости будет отключен: https://st.yandex-team.ru/DEVTOOLS-7436 - -### Разделяемая реализация - -Была идея оформить новые реализации так, чтобы в случае их наличия и в -загруженной libc динамический компоновщик выбирал для всех ссылок одну -реализацию. - -По всей видимости, для этого требуется собирать исполняемый файл как PIE. Только -в этом случае для наших реализаций будут сгенерированы дополнительные PLT -прослойки и вызовы наших реализаций будут проходить через них. - -Но в этом случае вообще все вызовы будут происходить таким образом и это -повлияет на производительность. Ухудшения производительности, наверное, можно -избежать, явно указав, какие символы в исполняемом файле должны быть публичными, -но сейчас нет способа сделать это в одном месте, учитывая, что в некоторых -случаях этот список должен дополняться. - -## `getauxval` и `secure_getenv` - -Функция `getauxval` требует загрузки и хранения «Auxiliary Vector» (см. -[здесь](https://refspecs.linuxfoundation.org/LSB_1.3.0/IA64/spec/auxiliaryvector.html)). - -Эти данные доступны в момент запуска процесса. libc из новых Ubuntu сохраняет -эти данные и предоставляет реализацию `getauxval`. В этом случае наша реализация -перенаправляет вызовы `getauxval` в libc, получив при старте исполняемого файла -соответствующий указатель. - -Если реализация libc недоступна (на старых Ubuntu или если libc не загружена), -то эти данные можно получить, прочитав `/proc/self/auxv`. Это также делается -один раз при старте. - -В обоих случаях, статически инициализируется синглтон `NUbuntuCompat::TGlibc`, -который производит эти действия в конструкторе. - -`secure_getenv` использует одно из значений `getauxval`, поэтому к нему всё это -также относится. - -Каждый метод новой libc реализован в отдельном объектом файле. `TGlibc` также -находится в отдельном файле, и ссылки на неё стоят только в местах использования. -Если при компоновке не понадобились ни `getauxval`, ни `secure_getenv`, то -объектный файл с `TGlibc` тоже не будет выбран компоновщиком, и в этом случае -никакой лишней статической инициализации выполняться не будет. - -## Патч libc.so - -Чтобы иметь возможность использовать `getauxval` (точнее его реализацию -`__getauxval`) из новой libc, если таковая уже используется процессом, -библиотека совместимости объявляет этот символ у себя как внешний и слабый. При -загрузке динамический компоновщик устанавливает значение этого символа из libc -или `nullptr`, если его там нет. Наша реализация `getauxval` проверяет -доступность реализации libc, просто сравнивая указатель с `nullptr`. - -В Аркадии также есть код, который подобным образом работает с символом -`__cxa_thread_atexit_impl`. - -Однако, если компоновать такую программу с использованием новой libc, то к таким -символам и самой программе будет приписано требование соответствующей (новой) -версии libc. Чтобы этого не произошло, при сборке с этой библиотекой -совместимости используется патченный вариант `libc.so.6`, где у таких символов -удалена версия. - -Также, файлы, проверяющие, что доступна реализация из libc, должны быть собраны -как PIC. В противном случае вместо значения, заполненного динамическим -компоновщиком, компилятор ещё на стадии компиляции использует `nullptr` и -проверка никогда не срабатывает. - -## Упоминания - -Идея о возможности добавить слой совместимости была взята из ClickHouse. -* [https://clickhouse.tech/](https://clickhouse.tech/) -* [https://wiki.yandex-team.ru/clickhouse/](https://wiki.yandex-team.ru/clickhouse/) +## Общие соображения + +В библиотеку добавлены реализации символов, появившихся в `libc.so.6` Ubuntu +14.04 с момента Ubuntu 12.04. + +Если какой-либо объектный файл ссылается на один из таких символов, то при +компоновке этот символ будет взят из нашей библиотеки. В противном случае, +компоновщик сослался бы на такой символ из `libc.so.6`, добавив к исполняемому +файлу зависимость от новой версии динамической библиотеки (`GLIBC_2.16`, +`GLIBC_2.17` или `GLIBC_2.18`). Такой исполняемый файл не может быть запущен на +Ubuntu 12.04, даже если ни один из новых символов не используется в runtime. + +На Ubuntu 14.04 или более новых, в случае если процесс загружает `libc.so.6`, мы +будем в runtime иметь две реализации символов, нашу и libc. Но все добавленные +функции не имеют какого-либо состояния и никакими деталями внутренней реализации +не связаны с другими. Нет разницы, какую из реализаций использовать, и даже +попеременное использование различных реализаций в одном и том же контексте не +должно приводить к некорректной работе. + +В какой-то момент этот слой совместимости будет отключен: https://st.yandex-team.ru/DEVTOOLS-7436 + +### Разделяемая реализация + +Была идея оформить новые реализации так, чтобы в случае их наличия и в +загруженной libc динамический компоновщик выбирал для всех ссылок одну +реализацию. + +По всей видимости, для этого требуется собирать исполняемый файл как PIE. Только +в этом случае для наших реализаций будут сгенерированы дополнительные PLT +прослойки и вызовы наших реализаций будут проходить через них. + +Но в этом случае вообще все вызовы будут происходить таким образом и это +повлияет на производительность. Ухудшения производительности, наверное, можно +избежать, явно указав, какие символы в исполняемом файле должны быть публичными, +но сейчас нет способа сделать это в одном месте, учитывая, что в некоторых +случаях этот список должен дополняться. + +## `getauxval` и `secure_getenv` + +Функция `getauxval` требует загрузки и хранения «Auxiliary Vector» (см. +[здесь](https://refspecs.linuxfoundation.org/LSB_1.3.0/IA64/spec/auxiliaryvector.html)). + +Эти данные доступны в момент запуска процесса. libc из новых Ubuntu сохраняет +эти данные и предоставляет реализацию `getauxval`. В этом случае наша реализация +перенаправляет вызовы `getauxval` в libc, получив при старте исполняемого файла +соответствующий указатель. + +Если реализация libc недоступна (на старых Ubuntu или если libc не загружена), +то эти данные можно получить, прочитав `/proc/self/auxv`. Это также делается +один раз при старте. + +В обоих случаях, статически инициализируется синглтон `NUbuntuCompat::TGlibc`, +который производит эти действия в конструкторе. + +`secure_getenv` использует одно из значений `getauxval`, поэтому к нему всё это +также относится. + +Каждый метод новой libc реализован в отдельном объектом файле. `TGlibc` также +находится в отдельном файле, и ссылки на неё стоят только в местах использования. +Если при компоновке не понадобились ни `getauxval`, ни `secure_getenv`, то +объектный файл с `TGlibc` тоже не будет выбран компоновщиком, и в этом случае +никакой лишней статической инициализации выполняться не будет. + +## Патч libc.so + +Чтобы иметь возможность использовать `getauxval` (точнее его реализацию +`__getauxval`) из новой libc, если таковая уже используется процессом, +библиотека совместимости объявляет этот символ у себя как внешний и слабый. При +загрузке динамический компоновщик устанавливает значение этого символа из libc +или `nullptr`, если его там нет. Наша реализация `getauxval` проверяет +доступность реализации libc, просто сравнивая указатель с `nullptr`. + +В Аркадии также есть код, который подобным образом работает с символом +`__cxa_thread_atexit_impl`. + +Однако, если компоновать такую программу с использованием новой libc, то к таким +символам и самой программе будет приписано требование соответствующей (новой) +версии libc. Чтобы этого не произошло, при сборке с этой библиотекой +совместимости используется патченный вариант `libc.so.6`, где у таких символов +удалена версия. + +Также, файлы, проверяющие, что доступна реализация из libc, должны быть собраны +как PIC. В противном случае вместо значения, заполненного динамическим +компоновщиком, компилятор ещё на стадии компиляции использует `nullptr` и +проверка никогда не срабатывает. + +## Упоминания + +Идея о возможности добавить слой совместимости была взята из ClickHouse. +* [https://clickhouse.tech/](https://clickhouse.tech/) +* [https://wiki.yandex-team.ru/clickhouse/](https://wiki.yandex-team.ru/clickhouse/) diff --git a/contrib/libs/libc_compat/ubuntu_14/aligned_alloc.c b/contrib/libs/libc_compat/ubuntu_14/aligned_alloc.c index 880babd32a..c4a1378624 100644 --- a/contrib/libs/libc_compat/ubuntu_14/aligned_alloc.c +++ b/contrib/libs/libc_compat/ubuntu_14/aligned_alloc.c @@ -1,6 +1,6 @@ -#include <malloc.h> -#include <stdlib.h> - -__attribute__((weak)) void* aligned_alloc(size_t alignment, size_t size) { - return memalign(alignment, size); -} +#include <malloc.h> +#include <stdlib.h> + +__attribute__((weak)) void* aligned_alloc(size_t alignment, size_t size) { + return memalign(alignment, size); +} diff --git a/contrib/libs/libc_compat/ubuntu_14/c16rtomb.c b/contrib/libs/libc_compat/ubuntu_14/c16rtomb.c index 18bc92c36c..39ca3758fa 100644 --- a/contrib/libs/libc_compat/ubuntu_14/c16rtomb.c +++ b/contrib/libs/libc_compat/ubuntu_14/c16rtomb.c @@ -1,35 +1,35 @@ -#include <uchar.h> -#include <errno.h> -#include <wchar.h> - -size_t c16rtomb(char *restrict s, char16_t c16, mbstate_t *restrict ps) -{ - static unsigned internal_state; - if (!ps) ps = (void *)&internal_state; - unsigned *x = (unsigned *)ps; - wchar_t wc; - - if (!s) { - if (*x) goto ilseq; - return 1; - } - - if (!*x && c16 - 0xd800u < 0x400) { - *x = c16 - 0xd7c0 << 10; - return 0; - } - - if (*x) { - if (c16 - 0xdc00u >= 0x400) goto ilseq; - else wc = *x + c16 - 0xdc00; - *x = 0; - } else { - wc = c16; - } - return wcrtomb(s, wc, 0); - -ilseq: - *x = 0; - errno = EILSEQ; - return -1; -} +#include <uchar.h> +#include <errno.h> +#include <wchar.h> + +size_t c16rtomb(char *restrict s, char16_t c16, mbstate_t *restrict ps) +{ + static unsigned internal_state; + if (!ps) ps = (void *)&internal_state; + unsigned *x = (unsigned *)ps; + wchar_t wc; + + if (!s) { + if (*x) goto ilseq; + return 1; + } + + if (!*x && c16 - 0xd800u < 0x400) { + *x = c16 - 0xd7c0 << 10; + return 0; + } + + if (*x) { + if (c16 - 0xdc00u >= 0x400) goto ilseq; + else wc = *x + c16 - 0xdc00; + *x = 0; + } else { + wc = c16; + } + return wcrtomb(s, wc, 0); + +ilseq: + *x = 0; + errno = EILSEQ; + return -1; +} diff --git a/contrib/libs/libc_compat/ubuntu_14/c32rtomb.c b/contrib/libs/libc_compat/ubuntu_14/c32rtomb.c index 9fccc0fafd..67851328e8 100644 --- a/contrib/libs/libc_compat/ubuntu_14/c32rtomb.c +++ b/contrib/libs/libc_compat/ubuntu_14/c32rtomb.c @@ -1,7 +1,7 @@ -#include <uchar.h> -#include <wchar.h> - -size_t c32rtomb(char *restrict s, char32_t c32, mbstate_t *restrict ps) -{ - return wcrtomb(s, c32, ps); -} +#include <uchar.h> +#include <wchar.h> + +size_t c32rtomb(char *restrict s, char32_t c32, mbstate_t *restrict ps) +{ + return wcrtomb(s, c32, ps); +} diff --git a/contrib/libs/libc_compat/ubuntu_14/features.h b/contrib/libs/libc_compat/ubuntu_14/features.h index 2930bdf967..9fbab45ab5 100644 --- a/contrib/libs/libc_compat/ubuntu_14/features.h +++ b/contrib/libs/libc_compat/ubuntu_14/features.h @@ -1,5 +1,5 @@ -#pragma once - -#define weak __attribute__((__weak__)) -#define weak_alias(old, new) \ - extern __typeof(old) new __attribute__((__weak__, __alias__(#old))) +#pragma once + +#define weak __attribute__((__weak__)) +#define weak_alias(old, new) \ + extern __typeof(old) new __attribute__((__weak__, __alias__(#old))) diff --git a/contrib/libs/libc_compat/ubuntu_14/getauxval.cpp b/contrib/libs/libc_compat/ubuntu_14/getauxval.cpp index 702abf3bbb..9f20dd0195 100644 --- a/contrib/libs/libc_compat/ubuntu_14/getauxval.cpp +++ b/contrib/libs/libc_compat/ubuntu_14/getauxval.cpp @@ -1,10 +1,10 @@ -#include <sys/auxv.h> - -#include "glibc.h" -#include "features.h" - -extern "C" { - unsigned long getauxval(unsigned long item) noexcept { - return NUbuntuCompat::GetGlibc().GetAuxVal(item); - } -} +#include <sys/auxv.h> + +#include "glibc.h" +#include "features.h" + +extern "C" { + unsigned long getauxval(unsigned long item) noexcept { + return NUbuntuCompat::GetGlibc().GetAuxVal(item); + } +} diff --git a/contrib/libs/libc_compat/ubuntu_14/glibc.cpp b/contrib/libs/libc_compat/ubuntu_14/glibc.cpp index b2c6098dd8..1cc444bce1 100644 --- a/contrib/libs/libc_compat/ubuntu_14/glibc.cpp +++ b/contrib/libs/libc_compat/ubuntu_14/glibc.cpp @@ -1,111 +1,111 @@ -#include <elf.h> -#include <errno.h> -#include <fcntl.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "glibc.h" -#include "features.h" - -namespace { - void ReadAuxVector(Elf64_auxv_t** begin, Elf64_auxv_t** end) noexcept { - int fd = open("/proc/self/auxv", O_RDONLY | O_CLOEXEC); - if (fd == -1) { - return; - } - - constexpr size_t item_size = sizeof(Elf64_auxv_t); - constexpr size_t block_size = item_size * 32; - - size_t bytes_read = 0; - size_t size = 0; - - struct TBuffer { - ~TBuffer() { - free(Pointer); - } - char* Pointer = nullptr; - } buffer; - - while (true) { - size_t bytes_left = size - bytes_read; - - if (!bytes_left) { - size += block_size; - char* new_buffer = (char*)realloc(buffer.Pointer, size); - if (!new_buffer) { - return; - } - buffer.Pointer = new_buffer; - continue; - } - - ssize_t r = read(fd, buffer.Pointer + bytes_read, bytes_left); - if (!r) { - break; - } else if (r < 0) { - if (errno == EINTR) { - continue; - } else { - return; - } - } - - bytes_read += r; - } - - size_t item_count = bytes_read / item_size; - *begin = (Elf64_auxv_t*)buffer.Pointer; - *end = (Elf64_auxv_t*)(buffer.Pointer + item_count * item_size); - buffer.Pointer = nullptr; - } -} - -extern "C" { - weak unsigned long __getauxval(unsigned long item); -} - -namespace NUbuntuCompat { - - TGlibc::TGlibc() noexcept - : AuxVectorBegin(nullptr) - , AuxVectorEnd(nullptr) - { - if (!__getauxval) { - ReadAuxVector((Elf64_auxv_t**)&AuxVectorBegin, (Elf64_auxv_t**)&AuxVectorEnd); - } - - Secure = (bool)GetAuxVal(AT_SECURE); - } - - TGlibc::~TGlibc() noexcept { - free(AuxVectorBegin); - } - - unsigned long TGlibc::GetAuxVal(unsigned long item) noexcept { - if (__getauxval) { - return __getauxval(item); - } - - for (Elf64_auxv_t* p = (Elf64_auxv_t*)AuxVectorBegin; p < (Elf64_auxv_t*)AuxVectorEnd; ++p) { - if (p->a_type == item) { - return p->a_un.a_val; - } - } - - errno = ENOENT; - return 0; - } - - bool TGlibc::IsSecure() noexcept { - return Secure; - } - - static TGlibc __attribute__((__init_priority__(101))) GlibcInstance; - - TGlibc& GetGlibc() noexcept { - return GlibcInstance; - } -} +#include <elf.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "glibc.h" +#include "features.h" + +namespace { + void ReadAuxVector(Elf64_auxv_t** begin, Elf64_auxv_t** end) noexcept { + int fd = open("/proc/self/auxv", O_RDONLY | O_CLOEXEC); + if (fd == -1) { + return; + } + + constexpr size_t item_size = sizeof(Elf64_auxv_t); + constexpr size_t block_size = item_size * 32; + + size_t bytes_read = 0; + size_t size = 0; + + struct TBuffer { + ~TBuffer() { + free(Pointer); + } + char* Pointer = nullptr; + } buffer; + + while (true) { + size_t bytes_left = size - bytes_read; + + if (!bytes_left) { + size += block_size; + char* new_buffer = (char*)realloc(buffer.Pointer, size); + if (!new_buffer) { + return; + } + buffer.Pointer = new_buffer; + continue; + } + + ssize_t r = read(fd, buffer.Pointer + bytes_read, bytes_left); + if (!r) { + break; + } else if (r < 0) { + if (errno == EINTR) { + continue; + } else { + return; + } + } + + bytes_read += r; + } + + size_t item_count = bytes_read / item_size; + *begin = (Elf64_auxv_t*)buffer.Pointer; + *end = (Elf64_auxv_t*)(buffer.Pointer + item_count * item_size); + buffer.Pointer = nullptr; + } +} + +extern "C" { + weak unsigned long __getauxval(unsigned long item); +} + +namespace NUbuntuCompat { + + TGlibc::TGlibc() noexcept + : AuxVectorBegin(nullptr) + , AuxVectorEnd(nullptr) + { + if (!__getauxval) { + ReadAuxVector((Elf64_auxv_t**)&AuxVectorBegin, (Elf64_auxv_t**)&AuxVectorEnd); + } + + Secure = (bool)GetAuxVal(AT_SECURE); + } + + TGlibc::~TGlibc() noexcept { + free(AuxVectorBegin); + } + + unsigned long TGlibc::GetAuxVal(unsigned long item) noexcept { + if (__getauxval) { + return __getauxval(item); + } + + for (Elf64_auxv_t* p = (Elf64_auxv_t*)AuxVectorBegin; p < (Elf64_auxv_t*)AuxVectorEnd; ++p) { + if (p->a_type == item) { + return p->a_un.a_val; + } + } + + errno = ENOENT; + return 0; + } + + bool TGlibc::IsSecure() noexcept { + return Secure; + } + + static TGlibc __attribute__((__init_priority__(101))) GlibcInstance; + + TGlibc& GetGlibc() noexcept { + return GlibcInstance; + } +} diff --git a/contrib/libs/libc_compat/ubuntu_14/glibc.h b/contrib/libs/libc_compat/ubuntu_14/glibc.h index e651371878..fa8f7dd013 100644 --- a/contrib/libs/libc_compat/ubuntu_14/glibc.h +++ b/contrib/libs/libc_compat/ubuntu_14/glibc.h @@ -1,20 +1,20 @@ -#pragma once - -typedef unsigned long (*TGetAuxVal)(unsigned long); - -namespace NUbuntuCompat { - class TGlibc { - public: - TGlibc() noexcept; - ~TGlibc() noexcept; - unsigned long GetAuxVal(unsigned long item) noexcept; - bool IsSecure() noexcept; - - private: - void* AuxVectorBegin; - void* AuxVectorEnd; - bool Secure; - }; - - TGlibc& GetGlibc() noexcept; -}; +#pragma once + +typedef unsigned long (*TGetAuxVal)(unsigned long); + +namespace NUbuntuCompat { + class TGlibc { + public: + TGlibc() noexcept; + ~TGlibc() noexcept; + unsigned long GetAuxVal(unsigned long item) noexcept; + bool IsSecure() noexcept; + + private: + void* AuxVectorBegin; + void* AuxVectorEnd; + bool Secure; + }; + + TGlibc& GetGlibc() noexcept; +}; diff --git a/contrib/libs/libc_compat/ubuntu_14/mbrtoc16.c b/contrib/libs/libc_compat/ubuntu_14/mbrtoc16.c index 160b8686c9..765ff9037c 100644 --- a/contrib/libs/libc_compat/ubuntu_14/mbrtoc16.c +++ b/contrib/libs/libc_compat/ubuntu_14/mbrtoc16.c @@ -1,30 +1,30 @@ -#include <uchar.h> -#include <wchar.h> - -size_t mbrtoc16(char16_t *restrict pc16, const char *restrict s, size_t n, mbstate_t *restrict ps) -{ - static unsigned internal_state; - if (!ps) ps = (void *)&internal_state; - unsigned *pending = (unsigned *)ps; - - if (!s) return mbrtoc16(0, "", 1, ps); - - /* mbrtowc states for partial UTF-8 characters have the high bit set; - * we use nonzero states without high bit for pending surrogates. */ - if ((int)*pending > 0) { - if (pc16) *pc16 = *pending; - *pending = 0; - return -3; - } - - wchar_t wc; - size_t ret = mbrtowc(&wc, s, n, ps); - if (ret <= 4) { - if (wc >= 0x10000) { - *pending = (wc & 0x3ff) + 0xdc00; - wc = 0xd7c0 + (wc >> 10); - } - if (pc16) *pc16 = wc; - } - return ret; -} +#include <uchar.h> +#include <wchar.h> + +size_t mbrtoc16(char16_t *restrict pc16, const char *restrict s, size_t n, mbstate_t *restrict ps) +{ + static unsigned internal_state; + if (!ps) ps = (void *)&internal_state; + unsigned *pending = (unsigned *)ps; + + if (!s) return mbrtoc16(0, "", 1, ps); + + /* mbrtowc states for partial UTF-8 characters have the high bit set; + * we use nonzero states without high bit for pending surrogates. */ + if ((int)*pending > 0) { + if (pc16) *pc16 = *pending; + *pending = 0; + return -3; + } + + wchar_t wc; + size_t ret = mbrtowc(&wc, s, n, ps); + if (ret <= 4) { + if (wc >= 0x10000) { + *pending = (wc & 0x3ff) + 0xdc00; + wc = 0xd7c0 + (wc >> 10); + } + if (pc16) *pc16 = wc; + } + return ret; +} diff --git a/contrib/libs/libc_compat/ubuntu_14/mbrtoc32.c b/contrib/libs/libc_compat/ubuntu_14/mbrtoc32.c index e7189170c4..9b6b236739 100644 --- a/contrib/libs/libc_compat/ubuntu_14/mbrtoc32.c +++ b/contrib/libs/libc_compat/ubuntu_14/mbrtoc32.c @@ -1,13 +1,13 @@ -#include <uchar.h> -#include <wchar.h> - -size_t mbrtoc32(char32_t *restrict pc32, const char *restrict s, size_t n, mbstate_t *restrict ps) -{ - static unsigned internal_state; - if (!ps) ps = (void *)&internal_state; - if (!s) return mbrtoc32(0, "", 1, ps); - wchar_t wc; - size_t ret = mbrtowc(&wc, s, n, ps); - if (ret <= 4 && pc32) *pc32 = wc; - return ret; -} +#include <uchar.h> +#include <wchar.h> + +size_t mbrtoc32(char32_t *restrict pc32, const char *restrict s, size_t n, mbstate_t *restrict ps) +{ + static unsigned internal_state; + if (!ps) ps = (void *)&internal_state; + if (!s) return mbrtoc32(0, "", 1, ps); + wchar_t wc; + size_t ret = mbrtowc(&wc, s, n, ps); + if (ret <= 4 && pc32) *pc32 = wc; + return ret; +} diff --git a/contrib/libs/libc_compat/ubuntu_14/secure_getenv.cpp b/contrib/libs/libc_compat/ubuntu_14/secure_getenv.cpp index 947fc3eb5a..14e3e90906 100644 --- a/contrib/libs/libc_compat/ubuntu_14/secure_getenv.cpp +++ b/contrib/libs/libc_compat/ubuntu_14/secure_getenv.cpp @@ -1,12 +1,12 @@ -#include <stdlib.h> - -#include "glibc.h" - -extern "C" { - char *secure_getenv(const char *name) noexcept { - if (NUbuntuCompat::GetGlibc().IsSecure()) { - return nullptr; - } - return getenv(name); - } -} +#include <stdlib.h> + +#include "glibc.h" + +extern "C" { + char *secure_getenv(const char *name) noexcept { + if (NUbuntuCompat::GetGlibc().IsSecure()) { + return nullptr; + } + return getenv(name); + } +} diff --git a/contrib/libs/libc_compat/ubuntu_14/timespec_get.c b/contrib/libs/libc_compat/ubuntu_14/timespec_get.c index 806d87f3d8..742b62ec84 100644 --- a/contrib/libs/libc_compat/ubuntu_14/timespec_get.c +++ b/contrib/libs/libc_compat/ubuntu_14/timespec_get.c @@ -1,10 +1,10 @@ -#include <time.h> - -/* There is no other implemented value than TIME_UTC; all other values - * are considered erroneous. */ -int timespec_get(struct timespec * ts, int base) -{ - if (base != TIME_UTC) return 0; - int ret = clock_gettime(CLOCK_REALTIME, ts); - return ret < 0 ? 0 : base; -} +#include <time.h> + +/* There is no other implemented value than TIME_UTC; all other values + * are considered erroneous. */ +int timespec_get(struct timespec * ts, int base) +{ + if (base != TIME_UTC) return 0; + int ret = clock_gettime(CLOCK_REALTIME, ts); + return ret < 0 ? 0 : base; +} diff --git a/contrib/libs/libc_compat/ubuntu_14/ya.make b/contrib/libs/libc_compat/ubuntu_14/ya.make index fc770dd4b4..7355c4ad9d 100644 --- a/contrib/libs/libc_compat/ubuntu_14/ya.make +++ b/contrib/libs/libc_compat/ubuntu_14/ya.make @@ -1,5 +1,5 @@ -LIBRARY() - +LIBRARY() + WITHOUT_LICENSE_TEXTS() LICENSE(BSD-3-Clause) @@ -9,34 +9,34 @@ OWNER( g:contrib g:cpp-contrib ) - -NO_PLATFORM() -NO_RUNTIME() +NO_PLATFORM() + +NO_RUNTIME() + +NO_UTIL() -NO_UTIL() - -DISABLE(NEED_PLATFORM_PEERDIRS) +DISABLE(NEED_PLATFORM_PEERDIRS) DISABLE(OPENSOURCE_EXPORT) - + IF (OS_SDK == "ubuntu-14") PEERDIR( build/platform/linux_sdk ) - SRCS( - aligned_alloc.c - c16rtomb.c - c32rtomb.c - getauxval.cpp - mbrtoc16.c - mbrtoc32.c - secure_getenv.cpp - timespec_get.c - ) + SRCS( + aligned_alloc.c + c16rtomb.c + c32rtomb.c + getauxval.cpp + mbrtoc16.c + mbrtoc32.c + secure_getenv.cpp + timespec_get.c + ) SRC_CPP_PIC( glibc.cpp -fno-lto ) -ENDIF() - -END() +ENDIF() + +END() |