440 / 97 / 42
Регистрация: 04.10.2011
Сообщений: 346
|
||||||
1 | ||||||
Getwchar stack smashing detected11.12.2018, 21:56. Показов 6439. Ответов 25
Всем привет. Кто сможет объяснить что происходит, вот этот код:
Кто подскажет где я умудрился ему стек переполнить?
0
|
11.12.2018, 21:56 | |
Ответы с готовыми решениями:
25
stack smashing detected Stack smashing detected + Массивы + Random Stack smashing detected. Ребята, перемешка данных, что не так? *** stack smashing detected ***: <unknown> terminated, программа завершает работу на цикле |
923 / 639 / 198
Регистрация: 08.09.2013
Сообщений: 1,693
|
|
12.12.2018, 21:52 | 2 |
Похоже, это баг libc, так как clang демонстрирует подобное поведение.
То, что getwchar() редко используется, мало их оправдывает. Увеличение стека с 8 до 100 К позволяет в несколько раз удлинить входной поток. Но все равно выскакивает либо корка, либо переполнение стека. Добавлено через 2 минуты libc6:amd64 2.27-8 gcc (Debian 8.2.0-9) 8.2.0 Добавлено через 16 минут А вот у более старой libc6:amd64 2.13-38 все в порядке
1
|
12.12.2018, 22:08 | 3 | |||||||||||||||
Нет. Это не бага, а "фишка" потоков в Си. В винде и макоси отошли от стандарта и решили исправить эту "фишку"(в винде вообще сильно расширили "многобайтное")
Они бывают "неориентированные", "узкой ориентации" и "широкой ориентации" Так вот, пока поток только открыт, но ещё не использовался - он "неориентированный" и первый вызов к-либо функции ввода/вывода "ориентирует" его в соотв. с этой функцией. Например(учтите, что getwchar() обращается к fgetwc()):
setlocale, по всей видимости взаимодействует с открытыми stdin/stdout переводя их "направленность" в значение по дефолту (узкое), потому и косяк вылазит при wide-char работе. Для кода ТС стоит убрать setlocale() - ошибка исчезнет, стоит обратиться wide-функцией к stdin до вызова setlocale() - ошибка тоже исчезнет: Кликните здесь для просмотра всего текста
3
|
923 / 639 / 198
Регистрация: 08.09.2013
Сообщений: 1,693
|
|
12.12.2018, 22:25 | 4 |
Интересная фишка. Старые libc об этом еще не знали?
По мне, это явный баг. Пусть тогда проверяют ориентацию потока и возвращают ошибку.
0
|
12.12.2018, 22:34 | 5 |
Они её "обходили", по примеру макосей и виндов, при этом отходя от стандарта. А может это сами стандарты поменялись(решили таким неудобным макаром упорядочить "узких" и "широких")
Надо попробовать без freopen() через stat() и setmode(). Вроде, не меняя то, что вернёт stat() и зарядив это в setmode можно "сбросить" ориентированность. Так же что-то читал про сброс буферов, персонально по stdin/stdout
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
13.12.2018, 20:12 | 6 |
fwide(stdin, 0) возвращает 0 - т.е. "без ориентации" как до, так и после setlocale() в этом примере. Правда если сделать fwide(stdin, 1) до setlocale() все работает хорошо. Получается, что если setlocale() и ставит какие-то флаги для stdin , то делает это как-то молча. ИМХО баг.
1
|
13.12.2018, 23:49 | 7 |
Нифига не понимаю где эта самая "направленность" хранится.
Прогнал код через strace - c setlocale и без. Да, setlocale дважды открывает свои файлы /usr/lib/locale/locale-archive и /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache и только потом (перед первым использованием stdin) вызывается stat() и read() для stdin`а открытого сразу execve(наша_косячная_прога) Выхлоп стартап-кода вырезал - там всё одинаково. Косячный Кликните здесь для просмотра всего текста
brk(NULL) = 0x55e2d88b4000 brk(0x55e2d88d5000) = 0x55e2d88d5000 open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_dev=makedev(8, 1), st_ino=5247872, st_mode=S_IFREG|0644, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=3144, st_size=1679808, st_atime=2018-12-13T21:26:50+0500.124037805, st_mtime=2018-03-20T13:00:34+0500.821409394, st_ctime=2018-03-20T13:00:34+0500.821409394}) = 0 mmap(NULL, 1679808, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5456828000 close(3) = 0 open("/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache", O_RDONLY) = 3 fstat(3, {st_dev=makedev(8, 1), st_ino=5251089, st_mode=S_IFREG|0644, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=56, st_size=26258, st_atime=2018-12-13T21:26:50+0500.556039947, st_mtime=2018-01-14T15:39:44+0500, st_ctime=2018-03-20T12:57:18+0500.885313523}) = 0 mmap(NULL, 26258, PROT_READ, MAP_SHARED, 3, 0) = 0x7f54569d5000 close(3) = 0 fstat(0, {st_dev=makedev(0, 17), st_ino=4, st_mode=S_IFCHR|0620, st_nlink=1, st_uid=1000, st_gid=5, st_blksize=1024, st_blocks=0, st_rdev=makedev(136, 1), st_atime=2018-12-14T01:25:12+0500.476080882, st_mtime=2018-12-14T01:25:12+0500.476080882, st_ctime=2018-12-14T01:10:19+0500.476080882}) = 0 read(0, "123123\n", 1024) = 7 read(0, "\n", 1024) = 1 read(0, "1231\n", 1024) = 5 lseek(0, -5, SEEK_CUR) = -1 ESPIPE (Illegal seek) exit_group(0) = ? +++ exited with 0 +++ Без setlocale Кликните здесь для просмотра всего текста
fstat(0, {st_dev=makedev(0, 17), st_ino=4, st_mode=S_IFCHR|0620, st_nlink=1, st_uid=1000, st_gid=5, st_blksize=1024, st_blocks=0, st_rdev=makedev(136, 1), st_atime=2018-12-14T01:18:16+0500.476080882, st_mtime=2018-12-14T01:18:16+0500.476080882, st_ctime=2018-12-14T01:10:19+0500.476080882}) = 0 brk(NULL) = 0x56344f007000 brk(0x56344f028000) = 0x56344f028000 read(0, "12311111111111111111111111111\n", 1024) = 30 lseek(0, -20, SEEK_CUR) = -1 ESPIPE (Illegal seek) exit_group(0) = ? +++ exited with 0 +++ Учитывая, что работа идёт через read(), которому до лампочки всё(просто поток байт), то рыть надо сам libc Просто жутко интересно, вроде должно пахать - ан нет... Обходных манёвров уже насобирали, а вот что бы понять суть...
0
|
440 / 97 / 42
Регистрация: 04.10.2011
Сообщений: 346
|
|
14.12.2018, 00:00 [ТС] | 8 |
Да вот суть хотелось бы понять. У самого у меня квалификации не хватит разобраться я к сожалению только в начале пути. Но с удовольствием понаблюдаю за дискуссией.
0
|
14.12.2018, 00:03 | 9 |
Покопался в fwide() - мультибайт расширяет привычную нам структуру FILE, там появляется и свой буфер, и привязывается iconv и ещё что-то... И, самое главное, то, чем манипулирует fwide() - поле _mode (fwide его нормализирует в -1,0,1 , обеспечивает блокировки, проверки и т.п.)
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
||||||
14.12.2018, 09:38 | 10 | |||||
Покрайней мере у меня оно падает именно в libc при выходе.
А вообще надо glibcшникам баг открыть, пусть сами ковыряются.
1
|
14.12.2018, 09:54 | 11 |
Думаю дело не в этой функции. Неверно инициализируются FILE структуры... Надо будет сравнить содержимое stdin до вызова setlocale и и после. Так же глянуть в какой именно момент при fgetwc устанавливается "направленность" потока.
Что-то и где-то они забыли проинициализировать... Если же поменять if (delta != 0) на if (delta > 0), то вместо вылета будем получать WEOF или к-нить errno, что тоже не красиво.
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|||||||||||
14.12.2018, 10:28 | 12 | ||||||||||
Я и не пытался понять где первоисточник граблей. Просто смотрю отладчиком где оно падает. В моем листинге 29 стока. Вызывается ф-я do_length() из iofwide.c вот она:
Добавлено через 20 минут Не. На вскидку (зуба не дам) фиксить надо 9ю строку. Думаю там должно быть такое.
Добавлено через 1 минуту Но, нужно глубже вникать в это, а что-то не хочется
0
|
14.12.2018, 20:07 | 13 | |||||
Бу-га-га...
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
14.12.2018, 21:16 | 14 |
setlocale() не виноватая вообще. Она и близко не прикасается к stdin. Баг будет проявляться на всех кодировках с символами переменной длины т.е. когда ф-ция do_encoding() возвращает -1;
Запустил пересборку glibc с патчем из 12го сообщения. Дома ноут старенький, минут 7 еще ждать Добавлено через 24 минуты Дождался. Вот это помогает, и вроде ничего не ломает. Код
--- glibc-2.28.old/libio/wfileops.c 2018-08-01 08:10:47.000000000 +0300 +++ glibc-2.28/libio/wfileops.c 2018-12-14 21:03:17.759346239 +0300 @@ -480,14 +480,14 @@ wint_t _IO_wfile_sync (FILE *fp) { - ssize_t delta; + size_t delta; wint_t retval = 0; /* char* ptr = cur_ptr(); */ if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base) if (_IO_do_flush (fp)) return WEOF; - delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end; + delta = fp->_wide_data->_IO_read_end - fp->_wide_data->_IO_read_ptr; if (delta != 0) { /* We have to find out how many bytes we have to go back in the Да, и в качестве воркэраунда имхо лучшим вариантом будет __fpurge(stdin); перед выходом.
2
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
15.12.2018, 10:11 | 16 |
Да, все именно так. Очень похоже на банальную описку.
Так для всех остальных случаев clen (это признак кодировки с переменным размером символов, который возвращает do_encoding() и именно его устанавливает fwide() глядя на текущую локаль)не отрицательный, и этот код просто не отрабатывает. Что меня больше всего удивляет, коду более 15 лет и я не смог нагуглить ни одного упоминания о проблеме.
0
|
923 / 639 / 198
Регистрация: 08.09.2013
Сообщений: 1,693
|
|
15.12.2018, 15:42 | 17 |
То, что при работе с utf-8 локалью широкие символы используют редко - не новость, но тем не менее то, что "детский" баг в широко используемой функции обнаружил уважаемый moskitos80 через 15 лет - действительно поражает!
Поленится или нет moskitos80 открыть баг glibc, но патч prik будет в любом случае востребован.
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
15.12.2018, 18:13 | 18 |
Проблема все-таки не в ней. А в коде выполняемом после return 0; где среди прочих деструкторов делают аналог fflush() для всех открытых FILE*. Если для обычных файлов и stdout/stderr это понятно логично и правильно, то зачем они делают это для stdin я не понимаю. Ну прочитали мы сколько-то "лишних" байт из stdin и что с ними можно сделать при выходе кроме как тихо выкинуть?
Думаю, что хороший патч кроме этого должен вообще отключать всю цепочку с fflush() для FILE* открытых только для чтения. Но там пляски со сбросом буферов тесно связаны с освобождением памяти - страшно трогать.
2
|
15.12.2018, 20:15 | 19 |
К стати это не оно?
https://www.linux.org.ru/forum/general/12361599 https://sourceware.org/bugzill... i?id=20568
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
15.12.2018, 20:30 | 20 |
По симптомам и трасам именно оно.
Печально, что в багзиле баг открыт с 16го кода и авторам пох
1
|
15.12.2018, 20:30 | |
15.12.2018, 20:30 | |
Помогаю со студенческими работами здесь
20
Ошибка: "Unhandled exception: Stack cookie instrumentation code detected a stack-based buffer overrun" [bcc32 Error] File1.cpp(19): E2316 'Stack<T>::Stack()' is not a member of 'Stack<T>' Есть ли связь между STL-stack и stack - высокопроизводительная память? error C2440: 'return' : cannot convert from 'stack<X>' to 'stack<X> *' Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |