LINUX.ORG.RU
ФорумTalks

2 дня на это

 ,


1

2

(нехочу засорять девелоп ветку форума)

у меня просто мозг взорвался уже
два дня я по 60000 строкам кода ищу откуда у меня течет память, часть кода скопипащена из другого проекта где 100% нет никаких утечек
таки выяснил

char *http_length ="";
sprintf(http_length,"test %i\r\n", strlen("test\n"));
printf(http_length);

ктото мне может объяснить как этот код может Не давать утечек памяти
я уже раз 50 пересобрал «исходный проект» где нет утечек с этим кодом, и в упор понять не могу
КАК это возможно, почему в моем коде это течет, а там нет, вот нет я в цикле это 500000 раз запускал тыкал в разные куски кода в «исходном проекте» и делаю тоже самое у меня-там не течет, у меня течет
Помогите спасите

c
два дня я по 60000 строкам кода ищу откуда у меня течет память

А чего ты хотел?

Unununij ★★★★ ()

Я давно уже не занимаюсь системным программированием, так что не и пинайте если что. По-моему, представленный код в принципе не совсем корректен.

Потому что при работе с указателями, логика обычно тремя: выделить память функцией malloc, произвести какие то нужные нам действия, освободить память функцией free.

Что у нас происходит здесь: мы неявно выделяем память в первой строчке. Сколько будет реально выделено и где именно, в куче или стеке - непонятно. Этот по видимому происходит в зависимости от компилятора и его настроек. Если выделение происходит в стеке, то утечки не будет. Если в куче - то произойдет. Явно освобождать память вызовом free, которую мы явно не выделяли перед этим malloc-ом - тоже неверно.

DawnCaster ()

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

какимто чудом(или так задумано) задевает ту память куда идет утечка от вышеуказанного кода, поэтому в оригинальном коде нет утечек

некст лвл г-но кода на Си какойто (я конечно встречал и раньше магию с «насрать в память» и читать из другого буфера, на основе этого делали даже «зищиты» от взлома программ, но в 2017, божечки)

сгорел

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

Пардон, с телефона пишу, автоисправление косячит. Ну так вот. Предложенный код я бы исправил так: Первую строчку заменил бы на вызов malloc с указанием размера, и добавил бы в конце free.

DawnCaster ()

Ну так оно же строго определено не будет, если это в цикле будет.

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

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

эта ошибка на уровне 5-го класса средней школы, если не детского сада, исправление более чем очевидно

я про то что-как это вообще могло работать, этож какие познания Си надо иметь чтоб в 2015-16 году писать такой код

причем познания не просто выделения памяти, а целевой платформы(проекты не для x86 и не для обычной RAM(несколько рамов быстрые медленные отдельными памятями в которых выделяется память по очереди))

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

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

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

Про ошибку на уровне пятого класса средней школы вы загнули. Там такому не и учат, повезет если бейсик или паскаль. Это ошибка первого или второго курса универа\техникума на программерской специальности.

DawnCaster ()

А статический анализатор эту проблему бы выявил?

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

компилятор вроде должен warning давать при присвоении (char*) литерала.

mittorn ★★★★★ ()

Да конструкция в целом не верна, о чем уже написали. Хз как оно работает. Это скорее тот самый момент, когда недостаток в одном месте компенсируется перезакладом в другом, и иногда приводит к непредсказуемым результатам.
Напомнило, я как-то занимался рефакторингом своего (не только своего) кода проекта который писался ну очень в сжатые строки. Проект в целом норм работал не один год, падумаеш иногда (очень редко) с корой падали, все на «темные электрические силы» списывали, главное ущерба по данным было ноль. Вот как раз одно из запомнившихся мест близкое к вашему, только там что-то в духе char[N], где N ну вообще никаким образом не соответствует предполагаемым входным данным, т.е. ни в меньшую ни в большую сторону, вообще с потолка число было. Задал вопрос человеку который это писал, но он конечно тоже уже не вспомнил почему именно так получилось. :)

Рекомендую и исходный проект все-таки прогнать, а то малоли чего там еще не познанного, а вы не в курсе.

ЗЫ Ну как минимум valgrind указал бы на ошибку.

anc ★★★★★ ()

У тебя код плохой, тебе повезло ещё, что течёт, а не сегфолтится. Переписывай.

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

Повезло? Хм, я наоборот рад сегфолтам — время поиска ошибки сокращается в разы.

JacobTwoTwo ()

Где выделение памяти? sprintf() не выделяет память. Для выделения памяти специально существуют malloc()/calloc()/realloc().

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

Если сборка дебажная, то корка - дело приятное. А если там всё оптимизировано и отстрипанно по самое не балуйся?

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

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

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

Что у нас происходит здесь: мы неявно выделяем память в первой строчке

Нет, никакого выделения памяти тут нет. Строка

""
лежит где-то в области глобальных констант, а до этого, прямо лежит в исходнике. Выделение на стеке будет только под сам указатель http_length, не под строку. Потом этому указателю присвоится адрес этой строки, дальше попытка пейсать в эту область. Если она не защищена - то что-то туда по этому адресу запишется. Может и работать.

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

Не должно если не писать по этому указателю

mittorn ★★★★★ ()

два дня я по 60000 строкам кода ищу откуда у меня течет память

а мог бы просто переписать на раст или ди

umren ★★★★★ ()

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

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

На переписывание на D уйдёт больше времени, чем на отлов ошибки. К тому же D сырой.

mxfm ()

В каком проекте ты откопал это говно?

BceM_IIpuBeT ★★★★ ()

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

Может это ошибка программы-отладчика утечек памяти (в смысле указывает на ложное место)?

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

