Store location during Ascii input parsing for use in error messages

This commit is contained in:
Tim Wojtulewicz 2022-05-12 14:40:31 -07:00
parent 098a5d3348
commit ec50b66ff3
8 changed files with 60 additions and 16 deletions

View file

@ -1101,7 +1101,15 @@ Val* Manager::ValueToIndexVal(const Stream* i, int num_fields, const RecordType*
{ {
// Since we're building a (list) value for indexing into // Since we're building a (list) value for indexing into
// a table, it is for sure an error to miss a value. // a table, it is for sure an error to miss a value.
Warning(i, "Skipping input with missing non-optional value"); auto source = i->reader->Info().source;
auto file_pos = vals[position]->GetFileLineNumber();
const char* warning = "Skipping input with missing non-optional value";
if ( source && file_pos != -1 )
Warning(i, "%s:%d: %s", source, file_pos, warning);
else
Warning(i, "%s", warning);
have_error = true; have_error = true;
} }
@ -1950,7 +1958,15 @@ RecordVal* Manager::ValueToRecordVal(const Stream* stream, const Value* const* v
else if ( ! vals[*position]->present && else if ( ! vals[*position]->present &&
! request_type->FieldDecl(i)->GetAttr(zeek::detail::ATTR_OPTIONAL) ) ! request_type->FieldDecl(i)->GetAttr(zeek::detail::ATTR_OPTIONAL) )
{ {
Warning(stream, "Skipping input with missing non-optional value"); auto source = stream->reader->Info().source;
auto file_pos = vals[*position]->GetFileLineNumber();
const char* warning = "Skipping input with missing non-optional value";
if ( source && file_pos != -1 )
Warning(stream, "%s:%d: %s", source, file_pos, warning);
else
Warning(stream, "%s", warning);
have_error = true; have_error = true;
} }
else else

View file

@ -157,8 +157,11 @@ bool Ascii::OpenFile()
return ! fail_on_file_problem; return ! fail_on_file_problem;
} }
read_location = std::make_unique<zeek::detail::Location>(); if ( ! read_location )
read_location->filename = util::copy_string(fname.c_str()); {
read_location = LocationPtr(new zeek::detail::Location());
read_location->filename = util::copy_string(fname.c_str());
}
StopWarningSuppression(); StopWarningSuppression();
return true; return true;
@ -389,6 +392,8 @@ bool Ascii::DoUpdate()
{ {
// add non-present field // add non-present field
fields[fpos] = new Value((*fit).type, false); fields[fpos] = new Value((*fit).type, false);
if ( read_location )
fields[fpos]->SetFileLineNumber(read_location->first_line);
fpos++; fpos++;
continue; continue;
} }
@ -420,7 +425,6 @@ bool Ascii::DoUpdate()
Value* val = formatter->ParseValue(stringfields[(*fit).position], (*fit).name, Value* val = formatter->ParseValue(stringfields[(*fit).position], (*fit).name,
(*fit).type, (*fit).subtype); (*fit).type, (*fit).subtype);
if ( ! val ) if ( ! val )
{ {
Warning(Fmt("Could not convert line '%s' of %s to Val. Ignoring line.", Warning(Fmt("Could not convert line '%s' of %s to Val. Ignoring line.",
@ -429,6 +433,9 @@ bool Ascii::DoUpdate()
break; break;
} }
if ( read_location )
val->SetFileLineNumber(read_location->first_line);
if ( (*fit).secondary_position != -1 ) if ( (*fit).secondary_position != -1 )
{ {
// we have a port definition :) // we have a port definition :)

View file

@ -91,7 +91,21 @@ private:
std::string path_prefix; std::string path_prefix;
std::unique_ptr<threading::Formatter> formatter; std::unique_ptr<threading::Formatter> formatter;
std::unique_ptr<zeek::detail::Location> read_location;
// zeek::detail::Location doesn't have a destructor because it's constexpr, so we have to
// define a custom deleter for the unique_ptr here to make sure the filename gets deleted
// correctly when the unique_ptr gets reset.
struct LocationDeleter
{
void operator()(zeek::detail::Location* loc) const
{
delete[] loc->filename;
delete loc;
}
};
using LocationPtr = std::unique_ptr<zeek::detail::Location, LocationDeleter>;
LocationPtr read_location;
}; };
} // namespace zeek::input::reader::detail } // namespace zeek::input::reader::detail

View file

@ -62,7 +62,7 @@ public:
* *
* @param val the Value to render to the ODesc object. * @param val the Value to render to the ODesc object.
* *
* @param The name of a field associated with the value. * @param name The name of a field associated with the value.
* *
* @return Returns true on success, false on error. Errors are also * @return Returns true on success, false on error. Errors are also
* flagged via the thread. * flagged via the thread.
@ -75,7 +75,7 @@ public:
* *
* @param s The string to parse. * @param s The string to parse.
* *
* @param The name of a field associated with the value. Used only * @param name The name of a field associated with the value. Used only
* for error reporting. * for error reporting.
* *
* @return The new value, or null on error. Errors must also be * @return The new value, or null on error. Errors must also be

View file

@ -253,9 +253,16 @@ struct Value
static Val* ValueToVal(const std::string& source, const threading::Value* val, static Val* ValueToVal(const std::string& source, const threading::Value* val,
bool& have_error); bool& have_error);
void SetFileLineNumber(int line) { line_number = line; }
int GetFileLineNumber() const { return line_number; }
private: private:
friend class IPAddr; friend class IPAddr;
Value(const Value& other) = delete; Value(const Value& other) = delete;
// For values read by the input framework, this can represent the line number
// containing this value. Used by the Ascii reader primarily.
int line_number = -1;
}; };
} // namespace zeek::threading } // namespace zeek::threading

View file

@ -47,13 +47,13 @@ public:
* separators. * separators.
*/ */
Ascii(MsgThread* t, const SeparatorInfo& info); Ascii(MsgThread* t, const SeparatorInfo& info);
virtual ~Ascii(); ~Ascii() override;
virtual bool Describe(ODesc* desc, Value* val, const std::string& name = "") const; virtual bool Describe(ODesc* desc, Value* val, const std::string& name = "") const override;
virtual bool Describe(ODesc* desc, int num_fields, const Field* const* fields, virtual bool Describe(ODesc* desc, int num_fields, const Field* const* fields,
Value** vals) const; Value** vals) const override;
virtual Value* ParseValue(const std::string& s, const std::string& name, TypeTag type, virtual Value* ParseValue(const std::string& s, const std::string& name, TypeTag type,
TypeTag subtype = TYPE_ERROR) const; TypeTag subtype = TYPE_ERROR) const override;
private: private:
bool CheckNumberError(const char* start, const char* end, bool nonneg_only = false) const; bool CheckNumberError(const char* start, const char* end, bool nonneg_only = false) const;

View file

@ -1,9 +1,9 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
warning: Skipping input with missing non-optional value warning: ../input.log:3: Skipping input with missing non-optional value
warning: ..<...>/Input::READER_ASCII: ../input.log, line 4: Invalid value for subnet: 127.0.0.1 warning: ..<...>/Input::READER_ASCII: ../input.log, line 4: Invalid value for subnet: 127.0.0.1
warning: ..<...>/Input::READER_ASCII: ../input.log, line 4: Error while reading set or vector warning: ..<...>/Input::READER_ASCII: ../input.log, line 4: Error while reading set or vector
warning: ..<...>/Input::READER_ASCII: ../input.log, line 4: Could not convert line 'name 127.0.0.1' of ../input.log to Val. Ignoring line. warning: ..<...>/Input::READER_ASCII: ../input.log, line 4: Could not convert line 'name 127.0.0.1' of ../input.log to Val. Ignoring line.
warning: Skipping input with missing non-optional value warning: ../input.log:3: Skipping input with missing non-optional value
warning: ..<...>/Input::READER_ASCII: ../input.log, line 4: Invalid value for subnet: 127.0.0.1 warning: ..<...>/Input::READER_ASCII: ../input.log, line 4: Invalid value for subnet: 127.0.0.1
warning: ..<...>/Input::READER_ASCII: ../input.log, line 4: Error while reading set or vector warning: ..<...>/Input::READER_ASCII: ../input.log, line 4: Error while reading set or vector
warning: ..<...>/Input::READER_ASCII: ../input.log, line 4: Could not convert line 'name 127.0.0.1' of ../input.log to Val. Ignoring line. warning: ..<...>/Input::READER_ASCII: ../input.log, line 4: Could not convert line 'name 127.0.0.1' of ../input.log to Val. Ignoring line.

View file

@ -1,13 +1,13 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
### NOTE: This file has been sorted with diff-sort. ### NOTE: This file has been sorted with diff-sort.
EventErrorEvent, ../input.log:3: Skipping input with missing non-optional value, Reporter::WARNING
EventErrorEvent, Could not convert line 'name\x09127.0.0.1' of ../input.log to Val. Ignoring line., Reporter::WARNING EventErrorEvent, Could not convert line 'name\x09127.0.0.1' of ../input.log to Val. Ignoring line., Reporter::WARNING
EventErrorEvent, Error while reading set or vector, Reporter::WARNING EventErrorEvent, Error while reading set or vector, Reporter::WARNING
EventErrorEvent, Invalid value for subnet: 127.0.0.1, Reporter::WARNING EventErrorEvent, Invalid value for subnet: 127.0.0.1, Reporter::WARNING
EventErrorEvent, Skipping input with missing non-optional value, Reporter::WARNING TableErrorEvent, ../input.log:3: Skipping input with missing non-optional value, Reporter::WARNING
TableErrorEvent, Could not convert line 'name\x09127.0.0.1' of ../input.log to Val. Ignoring line., Reporter::WARNING TableErrorEvent, Could not convert line 'name\x09127.0.0.1' of ../input.log to Val. Ignoring line., Reporter::WARNING
TableErrorEvent, Error while reading set or vector, Reporter::WARNING TableErrorEvent, Error while reading set or vector, Reporter::WARNING
TableErrorEvent, Invalid value for subnet: 127.0.0.1, Reporter::WARNING TableErrorEvent, Invalid value for subnet: 127.0.0.1, Reporter::WARNING
TableErrorEvent, Skipping input with missing non-optional value, Reporter::WARNING
{ {
} }