diff options
author | Nico Weber <nicolasweber@gmx.de> | 2015-03-19 08:42:46 -0700 |
---|---|---|
committer | Nico Weber <nicolasweber@gmx.de> | 2015-03-19 09:45:58 -0700 |
commit | b334523f1da03adfcd23b6e7e7a66c8fcbf87840 (patch) | |
tree | aa073a311c1e3380e26592b85e437322757f2921 /src/graph.cc | |
parent | bc38ef76ebfabe503b1b56a1e32827a851037766 (diff) | |
download | ninja-b334523f1da03adfcd23b6e7e7a66c8fcbf87840.tar.gz |
Make failing stat() calls abort the build.
Fixes #830, fixes #904.
In practice, this either happens with 64-bit inodes and a 32-bit
userspace when building without -D_FILE_OFFSET_BITS=64 in CFLAGS, or
when a filename is longer than the system file length limit.
Since DiskInterface::Stat() returns -1 on error, and Node used -1 on
"stat state unknown", not aborting the build lead to ninja stat()ing the
same file over and over again, until it finally ran out of stack. That's
now fixed.
* Change RecomputeOutputsDirty() to return success instead of dirty
state (like RecomputeDirty()) and return the dirty state in a bool
outparam
* Node::Stat()s old return value wasn't used anywhere, change the
function to return success instead and add an |err| outparam
* Node::StatIfNecessary()'s old return value was used only in one place.
Change that place to explicitly check status_known() and make
StatIfNecessary() return success and add an |err| outparam
* Plan::CleanNode() can now fail, make it return bool and add an |err|
outparam
Diffstat (limited to 'src/graph.cc')
-rw-r--r-- | src/graph.cc | 32 |
1 files changed, 22 insertions, 10 deletions
diff --git a/src/graph.cc b/src/graph.cc index e3253fd..b19dc85 100644 --- a/src/graph.cc +++ b/src/graph.cc @@ -27,10 +27,15 @@ #include "state.h" #include "util.h" -bool Node::Stat(DiskInterface* disk_interface) { +bool Node::Stat(DiskInterface* disk_interface, string* err) { METRIC_RECORD("node stat"); mtime_ = disk_interface->Stat(path_); - return mtime_ > 0; + if (mtime_ == -1) { + // TODO: Let DiskInterface::Stat() take err instead of it calling Error(). + *err = "stat failed"; + return false; + } + return true; } bool DependencyScan::RecomputeDirty(Edge* edge, string* err) { @@ -48,7 +53,8 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) { // graphs. for (vector<Node*>::iterator o = edge->outputs_.begin(); o != edge->outputs_.end(); ++o) { - (*o)->StatIfNecessary(disk_interface_); + if (!(*o)->StatIfNecessary(disk_interface_, err)) + return false; } if (!dep_loader_.LoadDeps(edge, err)) { @@ -62,7 +68,9 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) { Node* most_recent_input = NULL; for (vector<Node*>::iterator i = edge->inputs_.begin(); i != edge->inputs_.end(); ++i) { - if ((*i)->StatIfNecessary(disk_interface_)) { + if (!(*i)->status_known()) { + if (!(*i)->StatIfNecessary(disk_interface_, err)) + return false; if (Edge* in_edge = (*i)->in_edge()) { if (!RecomputeDirty(in_edge, err)) return false; @@ -97,7 +105,8 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) { // We may also be dirty due to output state: missing outputs, out of // date outputs, etc. Visit all outputs and determine whether they're dirty. if (!dirty) - dirty = RecomputeOutputsDirty(edge, most_recent_input); + if (!RecomputeOutputsDirty(edge, most_recent_input, &dirty, err)) + return false; // Finally, visit each output and update their dirty state if necessary. for (vector<Node*>::iterator o = edge->outputs_.begin(); @@ -117,16 +126,19 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) { return true; } -bool DependencyScan::RecomputeOutputsDirty(Edge* edge, - Node* most_recent_input) { +bool DependencyScan::RecomputeOutputsDirty(Edge* edge, Node* most_recent_input, + bool* outputs_dirty, string* err) { string command = edge->EvaluateCommand(/*incl_rsp_file=*/true); for (vector<Node*>::iterator o = edge->outputs_.begin(); o != edge->outputs_.end(); ++o) { - (*o)->StatIfNecessary(disk_interface_); - if (RecomputeOutputDirty(edge, most_recent_input, command, *o)) + if (!(*o)->StatIfNecessary(disk_interface_, err)) + return false; + if (RecomputeOutputDirty(edge, most_recent_input, command, *o)) { + *outputs_dirty = true; return true; + } } - return false; + return true; } bool DependencyScan::RecomputeOutputDirty(Edge* edge, |