1/*
2 * Copyright (c) 2015-2017, Intel Corporation
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * * Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of Intel Corporation nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** \file
30 * \brief Component tree analysis that checks that references (such as
31 * back-refs, conditionals) have valid referents.
32 */
33#include "check_refs.h"
34#include "ComponentBackReference.h"
35#include "ComponentCondReference.h"
36#include "ConstComponentVisitor.h"
37#include "parse_error.h"
38#include "util/container.h"
39#include "util/flat_containers.h"
40
41#include <sstream>
42
43using namespace std;
44
45namespace ue2 {
46
47/**
48 * \brief Visitor that checks the validity of references against a known list
49 * of indices and labels.
50 */
51class ReferenceVisitor: public DefaultConstComponentVisitor {
52private:
53 const size_t num_ids;
54 const flat_set<string> &names;
55
56public:
57 ReferenceVisitor(size_t num_groups, const flat_set<string> &targets)
58 : num_ids(num_groups), names(targets) {}
59
60 ~ReferenceVisitor() override;
61
62 void invalid_index(const char *component, unsigned id) {
63 assert(component);
64 ostringstream str;
65 str << "Invalid " << component << " to expression " << id << ".";
66 throw ParseError(str.str());
67 }
68
69 void invalid_label(const char *component, const std::string &label) {
70 assert(component);
71 ostringstream str;
72 str << "Invalid " << component << " to label '" << label << "'.";
73 throw ParseError(str.str());
74 }
75
76 using DefaultConstComponentVisitor::pre;
77
78 void pre(const ComponentBackReference &c) override {
79 if (c.ref_id) {
80 if (c.ref_id >= num_ids) {
81 invalid_index("back reference", c.ref_id);
82 }
83 } else {
84 if (!contains(names, c.name)) {
85 invalid_label("back reference", c.name);
86 }
87 }
88 }
89
90 void pre(const ComponentCondReference &c) override {
91 switch (c.kind) {
92 case ComponentCondReference::CONDITION_NUMBER:
93 if (c.ref_id >= num_ids) {
94 invalid_index("conditional reference", c.ref_id);
95 }
96 break;
97 case ComponentCondReference::CONDITION_NAME:
98 if (c.ref_name == "DEFINE") {
99 // The string "DEFINE" is a special "always false" condition
100 // used to define subroutines.
101 break;
102 }
103 if (!contains(names, c.ref_name)) {
104 invalid_label("conditional reference", c.ref_name);
105 }
106 break;
107 case ComponentCondReference::CONDITION_ASSERTION:
108 break;
109 }
110 }
111};
112
113// Out-of-line destructor to silence weak vtable warnings.
114ReferenceVisitor::~ReferenceVisitor() {}
115
116void checkReferences(const Component &root, unsigned int groupIndices,
117 const flat_set<std::string> &groupNames) {
118 ReferenceVisitor vis(groupIndices, groupNames);
119 root.accept(vis);
120}
121
122} // namespace ue2
123