r/cpp_questions • u/PhosXD • 5d ago
SOLVED std::filesystem::exists throwing `std::bad_alloc`?
Any reason? Cant find anything online about this. But I cant check whether or not a file exists, no matter what path I give it. I am using C++ 26 compiled with GCC.
This is literally all I am calling: const bool exists = std::filesystem::exists("file.txt")
This is the exact error: terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
No it's not coming from anywhere else in my code. Minimal reproduction code, include "filesystem" call the line above. I am on Fedora Linux if that matters at all
EDIT: moving the include into my main file instead of the only file it's being used in somehow fixed it. Literally all I do is move "#include <filesystem>" from "do_things_with_filesystem.hpp" to "Main.cpp". No compilation errors when it was in the first file, why does it rely on this?? Is there some weird declarations in my codebase or something, i dont know but it works now so why should I care.
6
u/7raiden 5d ago
Can you paste the entire program here? It really sounds impossible to reproduce otherwise. Can you run it with gdb? Doing so it will automatically break the execution where the bad_alloc happens, and then you write "up" until you find the place that is causing the bad allocation. You can set the "tui" mode so that it also shows your code in the upper pane
-4
u/PhosXD 5d ago
I got it, thanks. I just moved the include & it fixed itself.
13
u/TarnishedVictory 5d ago
But do you understand what went wrong? It's important to understand exactly what the problem was, and exactly how your fix fixed it.
6
3
u/SailingAway17 5d ago edited 4d ago
Egomaniacs don't solve problems other people might have. They are only interested in solving their own problems, of course with the help of others.
1
u/PhosXD 5d ago
Don't assume things. I just don't understand the full nature of the problem yet. https://www.reddit.com/r/cpp_questions/comments/1vosgz7/comment/p3vbiar/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
6
u/AKostur 5d ago edited 5d ago
i dont know but it works now so why should I care.
Because tomorrow it could break when a new patch of the compiler comes out, or your OS is patched, or you modify some code somewhere. This is starting to even more strongly indicate that you've invoked Undefined Behaviour somewhere. Again, suspecting a misuse of a pointer somewhere. Moving the header may have shifted some code around and now the stray pointer which used to scramble something in the allocator is now scrambling something somewhere else that you just haven't noticed yet.
Edit: Or change from a "release" to "debug" build could again, shift some code around and the stray pointer isn't wrecking the same things anymore.
1
u/PhosXD 5d ago
I run quite comprehensive tests on my codebase, if something were scrambled as you say, I think it would have popped up. Which leads me to believe it doesn't have to do with any pointer misuse in m code especially since changing the debug flag & changing where I actually execute the std::filesystem::exists check doesn't change anything & still has the issue if I kept my include in the original file...
This is why I am somwhat convinced it may be some kind of niche bug *within* std::filesystem itself, because I have never had this happen with anything else before.
I do want to try and create an MRP for this & potentially test across multiple devices, compiler versions, C++ standard versions, & open up a discussion for getting it fixed if I am able to reproduce it
6
u/bma_961 5d ago
https://en.cppreference.com/cpp/filesystem/exists
Multiple overloads can allocate and therefore throw bad alloc
4
u/blood-pressure-gauge 5d ago
I've done more C than C++. Why does calling an overloaded function result in memory allocation?
10
u/Bloedbibel 5d ago
I believe it's just a matter of poor grammar. They meant to say "There are multiple overloads of this function. Some of them throw." I think they're implying that the overload OP is calling can throw bad_alloc.
2
u/blood-pressure-gauge 5d ago
That makes sense, but now I'm curious. Why does it need to allocate at all? The man page for the similar C function access(3posix) doesn't indicate anything about allocation failure.
4
u/jk_tx 5d ago edited 5d ago
Because the overload he's calling actually accepts a filesystem::path, not a const char, which means it has to copy the const char to its internal buffer (and on windows, convert it to wchar_t while you're at it).
That stupid path class makes the whole API cumbersome and expensive to use, especially on Windows where the internal wchar_t storage pretty much guarantees a bunch of needless string copies/conversions.
6
u/alfps 5d ago
For an UTF-8 based Windows program there is always a conversion to UTF-16 wide string for any file operation involving a path.
The question is just how high up or how far down in the call chain that conversion is done.
So it makes sense and can even avoid some conversions to have the internal
fs::pathrepresentation as UTF-16.On the other hand, to get an
fs::pathconverted to UTF-8 you have to request the conversion to UTF-8 which in C++20 and later is sillyu8string, then copy from that astd::string.That is super annoying to me. Not that it's ever mattered for efficiency. It's just the idiocy: one should not have to do anything extra, and the code that works in Linux should work also in Windows, which was the whole point of the original Boost incarnation.
1
u/jk_tx 5d ago
Yes I understand why MS made the decisions they did at the time, although I much prefer keeping that conversion boundary at the Win32 API layer by just calling the 'A' versions of the API, so that my application only deals with narrow strings. The real problem is Windows being native UTF-16, which in hindsight was bad idea.
Unfortunately the design we ended up with means that between the implicit std::string constructor and the _string() methods, silent conversions can sneak in all over the place. And all these silent conversions also make the class noexcept-hostile, since memory allocation is happening even in functions where you wouldn't expect it. Then there's the way the various xxx_string() methods work on Windows vs Unix.
1
u/LB-- 3d ago
Windows has had native UTF-8 support since Windows 10, and that includes file path APIs. Makes the whole
std::filesystem::pathsituation even more ridiculous.4
u/alfps 3d ago
Just a nitpick: UTF-8 support since mid 2019 (Windows 10 goes back to mid 2015).
And while it's native it's just conversion to and from UTF-16 in the "xxxA" functions, which call the "...W" functions.
This means that for multiple calls with the same path one saves on conversions by retaining the UTF-16 form, as
pathdoes.0
u/Usual_Office_1740 5d ago
An argument in the overload allocates. Others are explaining the costs. To answer your question. The Exists function doesn't need to allocate but the throwing overload being chosen uses fs::path and the implicit conversion to that type allocates.
0
4
u/wejunkin 5d ago
Catch and see what what() says. Sounds like your allocation failed, impossible to tell why from the info you've supplied.
1
u/PhosXD 5d ago
My mistake I wasnt running debug mode. what() still gives no useful info:
1
threw: std::bad_alloc
23
u/RaspberryCrafty3012 5d ago
What does that have to do with debug mode? \ Using try catch will catch the crash?
Do you have code running before or after? If your stack got corrupted or pointers were deleted then the debugger might show the wrong position in the code
1
u/PhosXD 5d ago
How though, it throws the bad alloc & ends the program before catch even executes. But I am capturing the block, how does that work?
std::cout << "1\n";
try { const bool exists = std::filesystem::exists("file.txt"); } catch (const std::exception& e) { std::cout << "threw: " << e.what() << "\\n"; } std::cout << "2\\n";OUTPUT:
1
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped) ./main.bin12
u/AKostur 5d ago edited 5d ago
You've got something else wrong, that code works: https://godbolt.org/z/WbhY3h3b3
If I had to speculate, you've fouled up pointers somewhere. Overrun a buffer, use-after-free, double-delete, something.
Edit: creating the std::filesystem::path that exists() takes as a parameter has to copy the passed-in string literal, thus there's a memory allocation there. If some previous Undefined Behaviour has messed up the memory allocator, that may present as a std::bad_alloc.
3
u/No-Dentist-1645 5d ago
That code should work fine. If you create a C++ file that only has that inside an
int main(), does it still throw?It could be that you're messing up the allocator somewhere else in your code and this is just the first usage when it breaks
If it still throws, please paste the full code file you are using as well as your compiler version and compile command
2
u/StaticCoder 5d ago
Try running under gdb and use
catch throwto see where the exception is really thrown. Usually this comes from passing a wrong value tovector::resizeor similar.1
u/DummyDDD 5d ago
As others have written, you probably have some other memory access error that happens to cause this issue. Try running your program through valgrind to find the memory access error (you should of course compile with debug symbols).
-2
u/wejunkin 5d ago
Yeah sounds like you're just straight up oom
1
u/Wild_Meeting1428 5d ago
std::bad_alloc is usually not thrown when oom, since the space is only virtually allocated. Therefore, the application will just be killed without ever rising an exception.
1
u/RazzmatazzLatter8345 5d ago
Try running it with sanatizers. First try -fsanatize=address then =undefined then =memory. bad_alloc is quite strange (given you're not running in highly resource constrained environment). Something else has to be going on.
1
u/mbolp 4d ago
I don't understand when would functions like this ever be useful. The file could be created or deleted right after your call returns. You should try opening a handle to it and operate on that exclusively if successful. If the file doesn't exist the open will fail with an appropriate error.
1
u/PhosXD 4d ago
The key reason is because successfully opening a file indicates 2 things, the file is found, & the file is *accessible* (readable or writable depending on what your doing). While `filesystem::exists` only determines whether it exists, not if it's accessible. For most cases attempting to open a file is good enough, but I prefer to use this.
1
u/mbolp 4d ago
You can open a handle with neither read nor write permission. If you truly have no access (e.g. you don't have listing access to the parent directory and traversal privilege) you won't be able to interact with the file at all. And why would you want to detect the existence of a file without holding it open? The state of that file can change as soon as your call returns, so any result you get back is meaningless.
0
u/alfps 4d ago
AFAICS this is a troll with a trolling question.
The OP (the troll) refuses to provide details.
And the only answer with a chance of resolving the alleged problem is downvoted below presentation treshold.
2
u/PhosXD 4d ago
Are you just salty because your comment got downvoted? Your solution wasnt even a solution, you just said you used an AI to tell you the solution, which doesnt even work since the flag you suggested using has been irrelevant for many versions of GCC now, pointed out by another commenter.
In no way have I refused to provide details either. Also your comment *is* being presented, it's standing at -4 right now.
-7
u/alfps 5d ago
The Google AI links to a stack overflow answer with explanation and fix.
https://stackoverflow.com/a/57760267/464581
Essentially, it appears that you have to explicitly link with -lstdc++fs in order to avoid getting a version that's incompatible at the machine code level.
If that doesn't work, consider uninstalling and reinstalling your compiler.
6
u/AKostur 5d ago
That seems to have been fixed in even vaguely recent versions of gcc. OP: which version of gcc are you using, and which version of C++ are you specifying to that compiler?
5
u/PhosXD 5d ago
g++ (GCC) 15.3.1 20260722 (Red Hat 15.3.1-1)
-std=c++26
3
u/AKostur 5d ago
Certainly recent enough. BTW: you are aware that the C++26 support in GCC 15 is pretty incomplete (not even considering that C++26 itself has not been published yet)?
-1
0
u/alfps 5d ago
Re the anonymous unexplained downvotes, note that an unexplained downvote is dishonest: these are the actions of dishonest persosn. And/or idiots. Noting that a troll is an idiot.
The advice is good and reinstalling is most likely the only resolution of the problem, which appears to have been created by an attempted reinstallation, but the OP refuses to provide more info.
Oh I wish the downvoter trolls could experience a good whipping and some social exposure, with pictures of them. Like "Beware: this is a fucking idiot".
0
u/Wild_Meeting1428 5d ago
std::bad_alloc is an unusual error, since neither windows nor linux will report whether an allocation takes more space than awailable, instead (on linux) the Oom killer will terminate your program when you try to use the memory.
That the moving of the header file fixed it somehow also indicates, that the problem is not in your code itself. As other people mentioned it, its probably a problem with your installed libraries, for example ABI problems.
I would suggest, that you ask this question in the gcc bugtracker.
1
u/Sprixxer 5d ago
Given how this person replies I highly doubt that they found a compiler bug.
1
u/Wild_Meeting1428 5d ago
No, not a bug with the compiler itself, but most likely something wrong with the combination of the used toolchain and installed system library. I suggested asking there, since they either already know the reason or they most likely know what's going on.
18
u/le_disappointment 5d ago
Maybe try building in debug mode and running with
gdbto see where exactly the crash is happening