Skip to content

Commit 1dc13cc

Browse files
authored
Merge pull request github#15923 from hvitved/shared-xml-impl
Properly shared `XML.qll` implementation
2 parents cccb11f + 2e370e2 commit 1dc13cc

File tree

18 files changed

+620
-1398
lines changed

18 files changed

+620
-1398
lines changed

config/identical-files.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -251,12 +251,6 @@
251251
"cpp/ql/src/Security/CWE/CWE-020/SafeExternalAPIFunction.qll",
252252
"cpp/ql/src/Security/CWE/CWE-020/ir/SafeExternalAPIFunction.qll"
253253
],
254-
"XML": [
255-
"cpp/ql/lib/semmle/code/cpp/XML.qll",
256-
"csharp/ql/lib/semmle/code/csharp/XML.qll",
257-
"java/ql/lib/semmle/code/xml/XML.qll",
258-
"python/ql/lib/semmle/python/xml/XML.qll"
259-
],
260254
"DuplicationProblems.inc.qhelp": [
261255
"cpp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp",
262256
"javascript/ql/src/Metrics/DuplicationProblems.inc.qhelp",

cpp/ql/lib/qlpack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ dependencies:
1111
codeql/ssa: ${workspace}
1212
codeql/tutorial: ${workspace}
1313
codeql/util: ${workspace}
14+
codeql/xml: ${workspace}
1415
warnOnImplicitThis: true

cpp/ql/lib/semmle/code/cpp/XML.qll

Lines changed: 40 additions & 278 deletions
Original file line numberDiff line numberDiff line change
@@ -3,305 +3,67 @@
33
*/
44

55
import semmle.files.FileSystem
6+
private import codeql.xml.Xml
67

7-
private class TXmlLocatable =
8-
@xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters;
8+
private module Input implements InputSig<File, Location> {
9+
class XmlLocatableBase = @xmllocatable or @xmlnamespaceable;
910

10-
/** An XML element that has a location. */
11-
class XmlLocatable extends @xmllocatable, TXmlLocatable {
12-
/** Gets the source location for this element. */
13-
Location getLocation() { xmllocations(this, result) }
11+
predicate xmllocations_(XmlLocatableBase e, Location loc) { xmllocations(e, loc) }
1412

15-
/**
16-
* Holds if this element is at the specified location.
17-
* The location spans column `startcolumn` of line `startline` to
18-
* column `endcolumn` of line `endline` in file `filepath`.
19-
* For more information, see
20-
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
21-
*/
22-
predicate hasLocationInfo(
23-
string filepath, int startline, int startcolumn, int endline, int endcolumn
24-
) {
25-
exists(File f, Location l | l = this.getLocation() |
26-
locations_default(l, f, startline, startcolumn, endline, endcolumn) and
27-
filepath = f.getAbsolutePath()
28-
)
29-
}
30-
31-
/** Gets a textual representation of this element. */
32-
string toString() { none() } // overridden in subclasses
33-
}
34-
35-
/**
36-
* An `XmlParent` is either an `XmlElement` or an `XmlFile`,
37-
* both of which can contain other elements.
38-
*/
39-
class XmlParent extends @xmlparent {
40-
XmlParent() {
41-
// explicitly restrict `this` to be either an `XmlElement` or an `XmlFile`;
42-
// the type `@xmlparent` currently also includes non-XML files
43-
this instanceof @xmlelement or xmlEncoding(this, _)
44-
}
45-
46-
/**
47-
* Gets a printable representation of this XML parent.
48-
* (Intended to be overridden in subclasses.)
49-
*/
50-
string getName() { none() } // overridden in subclasses
51-
52-
/** Gets the file to which this XML parent belongs. */
53-
XmlFile getFile() { result = this or xmlElements(this, _, _, _, result) }
13+
class XmlParentBase = @xmlparent;
5414

55-
/** Gets the child element at a specified index of this XML parent. */
56-
XmlElement getChild(int index) { xmlElements(result, _, this, index, _) }
15+
class XmlNamespaceableBase = @xmlnamespaceable;
5716

58-
/** Gets a child element of this XML parent. */
59-
XmlElement getAChild() { xmlElements(result, _, this, _, _) }
17+
class XmlElementBase = @xmlelement;
6018

61-
/** Gets a child element of this XML parent with the given `name`. */
62-
XmlElement getAChild(string name) { xmlElements(result, _, this, _, _) and result.hasName(name) }
19+
class XmlFileBase = File;
6320

64-
/** Gets a comment that is a child of this XML parent. */
65-
XmlComment getAComment() { xmlComments(result, _, this, _) }
21+
predicate xmlEncoding_(XmlFileBase f, string enc) { xmlEncoding(f, enc) }
6622

67-
/** Gets a character sequence that is a child of this XML parent. */
68-
XmlCharacters getACharactersSet() { xmlChars(result, _, this, _, _, _) }
23+
class XmlDtdBase = @xmldtd;
6924

70-
/** Gets the depth in the tree. (Overridden in XmlElement.) */
71-
int getDepth() { result = 0 }
72-
73-
/** Gets the number of child XML elements of this XML parent. */
74-
int getNumberOfChildren() { result = count(XmlElement e | xmlElements(e, _, this, _, _)) }
75-
76-
/** Gets the number of places in the body of this XML parent where text occurs. */
77-
int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) }
78-
79-
/**
80-
* Gets the result of appending all the character sequences of this XML parent from
81-
* left to right, separated by a space.
82-
*/
83-
string allCharactersString() {
84-
result =
85-
concat(string chars, int pos | xmlChars(_, chars, this, pos, _, _) | chars, " " order by pos)
25+
predicate xmlDTDs_(XmlDtdBase e, string root, string publicId, string systemId, XmlFileBase file) {
26+
xmlDTDs(e, root, publicId, systemId, file)
8627
}
8728

88-
/** Gets the text value contained in this XML parent. */
89-
string getTextValue() { result = this.allCharactersString() }
90-
91-
/** Gets a printable representation of this XML parent. */
92-
string toString() { result = this.getName() }
93-
}
94-
95-
/** An XML file. */
96-
class XmlFile extends XmlParent, File {
97-
XmlFile() { xmlEncoding(this, _) }
98-
99-
/** Gets a printable representation of this XML file. */
100-
override string toString() { result = this.getName() }
101-
102-
/** Gets the name of this XML file. */
103-
override string getName() { result = File.super.getAbsolutePath() }
104-
105-
/** Gets the encoding of this XML file. */
106-
string getEncoding() { xmlEncoding(this, result) }
107-
108-
/** Gets the XML file itself. */
109-
override XmlFile getFile() { result = this }
110-
111-
/** Gets a top-most element in an XML file. */
112-
XmlElement getARootElement() { result = this.getAChild() }
113-
114-
/** Gets a DTD associated with this XML file. */
115-
XmlDtd getADtd() { xmlDTDs(result, _, _, _, this) }
116-
}
117-
118-
/**
119-
* An XML document type definition (DTD).
120-
*
121-
* Example:
122-
*
123-
* ```
124-
* <!ELEMENT person (firstName, lastName?)>
125-
* <!ELEMENT firstName (#PCDATA)>
126-
* <!ELEMENT lastName (#PCDATA)>
127-
* ```
128-
*/
129-
class XmlDtd extends XmlLocatable, @xmldtd {
130-
/** Gets the name of the root element of this DTD. */
131-
string getRoot() { xmlDTDs(this, result, _, _, _) }
132-
133-
/** Gets the public ID of this DTD. */
134-
string getPublicId() { xmlDTDs(this, _, result, _, _) }
135-
136-
/** Gets the system ID of this DTD. */
137-
string getSystemId() { xmlDTDs(this, _, _, result, _) }
138-
139-
/** Holds if this DTD is public. */
140-
predicate isPublic() { not xmlDTDs(this, _, "", _, _) }
141-
142-
/** Gets the parent of this DTD. */
143-
XmlParent getParent() { xmlDTDs(this, _, _, _, result) }
144-
145-
override string toString() {
146-
this.isPublic() and
147-
result = this.getRoot() + " PUBLIC '" + this.getPublicId() + "' '" + this.getSystemId() + "'"
148-
or
149-
not this.isPublic() and
150-
result = this.getRoot() + " SYSTEM '" + this.getSystemId() + "'"
29+
predicate xmlElements_(
30+
XmlElementBase e, string name, XmlParentBase parent, int idx, XmlFileBase file
31+
) {
32+
xmlElements(e, name, parent, idx, file)
15133
}
152-
}
153-
154-
/**
155-
* An XML element in an XML file.
156-
*
157-
* Example:
158-
*
159-
* ```
160-
* <manifest xmlns:android="http://schemas.android.com/apk/res/android"
161-
* package="com.example.exampleapp" android:versionCode="1">
162-
* </manifest>
163-
* ```
164-
*/
165-
class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
166-
/** Holds if this XML element has the given `name`. */
167-
predicate hasName(string name) { name = this.getName() }
168-
169-
/** Gets the name of this XML element. */
170-
override string getName() { xmlElements(this, result, _, _, _) }
17134

172-
/** Gets the XML file in which this XML element occurs. */
173-
override XmlFile getFile() { xmlElements(this, _, _, _, result) }
35+
class XmlAttributeBase = @xmlattribute;
17436

175-
/** Gets the parent of this XML element. */
176-
XmlParent getParent() { xmlElements(this, _, result, _, _) }
177-
178-
/** Gets the index of this XML element among its parent's children. */
179-
int getIndex() { xmlElements(this, _, _, result, _) }
180-
181-
/** Holds if this XML element has a namespace. */
182-
predicate hasNamespace() { xmlHasNs(this, _, _) }
183-
184-
/** Gets the namespace of this XML element, if any. */
185-
XmlNamespace getNamespace() { xmlHasNs(this, result, _) }
186-
187-
/** Gets the index of this XML element among its parent's children. */
188-
int getElementPositionIndex() { xmlElements(this, _, _, result, _) }
189-
190-
/** Gets the depth of this element within the XML file tree structure. */
191-
override int getDepth() { result = this.getParent().getDepth() + 1 }
192-
193-
/** Gets an XML attribute of this XML element. */
194-
XmlAttribute getAnAttribute() { result.getElement() = this }
195-
196-
/** Gets the attribute with the specified `name`, if any. */
197-
XmlAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
198-
199-
/** Holds if this XML element has an attribute with the specified `name`. */
200-
predicate hasAttribute(string name) { exists(this.getAttribute(name)) }
201-
202-
/** Gets the value of the attribute with the specified `name`, if any. */
203-
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
204-
205-
/** Gets a printable representation of this XML element. */
206-
override string toString() { result = this.getName() }
207-
}
208-
209-
/**
210-
* An attribute that occurs inside an XML element.
211-
*
212-
* Examples:
213-
*
214-
* ```
215-
* package="com.example.exampleapp"
216-
* android:versionCode="1"
217-
* ```
218-
*/
219-
class XmlAttribute extends @xmlattribute, XmlLocatable {
220-
/** Gets the name of this attribute. */
221-
string getName() { xmlAttrs(this, _, result, _, _, _) }
222-
223-
/** Gets the XML element to which this attribute belongs. */
224-
XmlElement getElement() { xmlAttrs(this, result, _, _, _, _) }
225-
226-
/** Holds if this attribute has a namespace. */
227-
predicate hasNamespace() { xmlHasNs(this, _, _) }
228-
229-
/** Gets the namespace of this attribute, if any. */
230-
XmlNamespace getNamespace() { xmlHasNs(this, result, _) }
231-
232-
/** Gets the value of this attribute. */
233-
string getValue() { xmlAttrs(this, _, _, result, _, _) }
37+
predicate xmlAttrs_(
38+
XmlAttributeBase e, XmlElementBase elementid, string name, string value, int idx,
39+
XmlFileBase file
40+
) {
41+
xmlAttrs(e, elementid, name, value, idx, file)
42+
}
23443

235-
/** Gets a printable representation of this XML attribute. */
236-
override string toString() { result = this.getName() + "=" + this.getValue() }
237-
}
44+
class XmlNamespaceBase = @xmlnamespace;
23845

239-
/**
240-
* A namespace used in an XML file.
241-
*
242-
* Example:
243-
*
244-
* ```
245-
* xmlns:android="http://schemas.android.com/apk/res/android"
246-
* ```
247-
*/
248-
class XmlNamespace extends XmlLocatable, @xmlnamespace {
249-
/** Gets the prefix of this namespace. */
250-
string getPrefix() { xmlNs(this, result, _, _) }
46+
predicate xmlNs_(XmlNamespaceBase e, string prefixName, string uri, XmlFileBase file) {
47+
xmlNs(e, prefixName, uri, file)
48+
}
25149

252-
/** Gets the URI of this namespace. */
253-
string getUri() { xmlNs(this, _, result, _) }
50+
predicate xmlHasNs_(XmlNamespaceableBase e, XmlNamespaceBase ns, XmlFileBase file) {
51+
xmlHasNs(e, ns, file)
52+
}
25453

255-
/** Holds if this namespace has no prefix. */
256-
predicate isDefault() { this.getPrefix() = "" }
54+
class XmlCommentBase = @xmlcomment;
25755

258-
override string toString() {
259-
this.isDefault() and result = this.getUri()
260-
or
261-
not this.isDefault() and result = this.getPrefix() + ":" + this.getUri()
56+
predicate xmlComments_(XmlCommentBase e, string text, XmlParentBase parent, XmlFileBase file) {
57+
xmlComments(e, text, parent, file)
26258
}
263-
}
264-
265-
/**
266-
* A comment in an XML file.
267-
*
268-
* Example:
269-
*
270-
* ```
271-
* <!-- This is a comment. -->
272-
* ```
273-
*/
274-
class XmlComment extends @xmlcomment, XmlLocatable {
275-
/** Gets the text content of this XML comment. */
276-
string getText() { xmlComments(this, result, _, _) }
27759

278-
/** Gets the parent of this XML comment. */
279-
XmlParent getParent() { xmlComments(this, _, result, _) }
60+
class XmlCharactersBase = @xmlcharacters;
28061

281-
/** Gets a printable representation of this XML comment. */
282-
override string toString() { result = this.getText() }
62+
predicate xmlChars_(
63+
XmlCharactersBase e, string text, XmlParentBase parent, int idx, int isCDATA, XmlFileBase file
64+
) {
65+
xmlChars(e, text, parent, idx, isCDATA, file)
66+
}
28367
}
28468

285-
/**
286-
* A sequence of characters that occurs between opening and
287-
* closing tags of an XML element, excluding other elements.
288-
*
289-
* Example:
290-
*
291-
* ```
292-
* <content>This is a sequence of characters.</content>
293-
* ```
294-
*/
295-
class XmlCharacters extends @xmlcharacters, XmlLocatable {
296-
/** Gets the content of this character sequence. */
297-
string getCharacters() { xmlChars(this, result, _, _, _, _) }
298-
299-
/** Gets the parent of this character sequence. */
300-
XmlParent getParent() { xmlChars(this, _, result, _, _, _) }
301-
302-
/** Holds if this character sequence is CDATA. */
303-
predicate isCDATA() { xmlChars(this, _, _, _, 1, _) }
304-
305-
/** Gets a printable representation of this XML character sequence. */
306-
override string toString() { result = this.getCharacters() }
307-
}
69+
import Make<File, Location, Input>

csharp/ql/lib/qlpack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dependencies:
1313
codeql/threat-models: ${workspace}
1414
codeql/tutorial: ${workspace}
1515
codeql/util: ${workspace}
16+
codeql/xml: ${workspace}
1617
dataExtensions:
1718
- ext/*.model.yml
1819
- ext/generated/*.model.yml

0 commit comments

Comments
 (0)