Не понял. D на текущий момет сыроват: есть куча ошибок компиляции в шаблонах, в общих ситуациях т.н. на форумах «corner cases». Есть фундаментальные проблемы с поддержкой динамических библиотек (хотя их можно в каких-то местах избежать слинковывая в месте, но например проблему плаггинов так нельзя решить).

Есть проблемы с code-bloat. Например несколько последних постов в багзилле - человек не может применить D на embedded платформе, потому что простые объявления классов сильно раздувают объём бинарика.

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

При глубоком рассмотрении D совсем не такой очаровательный как при поверхностном ознакомлении.

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

куча ошибок компиляции в шаблонах

враки

Есть фундаментальные проблемы с поддержкой динамических библиотек

что за проблемы?

D на embedded платформе

поржал

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

и зачем язык в котором над применением в embedded платформе можно только поржать?

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

D на embedded платформе

поржал

Когда только начали пихать java в контролеры, я тоже был в акуе недоумении. Однако сейчас уже полным ходом пользуют. И согласился с тем что большинству автоматизаторов это удобнее чем asm или c. А то они там такое воротили.

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

враки

Их много

что за проблемы?

Большие

поржал

Вот обсуждение в багзилле о code bloat, которая мешает на малых платформах.

Ты, что познакомился с языком вчера-позавчера?

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

Ты, что познакомился с языком вчера-позавчера?

на выходных прошлых

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

Вот обсуждение в багзилле о code bloat, которая мешает на малых платформах.

последний коммент читай, все пофиксили давно

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

тут тоже, но все жрут пол века

Так они не возникают так часто в использовании.

на выходных прошлых

Оно и видно.

последние коммент читай, все пофиксили давно

Тот пофиксили, другие остались. Там проблемы с рантаймом, со скоростью, с шаблонами, с документацией. Кроме того, язык нестабилен - его часто понемногу меняют, вскрываются какие-то баги и т.п. Это реально надоедает. Я не уверен, что если пишу код, он заработает в следующей версии, или опять что-то не изменят. Ну и напоследок, D привлекает своей компактностью, но на самом деле там полно подводных камней.

mxfm ()

Не читал комментарии, но твой код

char *http_length ="";
sprintf(http_length,"test %i\r\n", strlen("test\n"));
printf(http_length);

это кошмар. Здесь надо самому выделять память и потом ее освобождать. Да и не безопасно используешь функцию printf.

Как вариант (конечно, не самый идеальный)

char *http_length = malloc(256);
http_length[0] = '/0'; // на всякий случай)
sprintf(http_length,"test %i\r\n", strlen("test\n"));
printf("%s", http_length);
free(http_length);

Если лень самому выделять память, можно использовать GString из библиотеки glib.

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

А почему 256? А не 257? или не 100? Или не 50 ? Не, ну серьезно, потом на грабли будем еще раз наступать?

anc ★★★★★ ()
Последнее исправление: anc (всего исправлений: 1)

char *http_length ="";

WAT

sprintf

Это плохая функция, s/sprintf/snprintf Вызывайте snprintf(nullptr, 0, fmt, args...) — возвратит размер буфера, который необходимо выделить. А дальше уже выделяйте на стеке или в куче и в него пишите.

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

Это я понимаю) выше еще упомянули про snprintf)

В Linux же указали максимальный размер пути 256) Я вот только не знаю, сейчас то можно использовать больше 256 байт или нет?

Лично, я использую либо GString из библиотеки glib для Си, либо std::string в C++.

neon1ks ★★ ()

char *http_length ="";

Указывает на кусок памяти, где выделен один байт «\0». Кроме того, компилятор должен ругнуться на эту строку, т.к. там нет const, а указывает он на константные данные.

sprintf(http_length,«test %i\r\n», strlen(«test\n»));

strlen возвращает size_t, а %i ожидает signed int. Нет проверки на размер буфера, в который будет происходит форматирование строки.
И вообще, это какой-то ужасный вендовый (привет «\r\n») говнокод.

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

компилятор вроде должен warning давать при присвоении (char*) литерала.

Разве что приплюснутый...

andreyu

Кроме того, компилятор должен ругнуться на эту строку, т.к. там нет const, а указывает он на константные данные.

У ТС вроде чистая сишка. Родить предупреждение там даже с -Wall/-pedantic скорее всего не получится (могу ошибаться и в каком-то стандарте может и получится).

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

вендовый

Судя по переменной http_length, здесь замешан HTTP протокол, в котором используется как раз CRLF в качестве разделителя строк.

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

Думаете, капает на D? Нет, дело в сырости толстого слоя земли над ним.

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

Кроме того, компилятор должен ругнуться на эту строку, т.к. там нет const, а указывает он на константные данные.

в оригинальном С нет такого ключевого слова

тем не менее, вылететь почти обязан: sizeof(http_length) == 1

strlen возвращает size_t, а %i ожидает signed int.

приведётся без малейших проблем

next_time ★★★★★ ()

ух писателей на «эталонном Си в вакууме» прибыло

Стандарт Си такой какой встроен в компилятор

у меня «порт gcc(свежего) на Не x86 архитектуру(свои команды процессора и менеджмент памяти свой)»
asprintf vsprintf как и многие другие функции стандарта/POSIX стандарта не реализованы
хорошо что хоть спринтф есть, а тоб пришлось еще и «в память срать»

код который я привел, я также тестил на gcc-x96_64 на линуксе и он естественно сегфолтился(возможно в 32 битном компиляторе не будет, или в другой версии gcc)(когда на gcc-под платформу он работает нормально)

работа такого кода зависит от компилятора
и в моем случае видя Огромный проект который весь написан на такой магии- либо тот программист «чтото знает» либо удача(удача написать тыщи логических конструкций опираясь на ошибочный код-ага какже)

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

Здесь явное переполнение буфера. Независимо от компилятора это - ошибка.

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