LINUX.ORG.RU

musl libc 1.0

 ,


1

2

Сегодня вышла версия 1.0 musl, свободной реализации стандартной библиотеки языка C. musl реализует стандарты ISO C и Posix, плюс набор расширений используемых в системах на базе Linux. Код распространяется под лицензией MIT (начиная с версии 0.9.). Основные изменения:

  • нововведения
    • поддержка mips softfloat ABI;
    • legacy setkey и API шифрования для DES;
    • поддержка BSD версии struct tcphdr в дополнение к GNU версии;
    • поддержка протоколов ipv6, icmpv6 в семействе функций getprotoent;
  • поддержка новых архитектур
    • sh (SuperH);
    • x32 (ILP32 ABI для x86_64);
  • совместимость
    • улучшена поддержка компилятора c89 в math.h;
    • удалены предупреждения об ошибках в публичных заголовках;
    • добавлены отсутствующие возможности для LFS64 API;
  • исправление ошибок
    • переполнение буфера в printf;
    • ошибки округления в printf;
    • падение программы при передаче нулевого указателя в posix_spawn;
    • некорректная работа ftello;
    • некорректная работа wcsxfrm при n = 0;
    • ошибки в install.sh, в некоторых случаях, приводящие к краху системы при обновлении libc;
    • некорректная работа флага ntfw FTW_MOUNT;
    • отрицательные коды ошибок в ptsname/ptsname_r;
    • некорректная работа getprotoent;
    • неправильные код ошибки вызвращаемой readdir когда директория удалена;
  • архитектурно-специфические ошибки
    • некорректная работа fesetenv(FE_DFL_ENV) на i386 и x86_64;
    • strerror(EDQUOT) не работал на mips;
    • recvmsg/sendmsg не работал на powerpc;
    • sysv ipc не работал на powerpc и mips;
    • statfs/statvfs не работали на mips;
    • sigaltstack не работал на mips;

Список изменений по версиям

Сравнение различных реализаций libc

Скачать исходный код

>>> Подробности

★★★★★

Проверено: Shaman007 ()
Последнее исправление: cetjs2 (всего исправлений: 2)
Ответ на: комментарий от anonymous

куясе! Я там после 2 лет писания на Си писал, считал что так
писать - мегакруто ))

Уверяю вас, вы писали не так! Здесь - умышленная обфускация, использована даже таблица обфускации, из которой по индексам выбираются определённые элементы различных типов, а индексы просчитываются совсем не тривиально. Я не зря твержу: _попробуйте_ прочитать этот код! У вас ничего не выйдет, и это не случайно.

anonymous
()
Ответ на: комментарий от anonymous

использована даже таблица обфускации
индексы просчитываются совсем не тривиально

все там тривиально и нет никакой обфускации, хотя конечно код не самый читабельный, но это скорее авторский стиль, а не желание что-то запутать

wota ★★
()
Ответ на: комментарий от anonymous

Я не зря твержу: _попробуйте_ прочитать этот код! У вас ничего не выйдет, и это не случайно.

Исходники busybox почитай. Или любого большого проекта.

devl547 ★★★★★
()
Ответ на: комментарий от wota

Ну так сделайте наконец то, что просят: распишите тот код - тогда и посмотрим, есть обфускация, или нет. Особенно над memcpy() в одни и те же области подумайте. Чо все болтают-то только? Давно бы уже расписали.

anonymous
()
Ответ на: комментарий от devl547

Исходники busybox почитай. Или любого большого проекта.

Сэр, простите, но вы ламер. Ни в одном большом проекте такого кода нет. Это ещё помимо огромного числа багов в этом коде. Пока ни распишите код, говорить с вами не о чем.

anonymous
()
Ответ на: комментарий от anonymous

Особенно над memcpy() в одни и те же области подумайте.

а что там думать - все очевидно, первый memcpy - это «шаблон» с разделителями:

	'?', '?', '?',
	' ', '?', '?', '?',
	' ', '0',
	offsetof(struct tm, tm_mday),
	' ', '0',
	offsetof(struct tm, tm_hour),
	':', '0',
	offsetof(struct tm, tm_min),
	':', '0',
	offsetof(struct tm, tm_sec),
	' ', '?', '?', '?', '?', '\n'

а второй «memcpy() в одни и те же области» - начало заполнения результата, а offsetof(struct tm, tm_mday) и пр. - трюк, чтоб сэкономить на размере кода

wota ★★
()
Ответ на: комментарий от devl547

