I want to safely read a line from an std::istream
. The stream could be anything, e.g., a connection on a Web server or something processing files submitted by unknown sources. There are many answers starting to do the moral equivalent of this code:
void read(std::istream& in) { std::string line; if (std::getline(in, line)) { // process the line } }
Given the possibly dubious source of in
, using the above code would lead to a vulnerability: a malicious agent may mount a denial of service attack against this code using a huge line. Thus, I would like to limit the line length to some rather high value, say 4 millions char
s. While a few large lines may be encountered, it isn't viable to allocate a buffer for each file and use std::istream::getline()
.
How can the maximum size of the line be limited, ideally without distorting the code too badly and without allocating large chunks of memory up front?
Other ways to read a std::istreamTo read a line of input, try the getline() function. For this, you need #include <string> in addition to #include <iostream> . To read a single char: use the get() method. To read a large block of characters, either use get() with a char[] as the argument, or use read() .
2.2 File InputConstruct an istream object. Connect it to a file (i.e., file open) and set the mode of file operation. Perform output operation via extraction << operator or read() , get() , getline() functions. Disconnect (close the file) and free the istream object.
Use std::getline() Function to Read a File Line by Line The getline() function is the preferred way of reading a file line by line in C++. The function reads characters from the input stream until the delimiter char is encountered and then stores them in a string.
Opening a File The object ifs can be instantiated from the ifstream class using the first syntax with the statement: ifstream ifs; In this case, a file object ifs has been created but the file is not yet opened. To open the file for reading, the open member function of the ifstream class has to be used.
You could write your own version of std::getline
with a maximum number of characters read parameter, something called getline_n
or something.
#include <string> #include <iostream> template<typename CharT, typename Traits, typename Alloc> auto getline_n(std::basic_istream<CharT, Traits>& in, std::basic_string<CharT, Traits, Alloc>& str, std::streamsize n) -> decltype(in) { std::ios_base::iostate state = std::ios_base::goodbit; bool extracted = false; const typename std::basic_istream<CharT, Traits>::sentry s(in, true); if(s) { try { str.erase(); typename Traits::int_type ch = in.rdbuf()->sgetc(); for(; ; ch = in.rdbuf()->snextc()) { if(Traits::eq_int_type(ch, Traits::eof())) { // eof spotted, quit state |= std::ios_base::eofbit; break; } else if(str.size() == n) { // maximum number of characters met, quit extracted = true; in.rdbuf()->sbumpc(); break; } else if(str.max_size() <= str.size()) { // string too big state |= std::ios_base::failbit; break; } else { // character valid str += Traits::to_char_type(ch); extracted = true; } } } catch(...) { in.setstate(std::ios_base::badbit); } } if(!extracted) { state |= std::ios_base::failbit; } in.setstate(state); return in; } int main() { std::string s; getline_n(std::cin, s, 10); // maximum of 10 characters std::cout << s << '\n'; }
Might be overkill though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With