c – basic_filebuf :: underflow错误在/ proc / pid / stat上使
为什么以下代码会抛出异常?请注意,该文件是/ proc / pid / stat文件,因此它可能会受到内核的干扰.
// Checked that file does exist try { std::ifstream file(path.c_str()); // Shouldn't even be necessary because it's the default but it doesn't // make any difference. file.exceptions(std::ifstream::goodbit); // Read the stream into many fields // !!!! The exception was thrown here. file >> _ >> comm >> state >> ppid >> pgrp >> session >> tty_nr /* >> ... omitted */; file.close(); } catch (const std::ifstream::failure& e) { std::cout << "Exception!!!! " << e.what(); } 例外是“读取文件的basic_filebuf :: underflow错误”. 当我们没有要求它时(通过设置file.exceptions()),流不应该抛出异常吗? 更多信息: >它运行在gcc版本4.1.2 20080704(Red Hat 4.1.2-54) 解决方法
更新2
我甚至试图通过手动设置微小或巨大的缓冲区大小来强制错误: std::filebuf fb; // set tiny input buffer char buf[8]; // or huge: 64*1024 fb.pubsetbuf(buf,sizeof(buf)); fb.open(path.c_str(),std::ios::in); std::istream file(&fb); 我已经使用strace验证了读取大小确实很小(7) sudo strace ./test $(sudo ps h -ae -o pid) |& egrep -w 'read|open' | grep -v '= 7' | less -SR 有趣的是,这一切都没有失败. 更新 为了回应这些评论,我设计了一个完全符合OP描述的独立程序,但我无法重现这个问题: > See it live on Coliru again http://coliru.stacked-crooked.com/view?id=81960c… #include <sys/types.h> // For pid_t. #include <fstream> #include <string> // mock up #include <boost/variant.hpp> namespace { struct None {}; struct Error { std::string s; Error(std::string s): s(s){} }; std::ostream& operator<<(std::ostream& os,None const&) { return os << "None"; } std::ostream& operator<<(std::ostream& os,Error const& e) { return os << "Error {" << e.s << "}"; } template <typename T> using Result = boost::variant<None,Error,T>; } // end mockup namespace proc { // Snapshot of a process (modeled after /proc/[pid]/stat). // For more information,see: // http://www.kernel.org/doc/Documentation/filesystems/proc.txt struct ProcessStatus { pid_t pid; std::string comm; char state; pid_t ppid,pgrp,session; int tty_nr; pid_t tpgid; unsigned int flags; unsigned long minflt,cminflt,majflt,cmajflt; unsigned long utime,stime; long cutime,cstime,priority,nice,num_threads,itrealvalue; unsigned long long starttime; unsigned long vsize; long rss; unsigned long rsslim,startcode,endcode,startstack,kstkeip,signal,blocked,sigcatch,wchan,nswap,cnswap; friend std::ostream& operator<<(std::ostream& os,proc::ProcessStatus const& ps) { return os << "pid: " << ps.pid << "n" << "comm: " << ps.comm << "n" << "state: " << ps.state << "n" << "ppid: " << ps.ppid << "n" << "pgrp: " << ps.pgrp << "n" << "session: " << ps.session << "n" << "tty_nr: " << ps.tty_nr << "n" << "tpgid: " << ps.tpgid << "n" << "flags: " << ps.flags << "n" << "minflt: " << ps.minflt << "n" << "cminflt: " << ps.cminflt << "n" << "majflt: " << ps.majflt << "n" << "cmajflt: " << ps.cmajflt << "n" << "utime: " << ps.utime << "n" << "stime: " << ps.stime << "n" << "cutime: " << ps.cutime << "n" << "cstime: " << ps.cstime << "n" << "priority: " << ps.priority << "n" << "nice: " << ps.nice << "n" << "num_threads: " << ps.num_threads << "n" << "itrealvalue: " << ps.itrealvalue << "n" << "starttime: " << ps.starttime << "n" << "vsize: " << ps.vsize << "n" << "rss: " << ps.rss << "n" << "rsslim: " << ps.rsslim << "n" << "startcode: " << ps.startcode << "n" << "endcode: " << ps.endcode << "n" << "startstack: " << ps.startstack << "n" << "kstkeip: " << ps.kstkeip << "n" << "signal: " << ps.signal << "n" << "blocked: " << ps.blocked << "n" << "sigcatch: " << ps.sigcatch << "n" << "wchan: " << ps.wchan << "n" << "nswap: " << ps.nswap << "n" << "cnswap: " << ps.cnswap << "n"; } }; // Returns the process statistics from /proc/[pid]/stat. // The return value is None if the process does not exist. inline Result<ProcessStatus> status(pid_t pid) { std::string path = "/proc/" + std::to_string(pid) + "/stat"; std::ifstream file(path.c_str()); if (!file.is_open()) { #if 1 return Error("Failed to open '" + path + "'"); #else // FIXME reenable // Need to check if file exists AFTER we open it to guarantee // process hasn't terminated (or if it has,we at least have a // file which the kernel _should_ respect until a close). if (!os::exists(path)) { return None(); } return Error("Failed to open '" + path + "'"); #endif } std::string _; // For ignoring fields. // Parse all fields from stat. ProcessStatus ps; if (file >> _ >> ps.comm >> ps.state >> ps.ppid >> ps.pgrp >> ps.session >> ps.tty_nr >> ps.tpgid >> ps.flags >> ps.minflt >> ps.cminflt >> ps.majflt >> ps.cmajflt >> ps.utime >> ps.stime >> ps.cutime >> ps.cstime >> ps.priority >> ps.nice >> ps.num_threads >> ps.itrealvalue >> ps.starttime >> ps.vsize >> ps.rss >> ps.rsslim >> ps.startcode >> ps.endcode >> ps.startstack >> ps.kstkeip >> ps.signal >> ps.blocked >> ps.sigcatch >> ps.wchan >> ps.nswap >> ps.cnswap) { return ps; } else { return Error("Failed to read/parse '" + path + "'"); } } } // namespace proc { int main(int argc,const char *argv[]) { for (auto i=1; i<argc; ++i) std::cout << proc::status(std::stoul(argv[i])) << "n"; } 它在我的机器上快乐地运行,打印出类似的东西 pid: 594590200 comm: (test) state: R ppid: 8123 pgrp: 8123 session: 8123 ... 即使/当我折磨它时 sudo ./test $(sudo ps h -ae -o pid) | grep -v : | sort -u ./test $(sudo ps h -ae -o pid) | grep -v : | sort -u 它只是显示(可能是子shell中的sudo / ps) Error {Failed to open '/proc/8652/stat'} Error {Failed to open '/proc/8653/stat'} 我试图从输入流中读取两次信息(强制读取结束类型的情况),但没有运气. 旧答案文字: 您需要在什么样的条件下建立异常.以下演示代码在我的系统上按预期工作: #include <fstream> #include <iostream> int main() { system("ps -o pid,comm,state,ppid,session,tty > input.txt"); try { std::ifstream file("input.txt"); file.exceptions(std::ifstream::goodbit); std::string _,tty_nr; while (file >> _ >> comm >> state >> ppid >> pgrp >> session >> tty_nr) { for (auto&& s : { _,tty_nr }) std::cout << s << "t"; std::cout << "n"; } file.close(); } catch (const std::ifstream::failure& e) { std::cout << "Exception!!!! " << e.what(); } } 印刷品,例如: PID COMMAND S PPID PGRP SESS TT 20950 bash S 20945 20950 20950 pts/1 21275 vim S 20950 21275 20950 pts/1 21279 bash S 21275 21275 20950 pts/1 21280 test S 21279 21275 20950 pts/1 21281 sh S 21280 21275 20950 pts/1 21282 ps R 21281 21275 20950 pts/1 更新 我想,在许多系统上,默认缓冲区大小可能最大为8192字节;让我们创建一些愚蠢的长线!替换系统调用 system("od /dev/urandom -t x8 -Anone | xargs -n256 | tr -d ' ' | xargs -n7 | head -n100 > input.txt"); 产生7列的行,每行约29kB.输出毫不犹豫,相当于2.8MiB的输出,用 make -B && ./test | wc 在coliru上看到它: > http://coliru.stacked-crooked.com/view?id=00160c8a2b5d4447cbda3866da3913aa-b8c04540b49ee47c13fd3df477ec213b 请注意,在Coliru上,我们无法访问/ dev / urandom,这就是我从二进制文件本身读取的原因. “随机”足以达到此目的:) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |