- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
#include <iostream>
#include <string>
#include <string_view>
int main() {
std::string s = "Hellooooooooooooooo ";
std::string_view sv = s + "World\n";
std::cout << sv;
}
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
+4
#include <iostream>
#include <string>
#include <string_view>
int main() {
std::string s = "Hellooooooooooooooo ";
std::string_view sv = s + "World\n";
std::cout << sv;
}
https://alexgaynor.net/2019/apr/21/modern-c++-wont-save-us/
What's happening here is that s + "World\n" allocates a new std::string, and then is converted to a std::string_view. At this point the temporary std::string is freed, but sv still points at the memory that used to be owned by it. Any future use of sv is a use-after-free vulnerability. Oops! C++ lacks the facilities for the compiler to be aware that sv captures a reference to something where the reference lives longer than the referent. The same issue impacts std::span, also an extremely modern C++ type.
Странно было бы, если бы string_view, который создан как быстрая обёртка над куском существующей строки, работал иначе.
Вот именно поэтому я за Си. Там ничего просто так не дохнет.
У каждой функции как правило внятный контракт. Иногда даже на уровне одной либы они совпадают. Но в целом, когда у тебя в проге юзается несколько либ - это лютый треш, о котором постоянно надо думать.
Или я просто отупел после крестов, где я по каждой внешней функции читаю доку ровно один раз - чтобы сделать над ней RAII обёртку?
В крестах его держать под контролем ничуть не сложнее, имхо.
> пример треша
Да банально - в одной либе тебе возвращают хуйню, на которой ты должен LocalFree, во второй - просто free, в третьей - HuiPizdaFree. Где-то надо самому буфер подготовить (и позвать перед этим с нулём для оценки размера). Где-то тебе вернут указатель на кишки структуры который вообще удалять нельзя. Каждая либа вроде и консистентна, но в целом по проекту выходит каша.
Вот в том же openssl даже в пределах одной либы не всегда понятно надо ли освобождать поинтер. Благо в последних версиях они эту инфу в сигнатуру функций стали включать...
Вот здесь и спасают крестообёртки и крестосмартпоинтеры.
Так и запишем - C++ это язык для подкостыливания сишечки.
https://github.com/bormand/pp_aes
> Превращает govnokod.ru в анонимную борду
Можно говносток и хуз сделать анонимными.
Только аппарат Илизарова он не снимает уже очень долго, всё подкручивает к нему шурушки.
Блядь, как у вас хватает на это памяти и внимания!? И ещё остаётся на суть задачи...
@if(c == NULL) return EXIT_FAILURE;
А разве аллокатор молча не швыряет исключение?
Хм. Погуглил. Инфы по CRT крайне мало, но я полагаю, что это обёртка над VirtualAlloc. Тогда тем более нужен обработчик, швыряющий исключение при неудачном вызове.
«new (std::nothrow)» — не швыряет, возвращает «nullptr».
«malloc»/«calloc» — не швыряют, возвращают «NULL».
Ну и j123123 привёл пример на «C», в нём нет никаких «исключений», и именно поэтому я за.
procedure malloc(var P:Pointer; Size:DWORD);
begin
P:=Pointer(GlobalAlloc(GPTR, Size));
if P=nil then
raise ENotEnoughMemException.Create('Вы соснули с заглотом');
end;
Речь вообще-то идёт о try.. catch..throw
https://docs.microsoft.com/en-us/previous-versions/ms810627(v=msdn.10)
When memory is committed, physical pages of memory are allocated and space is reserved in a pagefile.
CRT может при старте вызвать VirtualAlloc (или ещё какой-нибудь ...Alloc) с запасом, а потом вызывать не на каждый malloc, а по необходимости. Внутри куска, выделенного VirtualAlloc, CRT может вводить свою разметку.
https://en.wikipedia.org/wiki/C_dynamic_memory_allocation#Implementati ons
Если бы функция malloc была тупой обёрткой, столько реализаций не появилось бы.
А «heap_alloc_dbg_internal» оперирует двусвязным списком вот таких штруктур:
Это такой noexcept в старых крестах.
> Это вообще няшная или кресты?
Кресты. Микрософтный CRT на них написан.
> Суть проблемы
> В общем, оказывается, что строки содержат ссылки на родительские строки! Что??
> Это вроде бы не сильно на что-то влияет, но только до тех пор, пока вы не захотите из огромной строки вырезать маленький кусочек и оставить себе, а большую строку удалить. Ведь она не удалится. Она останется в памяти, потому что на неё ссылается новая строка, которую вы где-то сохранили, поэтому сборщик мусора не хочет может освободить память.
> Получается такая цепочка указателей:
> какой-то массив или объект -> ваша новая маленькая строка -> старая большая строка
> На самом деле всё ещё сложнее, у строки может быть несколько «родителей», но не будем усугублять.
> Issue 2869: Substring of huge string retains huge string in memory
> Tue, Sep 3, 2013, 6:47 PM GMT+3
> Status: Assigned (Open)
Ну это более разумный подход, большая арена по сути.
Какой IntelliJ )))
https://intellij-support.jetbrains.com/hc/en-us/community/posts/206964525-why-does-idea-have-a-run-gc-button-
> А если выжила всего пара мелких фрагментов - можно их скопировать и ёбнуть оригинал.
Я кстати предлагал похожий вореант.
Когда сборщик сталкивается с high memory pressure он должен начинать компактизировать строки, а не вываливаться с OOM.
https://govnokod.ru/27616#comment664929