Анонимуса не трожь, грязный регистрантишка.

anonymous
()
Ответ на: комментарий от anonymous

да просто там все на самом деле. Что плохо, так это форматирование кода (это обфускацией называл?)

anonymous
()
Ответ на: комментарий от anonymous

facepalm... сам то пробовал? Все там тривиально. Никакой обфускации, просто с #ifdef #else #endif выглядит монстрозно. А так - тривиальный простой код.

держи я тебе его даже очистил от #ifdef SAFE_ASCTIME_R

Можешь повторить эксперимент с другой частью веток.

char *asctime_r(register const struct tm *__restrict ptm,
                register char *__restrict buffer)
{
    int tmp;

    memcpy(buffer,     at_data + 3*(7 + 12) - 3,        sizeof(at_data) + 3 - 3*(7 + 12));
    memcpy(buffer,     at_data + 3 * ptm->tm_wday,      3);
    memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
    
    buffer += 23;
    tmp = ptm->tm_year + 1900;

    do {
        *buffer = '0' + (tmp % 10);
        tmp /= 10;
    } while (*--buffer == '?');

    do {
        --buffer;
        tmp = *((int *)(((const char *) ptm) + (int) *buffer));
        {
            *buffer = '0' + (tmp % 10);
            buffer[-1] += (tmp/10);
        }
    } while ((buffer -= 2)[-2] == '0');

    if (*++buffer == '0') {		/* Space-pad day of month. */
        *buffer = ' ';
    }

    return buffer - 8;
}

а индексы просчитываются совсем не тривиально.

А если головой подумать? Имена 7 дней недели, 12 месяцев года, по 3 символа каждый. Кстати то, что автор писал именно так (3*(7 + 12)) говорит о том, что он как раз заботился о том, чтоб код был более читаем, эти индексы сразу глазом цепляются и становится ясно. Сложнее было бы понять что такое (57).

anonymous
()
Ответ на: комментарий от wota

а второй «memcpy() в одни и те же области» - начало заполнения
результата

Вы по-подробнее отвечайте. Я вас конкретно спрашиваю:

memcpy(buffer,     at_data + 3*(7 + 12) - 3,        sizeof(at_data) + 3 - 3*(7 + 12));
memcpy(buffer,     at_data + 3 * ptm->tm_wday,      3);
Зачем здесь, например, копировать в одну и ту же область, если в первой строчке можно было сразу на 3 вперёд отступить, и избавиться от -3/+3? Тоже для экономии кода? А таблицу создавать из разных типов данных, и выбирать их оффсетами, и потом касты делать, вместо использования структур - это, по вашему, преследовало какую цель?

anonymous
()
Ответ на: комментарий от anonymous

держи я тебе его даже очистил от #ifdef SAFE_ASCTIME_R

О, кто-то всё-таки, «оторвал зад от стула», и, что характерно - именно анонимус. :) Хорошее начало. Только, если можно, оставьте SAFE_ASCTIME_R, так как там именно этот вариант используется. Фрагмент я специально выбрал маленький - зачем утомлять людей большими фрагментами, если и тут всё видно. И просил его посмотреть не вас, а тех, кто больше всех орёт. Но раз уж вы взялись - что ж, верните SAFE_ASCTIME_R, добавьте коменты по каждому фрагменту (кусок маленький! это не долго), а потом, скажите, где эта штука упадёт, если вызывать её из разных тридов, когда buffer один и тот же.

anonymous
()
Ответ на: комментарий от anonymous

Это, унучок, старинный индейский прием. Скопировать сначала бОльшую часть (шаблон с разделителями), потом вставлять в области уже имена дней и месяцев.

А если б ты еще башкой подумал, то понял бы зачем тут создана таблица со смещениями в структуре. Привыкли к .net и 16 гигам оперативы, мля.

anonymous
()
Ответ на: комментарий от anonymous

Но раз уж вы взялись - что ж, верните SAFE_ASCTIME_R, добавьте коменты по каждому фрагменту (кусок маленький! это не долго), а потом, скажите, где эта штука упадёт, если вызывать её из разных тридов, когда buffer один и тот же.

Ты дурной чтоли? причем тут разне треды и один буфер? ААА ... не читал, но сделала выводы. Малчик, читай коммент автора выше. Уверяю с SAFE_ASCTIME_R код ничуть не сложнее, просто доп проверки за вылеты и все.

anonymous
()
Ответ на: комментарий от anonymous

