Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to safely read a line from an std::istream?

Tags:

c++

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 chars. 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?

like image 988
Dietmar Kühl Avatar asked Dec 17 '13 21:12

Dietmar Kühl


People also ask

How do I read an istream?

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() .

How do I use Istream in C++?

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.

How do you read one line at a time in C++?

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.

How do I read Ifstream?

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.


1 Answers

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.

like image 165
Rapptz Avatar answered Sep 26 '22 04:09

Rapptz