Skip to content

Commit e9540bd

Browse files
authored
JSON error checking when loading (#5401)
Signed-off-by: Chris Dodd <cdodd@nvidia.com>
1 parent 9d7e1c6 commit e9540bd

14 files changed

Lines changed: 246 additions & 94 deletions

File tree

backends/p4test/p4test.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ int main(int argc, char *const argv[]) {
158158
if (options.loadIRFromJson) {
159159
std::ifstream json(options.file);
160160
if (json) {
161+
JsonData::strict = true;
161162
JSONLoader loader(json);
162163
const IR::Node *node = nullptr;
163164
loader >> node;
@@ -227,6 +228,7 @@ int main(int argc, char *const argv[]) {
227228
if (options.debugJson) {
228229
std::stringstream ss1, ss2;
229230
JSONGenerator gen1(ss1), gen2(ss2);
231+
JsonData::strict = true;
230232
gen1.emit(program);
231233

232234
const IR::Node *node = nullptr;

backends/p4tools/p4tools.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,11 @@ class InOutReference : Expression {
272272
/// The value of the reference after it was resolved.
273273
Expression resolvedRef;
274274

275+
// FIXME -- this will fail trying to deserialize `ref` from the json. There's no
276+
// good way of getting to the `ref` field in the json object that can be done in the
277+
// ctor initializer list -- need to call `json.load("ref", ref);`
275278
InOutReference(JSONLoader & json) : Expression(json), ref(json) {
276-
json.load("resolvedRef", resolvedRef);
279+
json.load("resolvedRef", resolvedRef) || json.error("missing field resolvedRef");
277280
}
278281

279282
InOutReference(Util::SourceInfo srcInfo, IR::StateVariable &ref, const Expression* resolvedRef) :

backends/tofino/bf-p4c/ir/arch.def

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,6 @@ class P4Thread {
100100
inline Vector<IR::P4Parser> parsers = {};
101101
const IR::P4Control *mau = nullptr;
102102
const IR::P4Control *deparser = nullptr;
103-
toJSON {
104-
json.emit("parsers", parsers);
105-
json.emit("mau", mau);
106-
json.emit("deparser", deparser); }
107-
fromJSON {
108-
IR::BFN::P4Thread * thread = new IR::BFN::P4Thread();
109-
json.load("parsers", thread->parsers);
110-
json.load("mau", thread->mau);
111-
json.load("deparser", thread->deparser);
112-
return thread;
113-
}
114103
#apply
115104
visit_children {
116105
parsers.parallel_visit_children(v, n);

backends/tofino/bf-p4c/ir/tofino.def

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -95,19 +95,6 @@ class BFN::Pipe {
9595
return parsers == a.parsers && mau == a.mau && deparser == a.deparser &&
9696
hw_constrained_fields == a.hw_constrained_fields;
9797
}
98-
toJSON {
99-
json.emit("parser", parsers);
100-
json.emit("mau", mau);
101-
json.emit("deparser", deparser);
102-
json.emit("hw_constrained_fields", hw_constrained_fields); }
103-
fromJSON {
104-
IR::BFN::Pipe::thread_t * thread = new IR::BFN::Pipe::thread_t();
105-
json.load("parsers", thread->parsers);
106-
json.load("mau", thread->mau);
107-
json.load("deparser", thread->deparser);
108-
json.load("hw_constrained_fields", thread->hw_constrained_fields);
109-
return thread;
110-
}
11198
}
11299
thread_t[2] thread = {};
113100

backends/tofino/bf-p4c/ir/unique_id.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,8 @@ void UniqueAttachedId::toJSON(P4::JSONGenerator &json) const {
3636

3737
UniqueAttachedId UniqueAttachedId::fromJSON(P4::JSONLoader &json) {
3838
UniqueAttachedId uai;
39-
if (json) {
40-
json.load("name", uai.name);
41-
json.load("type", uai.type);
42-
}
39+
json.load("name", uai.name) || json.error("missing field name");
40+
json.load("type", uai.type) || json.error("missing field type");
4341
return uai;
4442
}
4543

backends/tofino/bf-p4c/mau/hash_function.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -583,15 +583,15 @@ IR::MAU::HashFunction *IR::MAU::HashFunction::fromJSON(JSONLoader &json) {
583583
if (!json) return nullptr;
584584
auto *rv = new HashFunction;
585585
int type = 0;
586-
json.load("type", type);
586+
json.load("type", type) || json.error("missing field type");
587587
rv->type = static_cast<decltype(rv->type)>(type);
588-
json.load("size", rv->size);
589-
json.load("msb", rv->msb);
590-
json.load("reverse", rv->reverse);
591-
json.load("poly", rv->poly);
592-
json.load("init", rv->init);
593-
json.load("xor", rv->final_xor);
594-
json.load("extend", rv->extend);
588+
json.load("size", rv->size) || json.error("missing field size");
589+
json.load("msb", rv->msb) || json.error("missing field msb");
590+
json.load("reverse", rv->reverse) || json.error("missing field reverse");
591+
json.load("poly", rv->poly) || json.error("missing field poly");
592+
json.load("init", rv->init) || json.error("missing field init");
593+
json.load("xor", rv->final_xor) || json.error("missing field final_xor");
594+
json.load("extend", rv->extend) || json.error("missing field extend");
595595
return rv;
596596
}
597597

backends/tofino/bf-p4c/parde/clot/clot.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,11 @@ void Clot::toJSON(JSONGenerator &json) const {
202202
}
203203

204204
Clot::Clot(JSONLoader &json) {
205-
json.load("tag", tag);
206-
json.load("gress", gress);
207-
json.load("pov_bit", pov_bit);
208-
json.load("stack_depth", stack_depth);
209-
json.load("stack_inc", stack_inc);
205+
json.load("tag", tag) || json.error("missing field tag");
206+
json.load("gress", gress) || json.error("missing field gress");
207+
json.load("pov_bit", pov_bit) || json.error("missing field pov_bit");
208+
json.load("stack_depth", stack_depth) || json.error("missing field stack_depth");
209+
json.load("stack_inc", stack_inc) || json.error("missing field stack_inc");
210210
}
211211

212212
std::ostream &operator<<(std::ostream &out, const Clot &clot) { return out << "CLOT " << clot.tag; }

backends/tofino/bf-p4c/parde/marshal.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ void MarshaledFrom::toJSON(JSONGenerator &json) const {
3737
/* static */
3838
MarshaledFrom MarshaledFrom::fromJSON(JSONLoader &json) {
3939
MarshaledFrom rv;
40-
json.load("gress", rv.gress);
41-
json.load("field_name", rv.field_name);
42-
json.load("pre_padding", rv.pre_padding);
40+
json.load("gress", rv.gress) || json.error("missing field gress");
41+
json.load("field_name", rv.field_name) || json.error("missing field field_name");
42+
json.load("pre_padding", rv.pre_padding) || json.error("missing field pre_padding");
4343
return rv;
4444
}

ir/json_generator.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,13 +311,15 @@ class JSONGenerator {
311311
}
312312

313313
template <typename T>
314-
std::enable_if_t<has_toJSON<T>::value && !std::is_base_of_v<IR::Node, T>> generate(const T &v) {
314+
std::enable_if_t<has_toJSON<T>::value && !std::is_base_of_v<IR::INode, T>> generate(
315+
const T &v) {
315316
auto t = begin_object();
316317
v.toJSON(*this);
317318
end_object(t);
318319
}
319320

320-
void generate(const IR::Node &v) {
321+
void generate(const IR::INode &v_) {
322+
auto &v = *v_.getNode();
321323
auto t = begin_object();
322324
if (node_refs.find(v.id) != node_refs.end()) {
323325
emit("Node_ID", v.id);

ir/json_loader.h

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,22 @@ class JSONLoader {
5757
std::unordered_map<int, IR::Node *> &node_refs;
5858
std::unique_ptr<JsonData> json_root;
5959
const JsonData *json = nullptr;
60+
JsonData::LocationInfo *locinfo = nullptr;
61+
bool (*errfn)(const JSONLoader &, std::string_view msg) = nullptr;
6062

61-
JSONLoader(const JsonData *json, std::unordered_map<int, IR::Node *> &refs)
62-
: node_refs(refs), json(json) {}
63+
JSONLoader(const JsonData *json, std::unordered_map<int, IR::Node *> &refs,
64+
JsonData::LocationInfo *locinfo)
65+
: node_refs(refs), json(json), locinfo(locinfo) {}
6366

6467
public:
65-
explicit JSONLoader(std::istream &in)
66-
: node_refs(*(new std::unordered_map<int, IR::Node *>())) {
68+
explicit JSONLoader(std::istream &in, JsonData::LocationInfo *li = nullptr)
69+
: node_refs(*(new std::unordered_map<int, IR::Node *>())), locinfo(li) {
6770
in >> json_root;
6871
json = json_root.get();
6972
}
7073

7174
JSONLoader(const JSONLoader &unpacker, std::string_view field)
72-
: node_refs(unpacker.node_refs), json(nullptr) {
75+
: node_refs(unpacker.node_refs), json(nullptr), locinfo(unpacker.locinfo) {
7376
if (!unpacker) return;
7477
if (auto *obj = unpacker.json->to<JsonObject>()) {
7578
if (auto it = obj->find(field); it != obj->end()) {
@@ -88,23 +91,35 @@ class JSONLoader {
8891
return json->as<T>();
8992
}
9093

94+
std::string locdesc(const JsonData &d) const {
95+
if (!locinfo) return "";
96+
return locinfo->desc(d);
97+
}
98+
std::string locdesc() const {
99+
if (!json) return "";
100+
return locdesc(*json);
101+
}
102+
bool error(std::string_view msg) const {
103+
if ((!errfn || errfn(*this, msg)) && JsonData::strict) throw JsonData::error(msg, json);
104+
return false;
105+
}
106+
91107
private:
92-
const IR::Node *get_node() {
108+
const IR::Node *get_node(NodeFactoryFn factory = nullptr) {
93109
if (!json || !json->is<JsonObject>()) return nullptr; // invalid json exception?
94110
int id;
95-
auto success = load("Node_ID", id);
96-
if (!success) {
97-
return nullptr;
98-
}
111+
auto success = load("Node_ID", id) || error("missing field Node_ID");
112+
if (!success) return nullptr;
99113
if (id >= 0) {
100114
if (node_refs.find(id) == node_refs.end()) {
101-
cstring type;
102-
auto success = load("Node_Type", type);
103-
if (!success) {
104-
return nullptr;
115+
if (!factory) {
116+
cstring type;
117+
auto success = load("Node_Type", type) || error("missing field Node_Type");
118+
if (!success) return nullptr;
119+
factory = get(IR::unpacker_table, type);
105120
}
106-
if (auto fn = get(IR::unpacker_table, type)) {
107-
node_refs[id] = fn(*this);
121+
if (factory) {
122+
node_refs[id] = factory(*this);
108123
// Creating JsonObject from source_info read from jsonFile
109124
// and setting SourceInfo for each node
110125
// when "--fromJSON" flag is used
@@ -150,29 +165,32 @@ class JSONLoader {
150165

151166
template <typename T>
152167
void unpack_json(IR::Vector<T> &v) {
153-
v = *IR::Vector<T>::fromJSON(*this);
168+
v = get_node(NodeFactoryFn(&IR::Vector<T>::fromJSON))->as<IR::Vector<T>>();
154169
}
155170
template <typename T>
156171
void unpack_json(const IR::Vector<T> *&v) {
157-
v = IR::Vector<T>::fromJSON(*this);
172+
v = get_node(NodeFactoryFn(&IR::Vector<T>::fromJSON))->checkedTo<IR::Vector<T>>();
158173
}
159174
template <typename T>
160175
void unpack_json(IR::IndexedVector<T> &v) {
161-
v = *IR::IndexedVector<T>::fromJSON(*this);
176+
v = get_node(NodeFactoryFn(&IR::IndexedVector<T>::fromJSON))->as<IR::IndexedVector<T>>();
162177
}
163178
template <typename T>
164179
void unpack_json(const IR::IndexedVector<T> *&v) {
165-
v = IR::IndexedVector<T>::fromJSON(*this);
180+
v = get_node(NodeFactoryFn(&IR::IndexedVector<T>::fromJSON))
181+
->checkedTo<IR::IndexedVector<T>>();
166182
}
167183
template <class T, template <class K, class V, class COMP, class ALLOC> class MAP, class COMP,
168184
class ALLOC>
169185
void unpack_json(IR::NameMap<T, MAP, COMP, ALLOC> &m) {
170-
m = *IR::NameMap<T, MAP, COMP, ALLOC>::fromJSON(*this);
186+
m = get_node(NodeFactoryFn(&IR::NameMap<T, MAP, COMP, ALLOC>::fromJSON))
187+
->as<IR::NameMap<T, MAP, COMP, ALLOC>>();
171188
}
172189
template <class T, template <class K, class V, class COMP, class ALLOC> class MAP, class COMP,
173190
class ALLOC>
174191
void unpack_json(const IR::NameMap<T, MAP, COMP, ALLOC> *&m) {
175-
m = IR::NameMap<T, MAP, COMP, ALLOC>::fromJSON(*this);
192+
m = get_node(NodeFactoryFn(&IR::NameMap<T, MAP, COMP, ALLOC>::fromJSON))
193+
->checkedTo<IR::NameMap<T, MAP, COMP, ALLOC>>();
176194
}
177195

178196
template <typename K, typename V>
@@ -250,20 +268,20 @@ class JSONLoader {
250268

251269
template <typename T, typename U>
252270
void unpack_json(std::pair<T, U> &v) {
253-
load("first", v.first);
254-
load("second", v.second);
271+
load("first", v.first) || error("missing field first");
272+
load("second", v.second) || error("missing field second");
255273
}
256274

257275
template <typename T>
258276
void unpack_json(std::optional<T> &v) {
259277
bool isValid = false;
260-
load("valid", isValid);
278+
load("valid", isValid) || error("missing field valid");
261279
if (!isValid) {
262280
v = std::nullopt;
263281
return;
264282
}
265283
T value;
266-
auto success = load("value", value);
284+
auto success = load("value", value) || error("missing field value");
267285
if (!success) {
268286
v = std::nullopt;
269287
return;
@@ -282,15 +300,15 @@ class JSONLoader {
282300
Variant &variant) {
283301
if (N == target) {
284302
variant.template emplace<N>();
285-
load("value", std::get<N>(variant));
303+
load("value", std::get<N>(variant)) || error("missing field value");
286304
} else
287305
unpack_variant<N + 1>(target, variant);
288306
}
289307

290308
template <class... Types>
291309
void unpack_json(std::variant<Types...> &v) {
292310
int index = -1;
293-
load("variant_index", index);
311+
load("variant_index", index) || error("missing field variant_index");
294312
unpack_variant<0>(index, v);
295313
}
296314

@@ -346,21 +364,21 @@ class JSONLoader {
346364
}
347365

348366
template <typename T>
349-
std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of_v<IR::Node, T> &&
367+
std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of_v<IR::INode, T> &&
350368
std::is_pointer_v<decltype(T::fromJSON(std::declval<JSONLoader &>()))>>
351369
unpack_json(T *&v) {
352370
v = T::fromJSON(*this);
353371
}
354372

355373
template <typename T>
356-
std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of_v<IR::Node, T> &&
374+
std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of_v<IR::INode, T> &&
357375
std::is_pointer_v<decltype(T::fromJSON(std::declval<JSONLoader &>()))>>
358376
unpack_json(T &v) {
359377
v = *(T::fromJSON(*this));
360378
}
361379

362380
template <typename T>
363-
std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of<IR::Node, T>::value &&
381+
std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of<IR::INode, T>::value &&
364382
!std::is_pointer_v<decltype(T::fromJSON(std::declval<JSONLoader &>()))>>
365383
unpack_json(T &v) {
366384
v = T::fromJSON(*this);
@@ -387,12 +405,12 @@ class JSONLoader {
387405
public:
388406
template <typename T>
389407
void load(const JsonData &json, T &v) {
390-
JSONLoader(&json, node_refs).unpack_json(v);
408+
JSONLoader(&json, node_refs, locinfo).unpack_json(v);
391409
}
392410

393411
template <typename T>
394412
void load(const std::unique_ptr<JsonData> &json, T &v) {
395-
JSONLoader(json.get(), node_refs).unpack_json(v);
413+
JSONLoader(json.get(), node_refs, locinfo).unpack_json(v);
396414
}
397415

398416
template <typename T>
@@ -424,15 +442,15 @@ class JSONLoader {
424442

425443
template <class T>
426444
IR::Vector<T>::Vector(JSONLoader &json) : VectorBase(json) {
427-
json.load("vec", vec);
445+
json.load("vec", vec) || json.error("missing field vec");
428446
}
429447
template <class T>
430448
IR::Vector<T> *IR::Vector<T>::fromJSON(JSONLoader &json) {
431449
return new Vector<T>(json);
432450
}
433451
template <class T>
434452
IR::IndexedVector<T>::IndexedVector(JSONLoader &json) : Vector<T>(json) {
435-
json.load("declarations", declarations);
453+
json.load("declarations", declarations) || json.error("missing field declarations");
436454
}
437455
template <class T>
438456
IR::IndexedVector<T> *IR::IndexedVector<T>::fromJSON(JSONLoader &json) {
@@ -442,7 +460,7 @@ template <class T, template <class K, class V, class COMP, class ALLOC> class MA
442460
class COMP /*= std::less<cstring>*/,
443461
class ALLOC /*= std::allocator<std::pair<cstring, const T*>>*/>
444462
IR::NameMap<T, MAP, COMP, ALLOC>::NameMap(JSONLoader &json) : Node(json) {
445-
json.load("symbols", symbols);
463+
json.load("symbols", symbols) || json.error("missing field symbols");
446464
}
447465
template <class T, template <class K, class V, class COMP, class ALLOC> class MAP /*= std::map */,
448466
class COMP /*= std::less<cstring>*/,

0 commit comments

Comments
 (0)