Зачем здесь, например, копировать в одну и ту же область, если в первой строчке можно было сразу на 3 вперёд отступить

«здесь» код вообще практически никогда не используется, т.к. в коде захардкожено:

#define SAFE_ASCTIME_R		1

и очень маловероятно, что кто-то полезет править, потому почти наверняка автор просто сделал по аналогии с базовым вариантом, где есть if и потому нельзя пропустить три символа, чтоб не допустить мусора в результате

А таблицу создавать из разных типов данных, и выбирать их оффсетами, и потом касты делать, вместо использования структур - это, по вашему, преследовало какую цель?

тип там один - unsigned char, зачем так сделано я уже писал - более компактный код, попробуй сделать свой вариант и увидишь

wota ★★
()
Ответ на: комментарий от anonymous

упадёт, если вызывать её из разных тридов, когда buffer один и тот же.

/* This is generally a good thing, but if you're _sure_ any data passed will be

* in range, you can #undef this. */ #define SAFE_ASCTIME_R 1

и причем тут разные потоки, дятло?

anonymous
()
Ответ на: комментарий от anonymous

Но раз уж вы взялись - что ж, верните SAFE_ASCTIME_R, добавьте коменты по каждому фрагменту (кусок маленький! это не долго), а потом, скажите, где эта штука упадёт, если вызывать её из разных тридов

LOL, SAFE в данном случае просто проверяет значения из ptm

wota ★★
()
Ответ на: комментарий от wota

LOL, SAFE в данном случае просто проверяет значения из ptm

Мля, я и не говорил, что SAFE к чему-то относится, я лишь попросил очистить от ифдефов по-другому, так как там #define SAFE_ASCTIME_R стоит, а анонимус очистил без него. Хватит уже отвечать не читая, чтоль.

anonymous
()
Ответ на: комментарий от anonymous

Хватит уже отвечать не читая, чтоль.

ага, а слово «тридов» ты просто так сказал, ну да ладно, если тебе еще что по коду не понятно - спрашивай

wota ★★
()
Ответ на: комментарий от anonymous

а тебе уже 2 раза сказали, что код с SAFE отличается от кода без SAFE тем, что в SAFE проверяются данные из ptm, все.

char *asctime_r(register const struct tm *__restrict ptm,
                register char *__restrict buffer)
{
    int tmp;

    memcpy(buffer,          at_data + 3*(7 + 12),           sizeof(at_data) - 3*(7 + 12));

    if (((unsigned int)(ptm->tm_wday)) <= 6) { // проверка
        memcpy(buffer,      at_data + 3 * ptm->tm_wday,     3);
    }

    if (((unsigned int)(ptm->tm_mon)) <= 11) { // проверка
        memcpy(buffer + 4,  at_data + 3*7 + 3 * ptm->tm_mon, 3);
    }

    buffer += 19;
    tmp = ptm->tm_year + 1900;
    if (((unsigned int) tmp) < 10000) { // проверка
        buffer += 4;
        do {
            *buffer = '0' + (tmp % 10);
            tmp /= 10;
        } while (*--buffer == '?');
    }

    do {
        --buffer;
        tmp = *((int *)(((const char *) ptm) + (int) *buffer));
        if (((unsigned int) tmp) >= 100) { /* Just check 2 digit non-neg. */ // тут даже коммент есть
            buffer[-1] = *buffer = '?';
        } else
        {
            *buffer = '0' + (tmp % 10);
            buffer[-1] += (tmp/10);
        }
    } while ((buffer -= 2)[-2] == '0');

    if (*++buffer == '0') {		/* Space-pad day of month. */
        *buffer = ' ';
    }

    return buffer - 8;
}

+ тебе уже 3 раза объяснили, зачем в таблице смещения полей. Что еще непонятного в этом коде?

anonymous
()
Ответ на: комментарий от anonymous

чота я подумал. что от ассертов тоже не стоило чистить, а то опять сейчас скажешь что все не так.

anonymous
()
Ответ на: комментарий от anonymous

А если б ты еще башкой подумал, то понял бы зачем тут создана
таблица со смещениями в структуре. Привыкли к .net и 16 гигам
оперативы, мля.

Вот ты дятел, да если эту таблицу в структуры оформить, она бы в памяти занимала _ровно_ столько же. В крайнем случае, packed её сделать, если за выравнивания беспокоитесь.

anonymous
()
Ответ на: комментарий от anonymous

сделай. Или только свистеть можешь? Обфускация, млять.

С индексами или без код очевиден и делает то, что от него ожидают. Заполняет буфер строкой с датой.

Где вы, млять, такие беретесь? уроки то сделал на завтра?

anonymous
()
Ответ на: комментарий от wota

ага, а слово «тридов» ты просто так сказал

Не просто так, но к SAFE это никак не относилось.

ну да ладно, если тебе еще что по коду не понятно - спрашивай

Вот и ответьте, где он упадёт и почему, если вызвать из разных тридов с одним буфером. Задачка это.

anonymous
()
Ответ на: комментарий от anonymous

сделай.

В смысле, где сделать? В моём коде такого и так не бывает, а этот код не мой, тут сделать ничего не могу.

Заполняет буфер строкой с датой.

Заполняет, заполняет. Это и из названия функции следует. Вы бы лучше код прокомментировали, всякие строки типа buffer += 19; tmp = *((int *)(((const char *) ptm) + (int) *buffer)); и все прочие. А люди уж и без вас, но по этим комментам, решат, так надо писать, или не так.

anonymous
()
Ответ на: комментарий от anonymous

сделай. Или только свистеть можешь?

А ладно, уболтали, сделал:

char *__asctime(const struct tm *restrict tm, char *restrict buf)
{
        /* FIXME: change __nl_langinfo to __nl_langinfo_l with explicit C
         * locale once we have locales */
        if (snprintf(buf, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
                __nl_langinfo(ABDAY_1+tm->tm_wday),
                __nl_langinfo(ABMON_1+tm->tm_mon),
                tm->tm_mday, tm->tm_hour,
                tm->tm_min, tm->tm_sec,
                1900 + tm->tm_year) >= 26)
        {
                /* ISO C requires us to use the above format string,
                 * even if it will not fit in the buffer. Thus asctime_r
                 * is _supposed_ to crash if the fields in tm are too large.
                 * We follow this behavior and crash "gracefully" to warn
                 * application developers that they may not be so lucky
                 * on other implementations (e.g. stack smashing..).
                 */
                a_crash();
        }
        return buf;
}

Только это не я сделал, а автор musl. Ещё вопросы?

anonymous
()
Ответ на: комментарий от anonymous

Вот и ответьте, где он упадёт и почему, если вызвать из разных тридов с одним буфером

ну так буфер модифицируется, смещения заменяются на значения, которые ес-но в другом треде посчитаются за смещения, но в любом случае «если вызвать из разных тридов с одним буфером» это будет нерабочий быдлокод, и данная реализация asctime_r в этом не виновата

wota ★★
()
Ответ на: комментарий от wota

ну так буфер модифицируется, смещения заменяются на значения,
которые ес-но в другом треде посчитаются за смещения, но в
любом случае «если вызвать из разных тридов с одним буфером»
это будет нерабочий быдлокод

Да, это быдлокод, только вполне рабочий на других либах. Если в какой-то либе вызывать asctime() (без _r) из разных тридов (что даёт неспецифицированный результат), то в других либах это иногда даёт попорченную дату, и только в уклибсе - приводит к порче памяти и различным непредсказуемым вылетам.

смешно

Что именно?

anonymous
()
Ответ на: комментарий от anonymous

какой же ты идиот. Тут и комментировать нечего

сначала в буфер копируется маска с '?' так же в буфер заносятся смещения полей в структуре. Первые memcpy недеюсь не надо объяснять зачем сделаны? они просто копируют имена по 3 символа. А далее начинается непонятная тебе «магия».

сначала год - он состоит из 4 символов и находится на 19-4 позиции от буфера. Путем подъема от хвоста к голове (с 19 позиции) буфер заполняется цифрами ('0' + (tmp % 10)) пока в буфере есть '?' (та самая маска, скопированная вначале). С годом все.

Далее индексы. Индексы в буфер внесены, чтоб сделать ВСЕ ЗА ОДИН проход по этому буферу. Так как день, час, минута и секунда это числа, которые ВСЕГДА занимают 2 символа (хх, 0x, 00) (исключенние - день, для него вносится пробел (строки 384-386)), то решение: поднимаясь от хвоста (дальше после года) и встретив смещение (проверка на не '0') просто взять значение в структуре, по этому смещению, и сделать ровно то, что сделано с годом.

Так убиваются несколько зайцев,

во-первых числовые данные (год, день, час, минута, секунда) заносятся за 1 проход,

во-вторых не нужно для каждого вычислять смещение отдельно.

в-третьих благодаря tmp не нужно парить мос по поводу >10 <10 и всандаливать нули.

