• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <cstring>
19 #include <regex>
20 
21 #include "gtest/gtest.h"
22 #include "modules.h"
23 
24 namespace {
25 constexpr const char* kSectionNameRegex = "\\[\\s*([\\w.]+)\\s*\\]";
26 constexpr const char* kDirRegex = "dir\\.([\\w.]+)\\s*=\\s*([\\w_.\\-/]+)";
27 constexpr const char* kNamespaceBaseRegex =
28     "namespace\\.(\\w+)\\.([^\\s=]+)\\s*(=|\\+=)\\s*([^\\s]+)";
29 constexpr const char* kAdditionalNamespacesRegex =
30     "additional\\.namespaces\\s*=\\s*((?:[\\w]+)(?:,[\\w]+)*)";
31 
32 // Functions to parse configuration string and verify syntax
33 
ParseDirPath(const std::string & line,Configuration & conf)34 inline void ParseDirPath(const std::string& line, Configuration& conf) {
35   static std::regex dir_regex(kDirRegex);
36   std::smatch match;
37 
38   ASSERT_TRUE(std::regex_match(line, match, dir_regex)) << line;
39   ASSERT_EQ(3u, match.size()) << line;
40   std::string section_name = match[1];
41   std::string dir_path = match[2];
42 
43   if (!MapContainsKey(conf.sections, section_name)) {
44     conf.sections[section_name].name = section_name;
45     conf.sections[section_name].namespaces["default"].name = "default";
46   }
47 
48   conf.sections[section_name].dirs.push_back(dir_path);
49 }
50 
ParseAdditionalNamespaces(const std::smatch & match,Section & current_section)51 inline void ParseAdditionalNamespaces(const std::smatch& match,
52                                       Section& current_section) {
53   // additional.namespace = a,b,c,e,d
54   ASSERT_EQ(2u, match.size());
55   std::stringstream namespaces(match[1]);
56   for (std::string namespace_name;
57        std::getline(namespaces, namespace_name, ',');) {
58     EXPECT_FALSE(MapContainsKey(current_section.namespaces, namespace_name))
59         << "Namespace " << namespace_name << " already exists";
60     Namespace new_namespace;
61     new_namespace.name = namespace_name;
62     current_section.namespaces[namespace_name] = new_namespace;
63   }
64 }
65 
ParseNamespacePath(const std::vector<std::string> & property_descs,const bool is_additional,const std::string & path,Namespace & current_namespace,const std::string & line)66 inline void ParseNamespacePath(const std::vector<std::string>& property_descs,
67                                const bool is_additional, const std::string& path,
68                                Namespace& current_namespace,
69                                const std::string& line) {
70   // namespace.test.(asan.)search|permitted.path =|+= /path/to/${LIB}/dir
71   ASSERT_EQ(
72       property_descs[0] == "asan" || property_descs[0] == "hwasan" ? 3u : 2u,
73       property_descs.size());
74 
75   std::vector<std::string>* target_path = nullptr;
76   if (property_descs[0] == "search") {
77     target_path = &current_namespace.search_path;
78   } else if (property_descs[0] == "permitted") {
79     target_path = &current_namespace.permitted_path;
80   } else if (property_descs[0] == "asan" && property_descs[1] == "search") {
81     target_path = &current_namespace.asan_search_path;
82   } else if (property_descs[0] == "asan" && property_descs[1] == "permitted") {
83     target_path = &current_namespace.asan_permitted_path;
84   } else if (property_descs[0] == "hwasan" && property_descs[1] == "search") {
85     target_path = &current_namespace.hwasan_search_path;
86   } else if (property_descs[0] == "hwasan" &&
87              property_descs[1] == "permitted") {
88     target_path = &current_namespace.hwasan_permitted_path;
89   }
90 
91   ASSERT_NE(nullptr, target_path) << line;
92   EXPECT_EQ(is_additional, target_path->size() != 0)
93       << "Path should be marked as = if and only if it is mentioned first : "
94       << line;
95 
96   target_path->push_back(path);
97 }
98 
ParseLinkList(const std::vector<std::string> & property_descs,const std::string & target_namespaces,Namespace & current_namespace,Section & current_section,const std::string & line)99 inline void ParseLinkList(const std::vector<std::string>& property_descs,
100                           const std::string& target_namespaces,
101                           Namespace& current_namespace,
102                           Section& current_section, const std::string& line) {
103   // namespace.test.links = a,b,c,d,e
104   EXPECT_EQ(1u, property_descs.size());
105   std::stringstream namespaces(target_namespaces);
106   for (std::string namespace_to; std::getline(namespaces, namespace_to, ',');) {
107     EXPECT_FALSE(MapContainsKey(current_namespace.links, namespace_to))
108         << "Link to " << namespace_to << " is already defined : " << line;
109     EXPECT_TRUE(MapContainsKey(current_section.namespaces, namespace_to))
110         << "Target namespace " << namespace_to
111         << " is not defined in section : " << line;
112 
113     current_namespace.links[namespace_to].from = &current_namespace;
114     current_namespace.links[namespace_to].to =
115         &current_section.namespaces[namespace_to];
116     current_namespace.links[namespace_to].allow_all_shared = false;
117   }
118 }
119 
ParseLink(const std::vector<std::string> & property_descs,const bool is_additional,const std::string & value,Namespace & current_namespace,Section & current_section,const std::string & line)120 inline void ParseLink(const std::vector<std::string>& property_descs,
121                       const bool is_additional, const std::string& value,
122                       Namespace& current_namespace, Section& current_section,
123                       const std::string& line) {
124   // namespace.from.link.to.shared_libs = a.so
125   // namespace.from.link.to.allow_all_shared_libs = true
126   ASSERT_EQ(3u, property_descs.size()) << line;
127   ASSERT_TRUE(property_descs[2] == "shared_libs" ||
128               property_descs[2] == "allow_all_shared_libs")
129       << line;
130   std::string namespace_to = property_descs[1];
131 
132   ASSERT_TRUE(MapContainsKey(current_section.namespaces, namespace_to))
133       << "To namespace does not exist in section " << current_section.name
134       << " : " << line;
135 
136   if (property_descs[2] == "shared_libs") {
137     EXPECT_EQ(is_additional,
138               current_namespace.links[namespace_to].shared_libs.size() != 0)
139         << "Link should be defined with = if and only if it is first link "
140            "between two namespaces : "
141         << line;
142 
143     current_namespace.links[namespace_to].shared_libs.push_back(value);
144   } else {
145     EXPECT_EQ("true", value) << line;
146     current_namespace.links[namespace_to].allow_all_shared = true;
147   }
148 }
149 
ParseNamespaceCommand(const std::string & namespace_name,const std::string & property_desc,const bool is_additional_property,const std::string & value,Section & current_section,const std::string & line)150 inline void ParseNamespaceCommand(const std::string& namespace_name,
151                                   const std::string& property_desc,
152                                   const bool is_additional_property,
153                                   const std::string& value,
154                                   Section& current_section,
155                                   const std::string& line) {
156   ASSERT_TRUE(MapContainsKey(current_section.namespaces, namespace_name))
157       << "Namespace " << namespace_name << " does not exist in section "
158       << current_section.name << " : " << line;
159   Namespace& current_namespace = current_section.namespaces[namespace_name];
160 
161   std::vector<std::string> property_descs;
162   std::stringstream property_desc_stream(property_desc);
163   for (std::string property;
164        std::getline(property_desc_stream, property, '.');) {
165     property_descs.push_back(property);
166   }
167 
168   ASSERT_TRUE(property_descs.size() > 0)
169       << "There should be at least one property description after namespace."
170       << namespace_name << " : " << line;
171 
172   if (property_descs[0].compare("isolated") == 0) {
173     // namespace.test.isolated = true
174     EXPECT_EQ(1u, property_descs.size()) << line;
175     EXPECT_TRUE(value == "true" || value == "false") << line;
176     current_namespace.is_isolated = value == "true";
177   } else if (property_descs[0].compare("visible") == 0) {
178     // namespace.test.visible = true
179     EXPECT_EQ(1u, property_descs.size()) << line;
180     EXPECT_TRUE(value == "true" || value == "false") << line;
181     current_namespace.is_visible = value == "true";
182   } else if (property_descs[property_descs.size() - 1] == "paths") {
183     // namespace.test.search.path += /system/lib
184     ParseNamespacePath(
185         property_descs, is_additional_property, value, current_namespace, line);
186   } else if (property_descs[0] == "links") {
187     // namespace.test.links = a,b,c
188     ParseLinkList(
189         property_descs, value, current_namespace, current_section, line);
190   } else if (property_descs[0] == "link") {
191     // namespace.test.link.a = libc.so
192     ParseLink(property_descs,
193               is_additional_property,
194               value,
195               current_namespace,
196               current_section,
197               line);
198   } else if (property_descs[0] == "allowed_libs") {
199     EXPECT_EQ(1u, property_descs.size()) << line;
200     current_namespace.allowed_libs.push_back(value);
201   } else {
202     EXPECT_TRUE(false) << "Failed to parse line : " << line;
203   }
204 }
205 }  // namespace
206 
ParseConfiguration(const std::string & configuration_str,Configuration & conf)207 inline void ParseConfiguration(const std::string& configuration_str,
208                                Configuration& conf) {
209   Section* current_section = nullptr;
210 
211   static std::regex section_name_regex(kSectionNameRegex);
212   static std::regex additional_namespaces_regex(kAdditionalNamespacesRegex);
213   static std::regex namespace_base_regex(kNamespaceBaseRegex);
214 
215   std::smatch match;
216 
217   std::stringstream configuration_stream(configuration_str);
218 
219   for (std::string line; std::getline(configuration_stream, line);) {
220     // Skip empty line
221     if (line.empty()) {
222       continue;
223     }
224 
225     if (std::regex_match(line, match, section_name_regex)) {
226       // [section_name]
227       ASSERT_EQ(2u, match.size()) << line;
228       std::string section_name = match[1];
229       ASSERT_TRUE(MapContainsKey(conf.sections, section_name)) << line;
230       current_section = &conf.sections[section_name];
231 
232       continue;
233     }
234 
235     if (current_section == nullptr) {
236       ParseDirPath(line, conf);
237     } else {
238       if (std::regex_match(line, match, additional_namespaces_regex)) {
239         ParseAdditionalNamespaces(match, *current_section);
240       } else {
241         EXPECT_TRUE(std::regex_match(line, match, namespace_base_regex)) << line;
242         ASSERT_EQ(5u, match.size()) << line;
243         std::string namespace_name = match[1];
244         std::string property_desc = match[2];
245         bool is_additional_property = match[3] == "+=";
246         std::string content = match[4];
247         ParseNamespaceCommand(namespace_name,
248                               property_desc,
249                               is_additional_property,
250                               content,
251                               *current_section,
252                               line);
253       }
254     }
255   }
256 }
257