Вариант с safe+assertы дают доп. проверки

anonymous
()
Ответ на: комментарий от tailgunner

И что смешного в коде? Всяко лучше дрочева с memcpy.

замеряй время работы обоих вариантов, а потом подумай - хочешь ли ты настолько тормозную реализацию libc

wota ★★
()
Ответ на: комментарий от anonymous

snprintf

и можешь закопать сразу, потому что snprintf это монструзная хрень, которую некоторые не включают в легкие либы, предназначенные для, например, встраиваемых железок.

anonymous
()
Ответ на: комментарий от wota

замеряй время работы обоих вариантов, а потом подумай - хочешь ли ты настолько тормозную реализацию libc

Скорость asctime? Как говорится, «could care less, but only if paid».

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

находится на 19-4

на 23 - 4, конечно

anonymous
()
Ответ на: комментарий от tailgunner

Скорость asctime? Как говорится, «could care less, but only if paid».

у меня разница в скорости двух вариантов - в 780 раз, а этр не очень приятно, если тебе нужно, например, писать много логов, и да - тебе не надо, другим надо, на то она и libc

wota ★★
()
Ответ на: комментарий от anonymous

Тут и комментировать нечего

Я уже сказал, для чего надо комментировать:

А люди уж и без вас, но по этим комментам, решат, так надо писать, или не так.
Вот теперь пускай и решают.

Ну и, для затравки, вариант dietlibc:

char *asctime_r(const struct tm *t, char *buf) {
  /* "Wed Jun 30 21:49:08 1993\n\0" */
  *(int*)buf=*(int*)(days+(t->tm_wday<<2));
  *(int*)(buf+4)=*(int*)(months+(t->tm_mon<<2));
  num2str(buf+8,t->tm_mday);
  if (buf[8]=='0') buf[8]=' ';
  buf[10]=' ';
  num2str(buf+11,t->tm_hour);
//  if (buf[11]=='0') buf[11]=' ';
  buf[13]=':';
  num2str(buf+14,t->tm_min);
  buf[16]=':';
  num2str(buf+17,t->tm_sec);
  buf[19]=' ';
  num2str(buf+20,(t->tm_year+1900)/100);
  num2str(buf+22,(t->tm_year+1900)%100);
  buf[24]='\n';
  buf[25]='\0';
  return buf;
}

anonymous
()
Ответ на: комментарий от wota

у меня разница в скорости двух вариантов - в 780 раз

Ну что ж, затестите ещё вариант выше, из dietlibc.

anonymous
()
Ответ на: комментарий от wota

надо полную версию, с num2str, days и пр.

Надо.

#include <time.h>

static const char days[] = "Sun Mon Tue Wed Thu Fri Sat ";
static const char months[] = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ";

static void num2str(char *c,int i) {
  c[0]=i/10+'0';
  c[1]=i%10+'0';
}
anonymous
()
Ответ на: комментарий от wota

И вы таки ответьте, нормально ли, вместе неспецифицированного результата, делать порчи памяти.

anonymous
()
Ответ на: комментарий от anonymous

И вы таки ответьте, нормально ли, вместе неспецифицированного результата, делать порчи памяти.

в С - да, такой уж это ЯП, передал не то смещение, размер или полез из двух тредов куда не надо - лови сегфолт или порчу памяти

wota ★★
()
Последнее исправление: wota (всего исправлений: 1)
Ответ на: комментарий от wota

с -O2 у меня вариант musl libc в ~6 раз быстрее

Чего? snprintf() быстрее этого в 6 раз??? Да с чего бы?

в С - да, такой уж это ЯП

Вы не путайте unspecified result и undefined behaviour. Во всех остальных либах это unspecified result.

anonymous
()
Ответ на: комментарий от anonymous

:) согласен, эта элегантнее выглядит.

Как на счёт «короче», «быстрее», и «не падает при неверном использовании»?

anonymous
()
Ответ на: комментарий от anonymous

Чего? snprintf() быстрее этого в 6 раз??? Да с чего бы?

нет, код musl быстрее кода из dietlibc у меня на i7 2600K собранный gcc 4.8.2 с -O2, если быть точным

Вы не путайте unspecified result и undefined behaviour. Во всех остальных либах это unspecified result.

ну так другие либы могут хоть все функции попытаться сделать полностью thread safe, это право их разработчиков, а есть стандарт, где сказано, что asctime_r thread safe именно из-за того, что позволяет использовать разные буфера, а не один

wota ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.