diff options
author | trav90 <travawine@protonmail.ch> | 2015-12-04 17:07:29 -0600 |
---|---|---|
committer | trav90 <travawine@protonmail.ch> | 2015-12-04 17:07:29 -0600 |
commit | 773b1154970428172e80ea737d5f4506a2823493 (patch) | |
tree | 9b2f3c8f8f7e6aaa512ac492a32e7e5702c5d6c1 /xpcom | |
parent | 5e7e0080bb7452e3c63b5f990fa6f6ee3d3c3aeb (diff) | |
download | palemoon-gre-773b1154970428172e80ea737d5f4506a2823493.tar.gz |
Remove GCC-dehydra support
Diffstat (limited to 'xpcom')
25 files changed, 0 insertions, 2471 deletions
diff --git a/xpcom/analysis/MDC-attach.py b/xpcom/analysis/MDC-attach.py deleted file mode 100755 index bbeae6f6d..000000000 --- a/xpcom/analysis/MDC-attach.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -""" -Upload a file attachment to MDC - -Usage: python MDC-attach.py <file> <parent page name> <MIME type> <description> -Please set MDC_USER and MDC_PASSWORD in the environment -""" - -import os, sys, deki - -wikiuser = os.environ['MDC_USER'] -wikipw = os.environ['MDC_PASSWORD'] - -file, pageid, mimetype, description = sys.argv[1:] - -wiki = deki.Deki("http://developer.mozilla.org/@api/deki/", wikiuser, wikipw) -wiki.create_file(pageid, os.path.basename(file), open(file).read(), mimetype, - description) diff --git a/xpcom/analysis/MDC-upload.py b/xpcom/analysis/MDC-upload.py deleted file mode 100755 index e1691308f..000000000 --- a/xpcom/analysis/MDC-upload.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -""" -Upload a page to MDC - -Usage: python MDC-upload.py <file> <MDC-path> -Please set MDC_USER and MDC_PASSWORD in the environment -""" - -import os, sys, deki - -wikiuser = os.environ['MDC_USER'] -wikipw = os.environ['MDC_PASSWORD'] - -(file, wikipath) = sys.argv[1:] - -wiki = deki.Deki("http://developer.mozilla.org/@api/deki/", wikiuser, wikipw) -wiki.create_page(wikipath, open(file).read(), overwrite=True) diff --git a/xpcom/analysis/Makefile.in b/xpcom/analysis/Makefile.in deleted file mode 100644 index 96d99f9af..000000000 --- a/xpcom/analysis/Makefile.in +++ /dev/null @@ -1,53 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DEPTH = @DEPTH@ -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -MOZILLA_INTERNAL_API = 1 - -include $(topsrcdir)/config/rules.mk - -DUMP_CLASSES = \ - nsAString_internal \ - nsACString_internal \ - $(NULL) - -SPACE = $(NULL) $(NULL) -COMMA = , - -HGREV = $(shell hg -R $(topsrcdir) id -i) - -classapi: DEHYDRA_MODULES = $(srcdir)/type-printer.js -classapi: TREEHYDRA_MODULES = -classapi: DEHYDRA_ARGS += --dump-types=$(subst $(SPACE),$(COMMA),$(strip $(DUMP_CLASSES))) --rev=$(HGREV) -classapi: $(call mkdir_deps,$(MDDEPDIR)) - $(CCC) $(OUTOPTION)/dev/null -c $(COMPILE_CXXFLAGS) $(srcdir)/type-printer.cpp >classapi.out 2>&1 - perl -e 'while (<>) {if (/DUMP-TYPE\((.*)\)/) {print "$$1 ";}}' <classapi.out >dumptypes.list - perl -e 'while (<>) {if (/GRAPH-TYPE\((.*)\)/) {print "$$1 ";}}' <classapi.out >graphtypes.list - $(EXIT_ON_ERROR) \ - for class in `cat graphtypes.list`; do \ - dot -Tpng -o$${class}-graph.png -Tcmapx -o$${class}-graph.map $${class}-graph.gv; \ - done - $(EXIT_ON_ERROR) \ - for class in `cat dumptypes.list`; do \ - $(PYTHON) $(srcdir)/fix-srcrefs.py $(topsrcdir) < $${class}.html > $${class}-fixed.html; \ - done - -upload_classapi: - $(EXIT_ON_ERROR) \ - for class in `cat dumptypes.list`; do \ - $(PYTHON) $(srcdir)/MDC-upload.py $${class}-fixed.html en/$${class}; \ - done - $(EXIT_ON_ERROR) \ - for class in `cat graphtypes.list`; do \ - $(PYTHON) $(srcdir)/MDC-attach.py $${class}-graph.png en/$${class} "image/png" "Class inheritance graph"; \ - done - -GARBAGE += $(wildcard *.html) $(wildcard *.png) $(wildcard *.map) \ - $(wildcard *.gv) classapi.out graphtypes.list dumptypes.list diff --git a/xpcom/analysis/deki.py b/xpcom/analysis/deki.py deleted file mode 100644 index 52814a6de..000000000 --- a/xpcom/analysis/deki.py +++ /dev/null @@ -1,346 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -""" deki.py - Access the wiki pages on a MindTouch Deki server via the API. - -Here's what this code can do: - - wiki = deki.Deki("http://developer.mozilla.org/@api/deki/", username, password) - page = wiki.get_page("Sheep") - print page.title - print page.doc.toxml() - - page.title = "Bananas" - page.save() - -There are also some additional methods: - wiki.create_page(path, content, title=, override=) - wiki.move_page(old, new) - wiki.get_subpages(page) - -This module does not try to mimic the MindTouch "Plug" API. It's meant to be -higher-level than that. -""" - -import sys -import urllib2, cookielib, httplib -import xml.dom.minidom as dom -from urllib import quote as _urllib_quote -from urllib import urlencode as _urlencode -import urlparse -from datetime import datetime -import re - -__all__ = ['Deki'] - - -# === Utils - -def _check(fact): - if not fact: - raise AssertionError('check failed') - -def _urlquote(s, *args): - return _urllib_quote(s.encode('utf-8'), *args) - -def _make_url(*dirs, **params): - """ dirs must already be url-encoded, params must not """ - url = '/'.join(dirs) - if params: - url += '?' + _urlencode(params) - return url - -class PutRequest(urllib2.Request): - def get_method(self): - return "PUT" - -# === Dream framework client code - -# This handler causes python to "always be logged in" when it's talking to the -# server. If you're just accessing public pages, it generates more requests -# than are strictly needed, but this is the behavior you want for a bot. -# -# The users/authenticate request is sent twice: once without any basic auth and -# once with. Dumb. Feel free to fix. -# -class _LoginHandler(urllib2.HTTPCookieProcessor): - def __init__(self, server): - policy = cookielib.DefaultCookiePolicy(rfc2965=True) - cookiejar = cookielib.CookieJar(policy) - urllib2.HTTPCookieProcessor.__init__(self, cookiejar) - self.server = server - - def http_request(self, req): - #print "DEBUG- Requesting " + req.get_full_url() - s = self.server - req = urllib2.HTTPCookieProcessor.http_request(self, req) - if ('Cookie' not in req.unredirected_hdrs - and req.get_full_url() != s.base + 'users/authenticate'): - s.login() - # Retry - should have a new cookie. - req = urllib2.HTTPCookieProcessor.http_request(self, req) - _check('Cookie' in req.unredirected_hdrs) - return req - -class DreamClient: - def __init__(self, base, user, password): - """ - base - The base URI of the Deki API, with trailing slash. - Typically, 'http://wiki.example.org/@api/deki/'. - user, password - Your Deki login information. - """ - self.base = base - pm = urllib2.HTTPPasswordMgrWithDefaultRealm() - pm.add_password(None, self.base, user, password) - ah = urllib2.HTTPBasicAuthHandler(pm) - lh = _LoginHandler(self) - self._opener = urllib2.build_opener(ah, lh) - - def login(self): - response = self._opener.open(self.base + 'users/authenticate') - response.close() - - def open(self, url): - return self._opener.open(self.base + url) - - def _handleResponse(self, req): - """Helper method shared between post() and put()""" - resp = self._opener.open(req) - try: - ct = resp.headers.get('Content-Type', '(none)') - if '/xml' in ct or '+xml' in ct: - return dom.parse(resp) - else: - #print "DEBUG- Content-Type:", ct - crud = resp.read() - #print 'DEBUG- crud:\n---\n%s\n---' % re.sub(r'(?m)^', ' ', crud) - return None - finally: - resp.close() - - - def post(self, url, data, type): - #print "DEBUG- posting to:", self.base + url - req = urllib2.Request(self.base + url, data, {'Content-Type': type}) - return self._handleResponse(req) - - def put(self, url, data, type): - #print "DEBUG- putting to:", self.base + url - req = PutRequest(self.base + url, data, {'Content-Type': type}) - return self._handleResponse(req) - - def get_xml(self, url): - resp = self.open(url) - try: - return dom.parse(resp) - finally: - resp.close() - - -# === DOM - -def _text_of(node): - if node.nodeType == node.ELEMENT_NODE: - return u''.join(_text_of(n) for n in node.childNodes) - elif node.nodeType == node.TEXT_NODE: - return node.nodeValue - else: - return u'' - -def _the_element_by_name(doc, tagName): - elts = doc.getElementsByTagName(tagName) - if len(elts) != 1: - raise ValueError("Expected exactly one <%s> tag, got %d." % (tagName, len(elts))) - return elts[0] - -def _first_element(node): - n = node.firstChild - while n is not None: - if n.nodeType == n.ELEMENT_NODE: - return n - n = node.nextSibling - return None - -def _find_elements(node, path): - if u'/' in path: - [first, rest] = path.split(u'/', 1) - for child in _find_elements(node, first): - for desc in _find_elements(child, rest): - yield desc - else: - for n in node.childNodes: - if n.nodeType == node.ELEMENT_NODE and n.nodeName == path: - yield n - - -# === Deki - -def _format_page_id(id): - if isinstance(id, int): - return str(id) - elif id is Deki.HOME: - return 'home' - elif isinstance(id, basestring): - # Double-encoded, per the Deki API reference. - return '=' + _urlquote(_urlquote(id, '')) - -class Deki(DreamClient): - HOME = object() - - def get_page(self, page_id): - """ Get the content of a page from the wiki. - - The page_id argument must be one of: - an int - The page id (an arbitrary number assigned by Deki) - a str - The page name (not the title, the full path that shows up in the URL) - Deki.HOME - Refers to the main page of the wiki. - - Returns a Page object. - """ - p = Page(self) - p._load(page_id) - return p - - def create_page(self, path, content, title=None, overwrite=False): - """ Create a new wiki page. - - Parameters: - path - str - The page id. - content - str - The XML content to put in the new page. - The document element must be a <body>. - title - str - The page title. Keyword argument only. - Defaults to the last path-segment of path. - overwrite - bool - Whether to overwrite an existing page. If false, - and the page already exists, the method will throw an error. - """ - if title is None: - title = path.split('/')[-1] - doc = dom.parseString(content) - _check(doc.documentElement.tagName == 'body') - p = Page(self) - p._create(path, title, doc, overwrite) - - def attach_file(self, page, name, data, mimetype, description=None): - """Create or update a file attachment. - - Parameters: - page - str - the page ID this file is related to - name - str - the name of the file - data - str - the file data - mimetype - str - the MIME type of the file - description - str - a description of the file - """ - - p = {} - if description is not None: - p['description'] = description - - url = _make_url('pages', _format_page_id(page), - 'files', _format_page_id(name), **p) - - r = self.put(url, data, mimetype) - _check(r.documentElement.nodeName == u'file') - - def get_subpages(self, page_id): - """ Return the ids of all subpages of the given page. """ - doc = self.get_xml(_make_url("pages", _format_page_id(page_id), - "files,subpages")) - for elt in _find_elements(doc, u'page/subpages/page.subpage/path'): - yield _text_of(elt) - - def move_page(self, page_id, new_title, redirects=True): - """ Move an existing page to a new location. - - A page cannot be moved to a destination that already exists, is a - descendant, or has a protected title (ex. Special:xxx, User:, - Template:). - - When a page is moved, subpages under the specified page are also moved. - For each moved page, the system automatically creates an alias page - that redirects from the old to the new destination. - """ - self.post(_make_url("pages", _format_page_id(page_id), "move", - to=new_title, - redirects=redirects and "1" or "0"), - "", "text/plain") - -class Page: - """ A Deki wiki page. - - To obtain a page, call wiki.get_page(id). - Attributes: - title : unicode - The page title. - doc : Document - The content of the page as a DOM Document. - The root element of this document is a <body>. - path : unicode - The path. Use this to detect redirects, as otherwise - page.save() will overwrite the redirect with a copy of the content! - deki : Deki - The Deki object from which the page was loaded. - page_id : str/id/Deki.HOME - The page id used to load the page. - load_time : datetime - The time the page was loaded, - according to the clock on the client machine. - Methods: - save() - Save the modified document back to the server. - Only the page.title and the contents of page.doc are saved. - """ - - def __init__(self, deki): - self.deki = deki - - def _create(self, path, title, doc, overwrite): - self.title = title - self.doc = doc - self.page_id = path - if overwrite: - self.load_time = datetime(2500, 1, 1) - else: - self.load_time = datetime(1900, 1, 1) - self.path = path - self.save() - - def _load(self, page_id): - """ page_id - See comment near the definition of `HOME`. """ - load_time = datetime.utcnow() - - # Getting the title is a whole separate query! - url = 'pages/%s/info' % _format_page_id(page_id) - doc = self.deki.get_xml(url) - title = _text_of(_the_element_by_name(doc, 'title')) - path = _text_of(_the_element_by_name(doc, 'path')) - - # If you prefer to sling regexes, you can request format=raw instead. - # The result is an XML document with one big fat text node in the body. - url = _make_url('pages', _format_page_id(page_id), 'contents', - format='xhtml', mode='edit') - doc = self.deki.get_xml(url) - - content = doc.documentElement - _check(content.tagName == u'content') - body = _first_element(content) - _check(body is not None) - _check(body.tagName == u'body') - - doc.removeChild(content) - doc.appendChild(body) - - self.page_id = page_id - self.load_time = load_time - self.title = title - self.path = path - self.doc = doc - - def save(self): - p = {'edittime': _urlquote(self.load_time.strftime('%Y%m%d%H%M%S')), - 'abort': 'modified'} - - if self.title is not None: - p['title'] = _urlquote(self.title) - - url = _make_url('pages', _format_page_id(self.page_id), 'contents', **p) - - body = self.doc.documentElement - bodyInnerXML = ''.join(n.toxml('utf-8') for n in body.childNodes) - - reply = self.deki.post(url, bodyInnerXML, 'text/plain; charset=utf-8') - _check(reply.documentElement.nodeName == u'edit') - _check(reply.documentElement.getAttribute(u'status') == u'success') diff --git a/xpcom/analysis/fix-srcrefs.py b/xpcom/analysis/fix-srcrefs.py deleted file mode 100755 index 30cc9efea..000000000 --- a/xpcom/analysis/fix-srcrefs.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -""" -Fix references to source files of the form [LOCpath] -so that they are relative to a given source directory. - -Substitute the DOT-generated image map into the document. -""" - -import os, sys, re - -(srcdir, ) = sys.argv[1:] -srcdir = os.path.realpath(srcdir) - -f = re.compile(r'\[LOC(.*?)\]') - -def replacer(m): - file = m.group(1) - file = os.path.realpath(file) - if not file.startswith(srcdir): - raise Exception("File %s doesn't start with %s" % (file, srcdir)) - - file = file[len(srcdir) + 1:] - return file - -s = re.compile(r'\[MAP(.*?)\]') - -def mapreplace(m): - file = m.group(1) - c = open(file).read() - return c - -for line in sys.stdin: - line = f.sub(replacer, line) - line = s.sub(mapreplace, line) - - sys.stdout.write(line) diff --git a/xpcom/analysis/flow.js b/xpcom/analysis/flow.js deleted file mode 100644 index 5153f3056..000000000 --- a/xpcom/analysis/flow.js +++ /dev/null @@ -1,150 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -require({ version: '1.8' }); -require({ after_gcc_pass: 'cfg' }); - -include('treehydra.js'); - -include('util.js'); -include('gcc_util.js'); -include('gcc_print.js'); -include('unstable/adts.js'); -include('unstable/analysis.js'); -include('unstable/esp.js'); - -/* This implements the control flows-through analysis in bug 432917 */ -var Zero_NonZero = {} -include('unstable/zero_nonzero.js', Zero_NonZero); - -MapFactory.use_injective = true; - -// Print a trace for each function analyzed -let TRACE_FUNCTIONS = 0; -// Trace operation of the ESP analysis, use 2 or 3 for more detail -let TRACE_ESP = 0; -// Print time-taken stats -let TRACE_PERF = 0; - -function process_tree(fndecl) { - // At this point we have a function we want to analyze - if (TRACE_FUNCTIONS) { - print('* function ' + decl_name(fndecl)); - print(' ' + loc_string(location_of(fndecl))); - } - if (TRACE_PERF) timer_start(fstring); - - let cfg = function_decl_cfg(fndecl); - - try { - let trace = TRACE_ESP; - let a = new FlowCheck(cfg, trace); - a.run(); - } catch (e if e == "skip") { - return - } - print("checked " + decl_name(fndecl)) - if (cfg.x_exit_block_ptr.stateIn.substates) - for each (let substate in cfg.x_exit_block_ptr.stateIn.substates.getValues()) { - for each (let v in substate.getVariables()) { - let var_state= substate.get (v) - let blame = substate.getBlame(v) - if (var_state != ESP.TOP && typeof var_state == 'string') - error(decl_name(fndecl) + ": Control did not flow through " +var_state, location_of(blame)) - } - } - - if (TRACE_PERF) timer_stop(fstring); -} - -let track_return_loc = 0; -const FLOW_THROUGH = "MUST_FLOW_THROUGH" - -function FlowCheck(cfg, trace) { - let found = create_decl_set(); // ones we already found - for (let bb in cfg_bb_iterator(cfg)) { - for (let isn in bb_isn_iterator(bb)) { - switch (isn.tree_code()) { - case GIMPLE_CALL: { - let fn = gimple_call_fndecl(isn) - if (!fn || decl_name(fn) != FLOW_THROUGH) - continue; - this.must_flow_fn = fn - break - } - case GIMPLE_RETURN: - let ret_expr = return_expr(isn); - if (track_return_loc && ret_expr) { - TREE_CHECK(ret_expr, VAR_DECL, RESULT_DECL); - this.rval = ret_expr; - } - break; - } - } - } - if (!this.must_flow_fn) - throw "skip" - - let psvar_list = [new ESP.PropVarSpec(this.must_flow_fn, true)] - - if (this.rval) - psvar_list.push(new ESP.PropVarSpec(this.rval)) - - this.zeroNonzero = new Zero_NonZero.Zero_NonZero() - ESP.Analysis.call(this, cfg, psvar_list, Zero_NonZero.meet, trace); -} - -FlowCheck.prototype = new ESP.Analysis; - -function char_star_arg2string(tree) { - return TREE_STRING_POINTER(tree.tree_check(ADDR_EXPR).operands()[0].tree_check(ARRAY_REF).operands()[0]) -} - -// State transition function. Mostly, we delegate everything to -// another function as either an assignment or a call. -FlowCheck.prototype.flowState = function(isn, state) { - switch (TREE_CODE(isn)) { - case GIMPLE_CALL: { - let fn = gimple_call_fndecl(isn) - if (fn == this.must_flow_fn) - state.assignValue(fn, char_star_arg2string(gimple_call_arg(isn, 0)), isn) - break - } - case GIMPLE_LABEL: { - let label = decl_name(gimple_op(isn, 0)) - for ([value, blame] in state.yieldPreconditions(this.must_flow_fn)) { - if (label != value) continue - // reached the goto label we wanted =D - state.assignValue(this.must_flow_fn, ESP.TOP, isn) - } - break - } - case GIMPLE_RETURN: - for ([value, blame] in state.yieldPreconditions(this.must_flow_fn)) { - if (typeof value != 'string') continue - let loc; - if (this.rval) - for ([value, blame] in state.yieldPreconditions(this.rval)) { - loc = value - break - } - error("return without going through label "+ value, loc); - return - } - break - case GIMPLE_ASSIGN: - if (track_return_loc && gimple_op(isn, 0) == this.rval) { - state.assignValue(this.rval, location_of(isn), isn) - break - } - default: - this.zeroNonzero.flowState(isn, state) - } -} - -// State transition function to apply branch filters. This is kind -// of boilerplate--we're just handling some stuff that GCC generates. -FlowCheck.prototype.flowStateCond = function(isn, truth, state) { - this.zeroNonzero.flowStateCond (isn, truth, state) -} diff --git a/xpcom/analysis/mayreturn.js b/xpcom/analysis/mayreturn.js deleted file mode 100644 index 9a9779749..000000000 --- a/xpcom/analysis/mayreturn.js +++ /dev/null @@ -1,44 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* May-return analysis. - * This makes sense only for functions that return a value. The analysis - * determines the set of variables that may transitively reach the return - * statement. */ - -function MayReturnAnalysis() { - BackwardAnalysis.apply(this, arguments); - // May-return variables. We collect them all here. - this.vbls = create_decl_set(); - // The return value variable itself - this.retvar = undefined; -} - -MayReturnAnalysis.prototype = new BackwardAnalysis; - -MayReturnAnalysis.prototype.flowState = function(isn, state) { - if (TREE_CODE(isn) == GIMPLE_RETURN) { - let v = return_expr(isn); - if (!v) - return; - if (v.tree_code() == RESULT_DECL) // only an issue with 4.3 - throw new Error("Weird case hit"); - this.vbls.add(v); - state.add(v); - this.retvar = v; - } else if (TREE_CODE(isn) == GIMPLE_ASSIGN) { - let lhs = gimple_op(isn, 0); - let rhs = gimple_op(isn, 1); - if (DECL_P(rhs) && DECL_P(lhs) && state.has(lhs)) { - this.vbls.add(rhs); - state.add(rhs); - } - - for (let e in isn_defs(isn, 'strong')) { - if (DECL_P(e)) { - state.remove(e); - } - } - } -}; diff --git a/xpcom/analysis/moz.build b/xpcom/analysis/moz.build deleted file mode 100644 index 895d11993..000000000 --- a/xpcom/analysis/moz.build +++ /dev/null @@ -1,6 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - diff --git a/xpcom/analysis/must-override.js b/xpcom/analysis/must-override.js deleted file mode 100644 index 4d1ed6115..000000000 --- a/xpcom/analysis/must-override.js +++ /dev/null @@ -1,52 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Detect classes that should have overridden members of their parent - * classes but didn't. - * - * Example: - * - * struct S { - * virtual NS_MUST_OVERRIDE void f(); - * virtual void g(); - * }; - * - * struct A : S { virtual void f(); }; // ok - * struct B : S { virtual NS_MUST_OVERRIDE void f(); }; // also ok - * - * struct C : S { virtual void g(); }; // ERROR: must override f() - * struct D : S { virtual void f(int); }; // ERROR: different overload - * struct E : A { }; // ok: A's definition of f() is good for subclasses - * struct F : B { }; // ERROR: B's definition of f() is still must-override - * - * We don't care if you define the method or not. - */ - -function get_must_overrides(cls) -{ - let mos = {}; - for each (let base in cls.bases) - for each (let m in base.type.members) - if (hasAttribute(m, 'NS_must_override')) - mos[m.shortName] = m; - - return mos; -} - -function process_type(t) -{ - if (t.isIncomplete || (t.kind != 'class' && t.kind != 'struct')) - return; - - let mos = get_must_overrides(t); - for each (let m in t.members) { - let mos_m = mos[m.shortName] - if (mos_m && signaturesMatch(mos_m, m)) - delete mos[m.shortName]; - } - - for each (let u in mos) - error(t.kind + " " + t.name + " must override " + u.name, t.loc); -} diff --git a/xpcom/analysis/outparams.js b/xpcom/analysis/outparams.js deleted file mode 100644 index f789e30d0..000000000 --- a/xpcom/analysis/outparams.js +++ /dev/null @@ -1,880 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -require({ version: '1.8' }); -require({ after_gcc_pass: 'cfg' }); - -include('treehydra.js'); - -include('util.js'); -include('gcc_util.js'); -include('gcc_print.js'); -include('unstable/adts.js'); -include('unstable/analysis.js'); -include('unstable/esp.js'); -let Zero_NonZero = {}; -include('unstable/zero_nonzero.js', Zero_NonZero); - -include('xpcom/analysis/mayreturn.js'); - -function safe_location_of(t) { - if (t === undefined) - return UNKNOWN_LOCATION; - - return location_of(t); -} - -MapFactory.use_injective = true; - -// Print a trace for each function analyzed -let TRACE_FUNCTIONS = 0; -// Trace operation of the ESP analysis, use 2 or 3 for more detail -let TRACE_ESP = 0; -// Trace determination of function call parameter semantics, 2 for detail -let TRACE_CALL_SEM = 0; -// Print time-taken stats -let TRACE_PERF = 0; -// Log analysis results in a special format -let LOG_RESULTS = false; - -const WARN_ON_SET_NULL = false; -const WARN_ON_SET_FAILURE = false; - -// Filter functions to process per CLI -let func_filter; -if (this.arg == undefined || this.arg == '') { - func_filter = function(fd) true; -} else { - func_filter = function(fd) function_decl_name(fd) == this.arg; -} - -function process_tree(func_decl) { - if (!func_filter(func_decl)) return; - - // Determine outparams and return if function not relevant - if (DECL_CONSTRUCTOR_P(func_decl)) return; - let psem = OutparamCheck.prototype.func_param_semantics(func_decl); - if (!psem.some(function(x) x.check)) return; - let decl = rectify_function_decl(func_decl); - if (decl.resultType != 'nsresult' && decl.resultType != 'PRBool' && - decl.resultType != 'void') { - warning("Cannot analyze outparam usage for function with return type '" + - decl.resultType + "'", location_of(func_decl)); - return; - } - - let params = [ v for (v in flatten_chain(DECL_ARGUMENTS(func_decl))) ]; - let outparam_list = []; - let psem_list = []; - for (let i = 0; i < psem.length; ++i) { - if (psem[i].check) { - outparam_list.push(params[i]); - psem_list.push(psem[i]); - } - } - if (outparam_list.length == 0) return; - - // At this point we have a function we want to analyze - let fstring = rfunc_string(decl); - if (TRACE_FUNCTIONS) { - print('* function ' + fstring); - print(' ' + loc_string(location_of(func_decl))); - } - if (TRACE_PERF) timer_start(fstring); - for (let i = 0; i < outparam_list.length; ++i) { - let p = outparam_list[i]; - if (TRACE_FUNCTIONS) { - print(" outparam " + expr_display(p) + " " + DECL_UID(p) + ' ' + - psem_list[i].label); - } - } - - let cfg = function_decl_cfg(func_decl); - - let [retvar, retvars] = function() { - let trace = 0; - let a = new MayReturnAnalysis(cfg, trace); - a.run(); - return [a.retvar, a.vbls]; - }(); - if (retvar == undefined && decl.resultType != 'void') throw new Error("assert"); - - { - let trace = TRACE_ESP; - for (let i = 0; i < outparam_list.length; ++i) { - let psem = [ psem_list[i] ]; - let outparam = [ outparam_list[i] ]; - let a = new OutparamCheck(cfg, psem, outparam, retvar, retvars, trace); - // This is annoying, but this field is only used for logging anyway. - a.fndecl = func_decl; - a.run(); - a.check(decl.resultType == 'void', func_decl); - } - } - - if (TRACE_PERF) timer_stop(fstring); -} - -// Outparam check analysis -function OutparamCheck(cfg, psem_list, outparam_list, retvar, retvar_set, - trace) { - // We need to save the retvars so we can detect assignments through - // their addresses passed as arguments. - this.retvar_set = retvar_set; - this.retvar = retvar; - - // We need both an ordered set and a lookup structure - this.outparam_list = outparam_list - this.outparams = create_decl_set(outparam_list); - this.psem_list = psem_list; - - // Set up property state vars for ESP - let psvar_list = []; - for each (let v in outparam_list) { - psvar_list.push(new ESP.PropVarSpec(v, true, av.NOT_WRITTEN)); - } - for (let v in retvar_set.items()) { - psvar_list.push(new ESP.PropVarSpec(v, v == this.retvar, ESP.TOP)); - } - if (trace) { - print("PS vars"); - for each (let v in this.psvar_list) { - print(" " + expr_display(v.vbl)); - } - } - this.zeroNonzero = new Zero_NonZero.Zero_NonZero(); - ESP.Analysis.call(this, cfg, psvar_list, av.meet, trace); -} - -// Abstract values for outparam check -function AbstractValue(name, ch) { - this.name = name; - this.ch = ch; -} - -AbstractValue.prototype.equals = function(v) { - return this === v; -} - -AbstractValue.prototype.toString = function() { - return this.name + ' (' + this.ch + ')'; -} - -AbstractValue.prototype.toShortString = function() { - return this.ch; -} - -let avspec = [ - // Abstract values for outparam contents write status - [ 'NULL', 'x' ], // is a null pointer - [ 'NOT_WRITTEN', '-' ], // not written - [ 'WROTE_NULL', '/' ], // had NULL written to - [ 'WRITTEN', '+' ], // had anything written to - // MAYBE_WRITTEN is special. "Officially", it means the same thing as - // NOT_WRITTEN. What it really means is that an outparam was passed - // to another function as a possible outparam (outparam type, but not - // in last position), so if there is an error with it not being written, - // we can give a hint about the possible outparam in the warning. - [ 'MAYBE_WRITTEN', '?' ], // written if possible outparam is one -]; - -let av = {}; -for each (let [name, ch] in avspec) { - av[name] = new AbstractValue(name, ch); -} - -av.ZERO = Zero_NonZero.Lattice.ZERO; -av.NONZERO = Zero_NonZero.Lattice.NONZERO; - -/* -av.ZERO.negation = av.NONZERO; -av.NONZERO.negation = av.ZERO; - -// Abstract values for int constants. We use these to figure out feasible -// paths in the presence of GCC finally_tmp-controlled switches. -function makeIntAV(v) { - let key = 'int_' + v; - if (cachedAVs.hasOwnProperty(key)) return cachedAVs[key]; - - let s = "" + v; - let ans = cachedAVs[key] = new AbstractValue(s, s); - ans.int_val = v; - return ans; -} -*/ - -let cachedAVs = {}; - -// Abstract values for pointers that contain a copy of an outparam -// pointer. We use these to figure out writes to a casted copy of -// an outparam passed to another method. -function makeOutparamAV(v) { - let key = 'outparam_' + DECL_UID(v); - if (key in cachedAVs) return cachedAVs[key]; - - let ans = cachedAVs[key] = - new AbstractValue('OUTPARAM:' + expr_display(v), 'P'); - ans.outparam = v; - return ans; -} - -/** Return the integer value if this is an integer av, otherwise undefined. */ -av.intVal = function(v) { - if (v.hasOwnProperty('int_val')) - return v.int_val; - return undefined; -} - -/** Meet function for our abstract values. */ -av.meet = function(v1, v2) { - // At this point we know v1 != v2. - let values = [v1,v2] - if (values.indexOf(av.LOCKED) != -1 - || values.indexOf(av.UNLOCKED) != -1) - return ESP.NOT_REACHED; - - return Zero_NonZero.meet(v1, v2) -}; - -// Outparam check analysis -OutparamCheck.prototype = new ESP.Analysis; - -OutparamCheck.prototype.split = function(vbl, v) { - // Can't happen for current version of ESP, but could change - if (v != ESP.TOP) throw new Error("not implemented"); - return [ av.ZERO, av.NONZERO ]; -} - -OutparamCheck.prototype.updateEdgeState = function(e) { - e.state.keepOnly(e.dest.keepVars); -} - -OutparamCheck.prototype.flowState = function(isn, state) { - switch (TREE_CODE(isn)) { - case GIMPLE_ASSIGN: - this.processAssign(isn, state); - break; - case GIMPLE_CALL: - this.processCall(isn, isn, state); - break; - case GIMPLE_SWITCH: - case GIMPLE_COND: - // This gets handled by flowStateCond instead, has no exec effect - break; - default: - this.zeroNonzero.flowState(isn, state); - } -} - -OutparamCheck.prototype.flowStateCond = function(isn, truth, state) { - this.zeroNonzero.flowStateCond(isn, truth, state); -} - -// For any outparams-specific semantics, we handle it here and then -// return. Otherwise we delegate to the zero-nonzero analysis. -OutparamCheck.prototype.processAssign = function(isn, state) { - let lhs = gimple_op(isn, 0); - let rhs = gimple_op(isn, 1); - - if (DECL_P(lhs)) { - // Unwrap NOP_EXPR, which is semantically a copy. - if (TREE_CODE(rhs) == NOP_EXPR) { - rhs = rhs.operands()[0]; - } - - if (DECL_P(rhs) && this.outparams.has(rhs)) { - // Copying an outparam pointer. We have to remember this so that - // if it is assigned thru later, we pick up the write. - state.assignValue(lhs, makeOutparamAV(rhs), isn); - return; - } - - // Cases of this switch that handle something should return from - // the function. Anything that does not return is picked up afteward. - switch (TREE_CODE(rhs)) { - case INTEGER_CST: - if (this.outparams.has(lhs)) { - warning("assigning to outparam pointer"); - return; - } - break; - case EQ_EXPR: { - // We only care about testing outparams for NULL (and then not writing) - let [op1, op2] = rhs.operands(); - if (DECL_P(op1) && this.outparams.has(op1) && expr_literal_int(op2) == 0) { - state.update(function(ss) { - let [s1, s2] = [ss, ss.copy()]; // s1 true, s2 false - s1.assignValue(lhs, av.NONZERO, isn); - s1.assignValue(op1, av.NULL, isn); - s2.assignValue(lhs, av.ZERO, isn); - return [s1, s2]; - }); - return; - } - } - break; - case CALL_EXPR: - /* Embedded CALL_EXPRs are a 4.3 issue */ - this.processCall(rhs, isn, state, lhs); - return; - - case INDIRECT_REF: - // If rhs is *outparam and pointer-typed, lhs is NULL iff rhs is - // WROTE_NULL. Required for testcase onull.cpp. - let v = rhs.operands()[0]; - if (DECL_P(v) && this.outparams.has(v) && - TREE_CODE(TREE_TYPE(v)) == POINTER_TYPE) { - state.update(function(ss) { - let val = ss.get(v) == av.WROTE_NULL ? av.ZERO : av.NONZERO; - ss.assignValue(lhs, val, isn); - return [ ss ]; - }); - return; - } - } - - // Nothing special -- delegate - this.zeroNonzero.processAssign(isn, state); - return; - } - - switch (TREE_CODE(lhs)) { - case INDIRECT_REF: - // Writing to an outparam. We want to try to figure out if we're - // writing NULL. - let e = TREE_OPERAND(lhs, 0); - if (this.outparams.has(e)) { - if (expr_literal_int(rhs) == 0) { - state.assignValue(e, av.WROTE_NULL, isn); - } else if (DECL_P(rhs)) { - state.update(function(ss) { - let [s1, s2] = [ss.copy(), ss]; // s1 NULL, s2 non-NULL - s1.assignValue(e, av.WROTE_NULL, isn); - s1.assignValue(rhs, av.ZERO, isn); - s2.assignValue(e, av.WRITTEN, isn); - s2.assignValue(rhs, av.NONZERO, isn); - return [s1,s2]; - }); - } else { - state.assignValue(e, av.WRITTEN, isn); - } - } else { - // unsound -- could be writing to anything through this ptr - } - break; - case COMPONENT_REF: // unsound - case ARRAY_REF: // unsound - case EXC_PTR_EXPR: - case FILTER_EXPR: - break; - default: - print(TREE_CODE(lhs)); - throw new Error("ni"); - } -} - -// Handle an assignment x := test(foo) where test is a simple predicate -OutparamCheck.prototype.processTest = function(lhs, call, val, blame, state) { - let arg = gimple_call_arg(call, 0); - if (DECL_P(arg)) { - this.zeroNonzero.predicate(state, lhs, val, arg, blame); - } else { - state.assignValue(lhs, ESP.TOP, blame); - } -}; - -// The big one: outparam semantics of function calls. -OutparamCheck.prototype.processCall = function(call, blame, state, dest) { - if (!dest) - dest = gimple_call_lhs(call); - - let args = gimple_call_args(call); - let callable = callable_arg_function_decl(gimple_call_fn(call)); - let psem = this.func_param_semantics(callable); - - let name = function_decl_name(callable); - if (name == 'NS_FAILED') { - this.processTest(dest, call, av.NONZERO, call, state); - return; - } else if (name == 'NS_SUCCEEDED') { - this.processTest(dest, call, av.ZERO, call, state); - return; - } else if (name == '__builtin_expect') { - // Same as an assign from arg 0 to lhs - state.assign(dest, args[0], call); - return; - } - - if (TRACE_CALL_SEM) { - print("param semantics:" + psem); - } - - if (args.length != psem.length) { - let ct = TREE_TYPE(callable); - if (TREE_CODE(ct) == POINTER_TYPE) ct = TREE_TYPE(ct); - if (args.length < psem.length || !stdarg_p(ct)) { - // TODO Can __builtin_memcpy write to an outparam? Probably not. - if (name != 'operator new' && name != 'operator delete' && - name != 'operator new []' && name != 'operator delete []' && - name.substr(0, 5) != '__cxa' && - name.substr(0, 9) != '__builtin') { - throw Error("bad len for '" + name + "': " + args.length + ' args, ' + - psem.length + ' params'); - } - } - } - - // Collect variables that are possibly written to on callee success - let updates = []; - for (let i = 0; i < psem.length; ++i) { - let arg = args[i]; - // The arg could be the address of a return-value variable. - // This means it's really the nsresult code for the call, - // so we treat it the same as the target of an rv assignment. - if (TREE_CODE(arg) == ADDR_EXPR) { - let v = arg.operands()[0]; - if (DECL_P(v) && this.retvar_set.has(v)) { - dest = v; - } - } - // The arg could be a copy of an outparam. We'll unwrap to the - // outparam if it is. The following is cheating a bit because - // we munge states together, but it should be OK in practice. - arg = unwrap_outparam(arg, state); - let sem = psem[i]; - if (sem == ps.CONST) continue; - // At this point, we know the call can write thru this param. - // Invalidate any vars whose addresses are passed here. This - // is distinct from the rv handling above. - if (TREE_CODE(arg) == ADDR_EXPR) { - let v = arg.operands()[0]; - if (DECL_P(v)) { - state.remove(v); - } - } - if (!DECL_P(arg) || !this.outparams.has(arg)) continue; - // At this point, we may be writing to an outparam - updates.push([arg, sem]); - } - - if (updates.length) { - if (dest != undefined && DECL_P(dest)) { - // Update & stored rv. Do updates predicated on success. - let [ succ_ret, fail_ret ] = ret_coding(callable); - - state.update(function(ss) { - let [s1, s2] = [ss.copy(), ss]; // s1 success, s2 fail - for each (let [vbl, sem] in updates) { - s1.assignValue(vbl, sem.val, blame); - s1.assignValue(dest, succ_ret, blame); - } - s2.assignValue(dest, fail_ret, blame); - return [s1,s2]; - }); - } else { - // Discarded rv. Per spec in the bug, we assume that either success - // or failure is possible (if not, callee should return void). - // Exceptions: Methods that return void and string mutators are - // considered no-fail. - state.update(function(ss) { - for each (let [vbl, sem] in updates) { - if (sem == ps.OUTNOFAIL || sem == ps.OUTNOFAILNOCHECK) { - ss.assignValue(vbl, av.WRITTEN, blame); - return [ss]; - } else { - let [s1, s2] = [ss.copy(), ss]; // s1 success, s2 fail - for each (let [vbl, sem] in updates) { - s1.assignValue(vbl, sem.val, blame); - } - return [s1,s2]; - } - } - }); - } - } else { - // no updates, just kill any destination for the rv - if (dest != undefined && DECL_P(dest)) { - state.remove(dest, blame); - } - } -}; - -/** Return the return value coding of the given function. This is a pair - * [ succ, fail ] giving the abstract values of the return value under - * success and failure conditions. */ -function ret_coding(callable) { - let type = TREE_TYPE(callable); - if (TREE_CODE(type) == POINTER_TYPE) type = TREE_TYPE(type); - - let rtname = TYPE_NAME(TREE_TYPE(type)); - if (rtname && IDENTIFIER_POINTER(DECL_NAME(rtname)) == 'PRBool') { - return [ av.NONZERO, av.ZERO ]; - } else { - return [ av.ZERO, av.NONZERO ]; - } -} - -function unwrap_outparam(arg, state) { - if (!DECL_P(arg) || state.factory.outparams.has(arg)) return arg; - - let outparam; - for (let ss in state.substates.getValues()) { - let val = ss.get(arg); - if (val != undefined && val.hasOwnProperty('outparam')) { - outparam = val.outparam; - } - } - if (outparam) return outparam; - return arg; -} - -// Check for errors. Must .run() analysis before calling this. -OutparamCheck.prototype.check = function(isvoid, fndecl) { - let state = this.cfg.x_exit_block_ptr.stateOut; - for (let substate in state.substates.getValues()) { - this.checkSubstate(isvoid, fndecl, substate); - } -} - -OutparamCheck.prototype.checkSubstate = function(isvoid, fndecl, ss) { - if (isvoid) { - this.checkSubstateSuccess(ss); - } else { - let [succ, fail] = ret_coding(fndecl); - let rv = ss.get(this.retvar); - // We want to check if the abstract value of the rv is entirely - // contained in the success or failure condition. - if (av.meet(rv, succ) == rv) { - this.checkSubstateSuccess(ss); - } else if (av.meet(rv, fail) == rv) { - this.checkSubstateFailure(ss); - } else { - // This condition indicates a bug in outparams.js. We'll just - // warn so we don't break static analysis builds. - warning("Outparams checker cannot determine rv success/failure", - location_of(fndecl)); - this.checkSubstateSuccess(ss); - this.checkSubstateFailure(ss); - } - } -} - -/* @return The return statement in the function - * that writes the return value in the given substate. - * If the function returns void, then the substate doesn't - * matter and we just look for the return. */ -OutparamCheck.prototype.findReturnStmt = function(ss) { - if (this.retvar != undefined) - return ss.getBlame(this.retvar); - - if (this.cfg._cached_return) - return this.cfg._cached_return; - - for (let bb in cfg_bb_iterator(this.cfg)) { - for (let isn in bb_isn_iterator(bb)) { - if (isn.tree_code() == GIMPLE_RETURN) { - return this.cfg._cached_return = isn; - } - } - } - - return undefined; -} - -OutparamCheck.prototype.checkSubstateSuccess = function(ss) { - for (let i = 0; i < this.psem_list.length; ++i) { - let [v, psem] = [ this.outparam_list[i], this.psem_list[i] ]; - if (psem == ps.INOUT) continue; - let val = ss.get(v); - if (val == av.NOT_WRITTEN) { - this.logResult('succ', 'not_written', 'error'); - this.warn([this.findReturnStmt(ss), "outparam '" + expr_display(v) + "' not written on NS_SUCCEEDED(return value)"], - [v, "outparam declared here"]); - } else if (val == av.MAYBE_WRITTEN) { - this.logResult('succ', 'maybe_written', 'error'); - - let blameStmt = ss.getBlame(v); - let callMsg; - let callName = ""; - try { - let call = TREE_CHECK(blameStmt, GIMPLE_CALL, GIMPLE_MODIFY_STMT); - let callDecl = callable_arg_function_decl(gimple_call_fn(call)); - - callMsg = [callDecl, "declared here"]; - callName = " '" + decl_name(callDecl) + "'"; - } - catch (e if e.TreeCheckError) { } - - this.warn([this.findReturnStmt(ss), "outparam '" + expr_display(v) + "' not written on NS_SUCCEEDED(return value)"], - [v, "outparam declared here"], - [blameStmt, "possibly written by unannotated function call" + callName], - callMsg); - } else { - this.logResult('succ', '', 'ok'); - } - } -} - -OutparamCheck.prototype.checkSubstateFailure = function(ss) { - for (let i = 0; i < this.psem_list.length; ++i) { - let [v, ps] = [ this.outparam_list[i], this.psem_list[i] ]; - let val = ss.get(v); - if (val == av.WRITTEN) { - this.logResult('fail', 'written', 'error'); - if (WARN_ON_SET_FAILURE) { - this.warn([this.findReturnStmt(ss), "outparam '" + expr_display(v) + "' written on NS_FAILED(return value)"], - [v, "outparam declared here"], - [ss.getBlame(v), "written here"]); - } - } else if (val == av.WROTE_NULL) { - this.logResult('fail', 'wrote_null', 'warning'); - if (WARN_ON_SET_NULL) { - this.warn([this.findReturnStmt(ss), "NULL written to outparam '" + expr_display(v) + "' on NS_FAILED(return value)"], - [v, "outparam declared here"], - [ss.getBlame(v), "written here"]); - } - } else { - this.logResult('fail', '', 'ok'); - } - } -} - -/** - * Generate a warning from one or more tuples [treeforloc, message] - */ -OutparamCheck.prototype.warn = function(arg0) { - let loc = safe_location_of(arg0[0]); - let msg = arg0[1]; - - for (let i = 1; i < arguments.length; ++i) { - if (arguments[i] === undefined) continue; - let [atree, amsg] = arguments[i]; - msg += "\n" + loc_string(safe_location_of(atree)) + ": " + amsg; - } - warning(msg, loc); -} - -OutparamCheck.prototype.logResult = function(rv, msg, kind) { - if (LOG_RESULTS) { - let s = [ '"' + x + '"' for each (x in [ loc_string(location_of(this.fndecl)), function_decl_name(this.fndecl), rv, msg, kind ]) ].join(', '); - print(":LR: (" + s + ")"); - } -} - -// Parameter Semantics values -- indicates whether a parameter is -// an outparam. -// label Used for debugging output -// val Abstract value (state) that holds on an argument after -// a call -// check True if parameters with this semantics should be -// checked by this analysis -let ps = { - OUTNOFAIL: { label: 'out-no-fail', val: av.WRITTEN, check: true }, - // Special value for receiver of strings methods. Callers should - // consider this to be an outparam (i.e., it modifies the string), - // but we don't want to check the method itself. - OUTNOFAILNOCHECK: { label: 'out-no-fail-no-check' }, - OUT: { label: 'out', val: av.WRITTEN, check: true }, - INOUT: { label: 'inout', val: av.WRITTEN, check: true }, - MAYBE: { label: 'maybe', val: av.MAYBE_WRITTEN}, // maybe out - CONST: { label: 'const' } // i.e. not out -}; - -// Return the param semantics of a FUNCTION_DECL or VAR_DECL representing -// a function pointer. The result is a pair [ ann, sems ]. -OutparamCheck.prototype.func_param_semantics = function(callable) { - let ftype = TREE_TYPE(callable); - if (TREE_CODE(ftype) == POINTER_TYPE) ftype = TREE_TYPE(ftype); - // What failure semantics to use for outparams - let rtype = TREE_TYPE(ftype); - let nofail = TREE_CODE(rtype) == VOID_TYPE; - // Whether to guess outparams by type - let guess = type_string(rtype) == 'nsresult'; - - // Set up param lists for analysis - let params; // param decls, if available - let types; // param types - let string_mutator = false; - if (TREE_CODE(callable) == FUNCTION_DECL) { - params = [ p for (p in function_decl_params(callable)) ]; - types = [ TREE_TYPE(p) for each (p in params) ]; - string_mutator = is_string_mutator(callable); - } else { - types = [ p for (p in function_type_args(ftype)) - if (TREE_CODE(p) != VOID_TYPE) ]; - } - - // Analyze params - let ans = []; - for (let i = 0; i < types.length; ++i) { - let sem; - if (i == 0 && string_mutator) { - // Special case: string mutator receiver is an no-fail outparams - // but not checkable - sem = ps.OUTNOFAILNOCHECK; - } else { - if (params) sem = decode_attr(DECL_ATTRIBUTES(params[i])); - if (TRACE_CALL_SEM >= 2) print("param " + i + ": annotated " + sem); - if (sem == undefined) { - sem = decode_attr(TYPE_ATTRIBUTES(types[i])); - if (TRACE_CALL_SEM >= 2) print("type " + i + ": annotated " + sem); - if (sem == undefined) { - if (guess && type_is_outparam(types[i])) { - // Params other than last are guessed as MAYBE - sem = i < types.length - 1 ? ps.MAYBE : ps.OUT; - } else { - sem = ps.CONST; - } - } - } - if (sem == ps.OUT && nofail) sem = ps.OUTNOFAIL; - } - if (sem == undefined) throw new Error("assert"); - ans.push(sem); - } - return ans; -} - -/* Decode parameter semantics GCC attributes. - * @param attrs GCC attributes of a parameter. E.g., TYPE_ATTRIBUTES - * or DECL_ATTRIBUTES of an item - * @return The parameter semantics value defined by the attributes, - * or undefined if no such attributes were present. */ -function decode_attr(attrs) { - // Note: we're not checking for conflicts, we just take the first - // one we find. - for each (let attr in rectify_attributes(attrs)) { - if (attr.name == 'user') { - for each (let arg in attr.args) { - if (arg == 'NS_outparam') { - return ps.OUT; - } else if (arg == 'NS_inoutparam') { - return ps.INOUT; - } else if (arg == 'NS_inparam') { - return ps.CONST; - } - } - } - } - return undefined; -} - -/* @return true if the given type appears to be an outparam - * type based on the type alone (i.e., not considering - * attributes. */ -function type_is_outparam(type) { - switch (TREE_CODE(type)) { - case POINTER_TYPE: - return pointer_type_is_outparam(TREE_TYPE(type)); - case REFERENCE_TYPE: - let rt = TREE_TYPE(type); - return !TYPE_READONLY(rt) && is_string_type(rt); - default: - // Note: This is unsound for UNION_TYPE, because the union could - // contain a pointer. - return false; - } -} - -/* Helper for type_is_outparam. - * @return true if 'pt *' looks like an outparam type. */ -function pointer_type_is_outparam(pt) { - if (TYPE_READONLY(pt)) return false; - - switch (TREE_CODE(pt)) { - case POINTER_TYPE: - case ARRAY_TYPE: { - // Look for void **, nsIFoo **, char **, PRUnichar ** - let ppt = TREE_TYPE(pt); - let tname = TYPE_NAME(ppt); - if (tname == undefined) return false; - let name = decl_name_string(tname); - return name == 'void' || name == 'char' || name == 'PRUnichar' || - name.substr(0, 3) == 'nsI'; - } - case INTEGER_TYPE: { - // char * and PRUnichar * are probably strings, otherwise guess - // it is an integer outparam. - let name = decl_name_string(TYPE_NAME(pt)); - return name != 'char' && name != 'PRUnichar'; - } - case ENUMERAL_TYPE: - case REAL_TYPE: - case UNION_TYPE: - case BOOLEAN_TYPE: - return true; - case RECORD_TYPE: - // TODO: should we consider field writes? - return false; - case FUNCTION_TYPE: - case VOID_TYPE: - return false; - default: - throw new Error("can't guess if a pointer to this type is an outparam: " + - TREE_CODE(pt) + ': ' + type_string(pt)); - } -} - -// Map type name to boolean as to whether it is a string. -let cached_string_types = MapFactory.create_map( - function (x, y) x == y, - function (x) x, - function (t) t, - function (t) t); - -// Base string types. Others will be found by searching the inheritance -// graph. - -cached_string_types.put('nsAString', true); -cached_string_types.put('nsACString', true); -cached_string_types.put('nsAString_internal', true); -cached_string_types.put('nsACString_internal', true); - -// Return true if the given type represents a Mozilla string type. -// The binfo arg is the binfo to use for further iteration. This is -// for internal use only, users of this function should pass only -// one arg. -function is_string_type(type, binfo) { - if (TREE_CODE(type) != RECORD_TYPE) return false; - //print(">>>IST " + type_string(type)); - let name = decl_name_string(TYPE_NAME(type)); - let ans = cached_string_types.get(name); - if (ans != undefined) return ans; - - ans = false; - binfo = binfo != undefined ? binfo : TYPE_BINFO(type); - if (binfo != undefined) { - for each (let base in VEC_iterate(BINFO_BASE_BINFOS(binfo))) { - let parent_ans = is_string_type(BINFO_TYPE(base), base); - if (parent_ans) { - ans = true; - break; - } - } - } - cached_string_types.put(name, ans); - //print("<<<IST " + type_string(type) + ' ' + ans); - return ans; -} - -function is_string_ptr_type(type) { - return TREE_CODE(type) == POINTER_TYPE && is_string_type(TREE_TYPE(type)); -} - -// Return true if the given function is a mutator method of a Mozilla -// string type. -function is_string_mutator(fndecl) { - let first_param = function() { - for (let p in function_decl_params(fndecl)) { - return p; - } - return undefined; - }(); - - return first_param != undefined && - decl_name_string(first_param) == 'this' && - is_string_ptr_type(TREE_TYPE(first_param)) && - !TYPE_READONLY(TREE_TYPE(TREE_TYPE(first_param))); -} - diff --git a/xpcom/analysis/stack.js b/xpcom/analysis/stack.js deleted file mode 100644 index 20fa7e7d2..000000000 --- a/xpcom/analysis/stack.js +++ /dev/null @@ -1,159 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -require({ after_gcc_pass: "cfg" }); - -include("gcc_util.js"); -include("unstable/lazy_types.js"); - -function process_type(c) -{ - if ((c.kind == 'class' || c.kind == 'struct') && - !c.isIncomplete) - isStack(c); -} - -/** - * A BlameChain records a chain of one or more location/message pairs. It - * can be used to issue a complex error message such as: - * location: error: Allocated class Foo on the heap - * locationofFoo: class Foo inherits from class Bar - * locationofBar: in class Bar - * locationofBarMem: Member Bar::mFoo - * locationofBaz: class Baz is annotated NS_STACK - */ -function BlameChain(loc, message, prev) -{ - this.loc = loc; - this.message = message; - this.prev = prev; -} - -BlameChain.prototype.toString = function() -{ - let loc = this.loc; - if (loc === undefined) - loc = "<unknown location>"; - - let str = '%s: %s'.format(loc.toString(), this.message); - if (this.prev) - str += "\n%s".format(this.prev); - return str; -}; - -function isStack(c) -{ - function calculate() - { - if (hasAttribute(c, 'NS_stack')) - return new BlameChain(c.loc, '%s %s is annotated NS_STACK_CLASS'.format(c.kind, c.name)); - - for each (let base in c.bases) { - let r = isStack(base.type); - if (r != null) - return new BlameChain(c.loc, '%s %s is a base of %s %s'.format(base.type.kind, base.type.name, c.kind, c.name), r); - } - - for each (let member in c.members) { - if (member.isFunction) - continue; - - if (hasAttribute(member, 'NS_okonheap')) - continue; - - let type = member.type; - while (true) { - if (type === undefined) - break; - - if (type.isArray) { - type = type.type; - continue; - } - - if (type.typedef) { - if (hasAttribute(type, 'NS_stack')) - return true; - - type = type.typedef; - continue; - } - break; - } - - if (type === undefined) { - warning("incomplete type for member " + member + ".", member.loc); - continue; - } - - if (type.isPointer || type.isReference) - continue; - - if (!type.kind || (type.kind != 'class' && type.kind != 'struct')) - continue; - - let r = isStack(type); - if (r != null) - return new BlameChain(c.loc, 'In class %s'.format(c.name), - new BlameChain(member.loc, 'Member %s'.format(member.name), r)); - } - return null; - } - - if (!c.hasOwnProperty('isStack')) - c.isStack = calculate(); - - return c.isStack; -} - -function process_tree(fn) -{ - if (hasAttribute(dehydra_convert(fn), 'NS_suppress_stackcheck')) - return; - - let cfg = function_decl_cfg(fn); - - for (let bb in cfg_bb_iterator(cfg)) { - let it = bb_isn_iterator(bb); - for (let isn in it) { - if (isn.tree_code() != GIMPLE_CALL) - continue; - - let name = gimple_call_function_name(isn); - if (name != "operator new" && name != "operator new []") - continue; - - // ignore placement new - // TODO? ensure 2nd arg is local stack variable - if (gimple_call_num_args(isn) == 2 && - TREE_TYPE(gimple_call_arg(isn, 1)).tree_code() == POINTER_TYPE) - continue; - - let newLhs = gimple_call_lhs(isn); - if (!newLhs) - error("Non assigning call to operator new", location_of(isn)); - - // if isn is the last of its block there are other problems... - assign = it.next(); - - // Calls to |new| are always followed by an assignment, casting the void ptr to which - // |new| was assigned, to a ptr variable of the same type as the allocated object. - // Exception: explicit calls to |::operator new (size_t)|, which can be ignored. - if (assign.tree_code() != GIMPLE_ASSIGN) - continue; - - let assignRhs = gimple_op(assign, 1); - if (newLhs != assignRhs) - continue; - - let assignLhs = gimple_op(assign, 0); - let type = TREE_TYPE(TREE_TYPE(assignLhs)); - let dehydraType = dehydra_convert(type); - - let r = isStack(dehydraType); - if (r) - warning("constructed object of type '%s' not on the stack: %s".format(dehydraType.name, r), location_of(isn)); - } - } -} diff --git a/xpcom/analysis/static-init.js b/xpcom/analysis/static-init.js deleted file mode 100644 index 11d576640..000000000 --- a/xpcom/analysis/static-init.js +++ /dev/null @@ -1,58 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Detects static initializers i.e. functions called during static initialization. - */ - -require({ after_gcc_pass: "cfg" }); - -function process_tree(fn) { - for each (let attr in translate_attributes(DECL_ATTRIBUTES(fn))) - if (attr.name == "constructor") - warning(pretty_func(fn) + " marked with constructor attribute\n"); - - if (decl_name_string(fn) != "__static_initialization_and_destruction_0") - return; - - let cfg = function_decl_cfg(fn); - for (let isn in cfg_isn_iterator(cfg)) { - if (isn.tree_code() != GIMPLE_CALL) - continue; - let decl = gimple_call_fndecl(isn); - let lhs = gimple_call_lhs(isn); - if (lhs) { - warning(pretty_var(lhs) + " defined by call to " + pretty_func(decl) + - " during static initialization", location_of(lhs)); - } else { - let arg = constructorArg(isn); - if (arg) - warning(pretty_var(arg) + " defined by call to constructor " + pretty_func(decl) + - " during static initialization", location_of(arg)); - else - warning(pretty_func(decl) + " called during static initialization", location_of(decl)); - } - } -} - -function constructorArg(call) { - let decl = gimple_call_fndecl(call); - - if (!DECL_CONSTRUCTOR_P(decl)) - return null; - - let arg = gimple_call_arg_iterator(call).next(); - if (TYPE_MAIN_VARIANT(TREE_TYPE(TREE_TYPE(arg))) != DECL_CONTEXT(decl)) - throw new Error("malformed constructor call?!"); - - return arg.tree_code() == ADDR_EXPR ? TREE_OPERAND(arg, 0) : arg; -} - -function pretty_func(fn) { - return rfunc_string(rectify_function_decl(fn)); -} - -function pretty_var(v) { - return type_string(TREE_TYPE(v)) + " " + expr_display(v); -} diff --git a/xpcom/analysis/type-printer.cpp b/xpcom/analysis/type-printer.cpp deleted file mode 100644 index 59d60fd62..000000000 --- a/xpcom/analysis/type-printer.cpp +++ /dev/null @@ -1,7 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsString.h" - -/* do nothing else */ diff --git a/xpcom/analysis/type-printer.js b/xpcom/analysis/type-printer.js deleted file mode 100644 index 672c3ab10..000000000 --- a/xpcom/analysis/type-printer.js +++ /dev/null @@ -1,402 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -let dumpTypes = options['dump-types'].split(','); - -let interestingList = {}; -let typelist = {}; - -function interestingType(t) -{ - let name = t.name; - - if (dumpTypes.some(function(n) n == name)) { - interestingList[name] = t; - typelist[name] = t; - return true; - } - - for each (let base in t.bases) { - if (base.access == 'public' && interestingType(base.type)) { - typelist[name] = t; - return true; - } - } - - return false; -} - -function addSubtype(t, subt) -{ - if (subt.typedef === undefined && - subt.kind === undefined) - throw Error("Unexpected subtype: not class or typedef: " + subt); - - if (t.subtypes === undefined) - t.subtypes = []; - - t.subtypes.push(subt); -} - -function process_type(t) -{ - interestingType(t); - - for each (let base in t.bases) - addSubtype(base.type, t); -} - -function process_decl(d) -{ - if (d.typedef !== undefined && d.memberOf) - addSubtype(d.memberOf, d); -} - -function publicBases(t) -{ - yield t; - - for each (let base in t.bases) - if (base.access == "public") - for each (let gbase in publicBases(base.type)) - yield gbase; -} - -function publicMembers(t) -{ - for each (let base in publicBases(t)) { - for each (let member in base.members) { - if (member.access === undefined) - throw Error("Harumph: member without access? " + member); - - if (member.access != "public") - continue; - - yield member; - } - } -} - -/** - * Get the short name of a decl name. E.g. turn - * "MyNamespace::MyClass::Method(int j) const" into - * "Method" - */ -function getShortName(decl) -{ - let name = decl.name; - let lp = name.lastIndexOf('('); - if (lp != -1) - name = name.slice(0, lp); - - lp = name.lastIndexOf('::'); - if (lp != -1) - name = name.slice(lp + 2); - - return name; -} - -/** - * Remove functions in a base class which were overridden in a derived - * class. - * - * Although really, we should perhaps do this the other way around, or even - * group the two together, but that can come later. - */ -function removeOverrides(members) -{ - let overrideMap = {}; - for (let i = members.length - 1; i >= 0; --i) { - let m = members[i]; - if (!m.isFunction) - continue; - - let shortName = getShortName(m); - - let overrides = overrideMap[shortName]; - if (overrides === undefined) { - overrideMap[shortName] = [m]; - continue; - } - - let found = false; - for each (let override in overrides) { - if (signaturesMatch(override, m)) { - // remove members[i], it was overridden - members.splice(i, 1); - found = true; - } - } - if (found) - continue; - - overrides.push(m); - } -} - -/** - * Generates the starting position of lines within a file. - */ -function getLineLocations(fdata) -{ - yield 0; - - let r = /\n/y; - let pos = 0; - let i = 1; - for (;;) { - pos = fdata.indexOf('\n', pos) + 1; - if (pos == 0) - break; - - yield pos; - i++; - } -} - -/** - * Find and return the doxygen comment immediately prior to the location - * object that was passed in. - * - * @todo: parse doccomment data such as @param, @returns - * @todo: parse comments for markup - */ -function getDocComment(loc) -{ - let fdata = read_file(loc.file); - let linemap = [l for (l in getLineLocations(fdata))]; - - if (loc.line >= linemap.length) { - warning("Location larger than actual header: " + loc); - return <></>; - } - - let endpos = linemap[loc.line - 1] + loc.column - 1; - let semipos = fdata.lastIndexOf(';', endpos); - let bracepos = fdata.lastIndexOf('}', endpos); - let searchslice = fdata.slice(Math.max(semipos, bracepos) + 1, endpos); - - let m = searchslice.match(/\/\*\*[\s\S]*?\*\//gm); - if (m === null) - return <></>; - - let dc = m[m.length - 1].slice(3, -2); - dc = dc.replace(/^\s*(\*+[ \t]*)?/gm, ""); - - return <pre class="doccomment">{dc}</pre>; -} - -function typeName(t) -{ - if (t.name !== undefined) - return t.name; - - if (t.isPointer) - return "%s%s*".format(t.isConst ? "const " : "", typeName(t.type)); - - if (t.isReference) - return "%s%s&".format(t.isConst ? "const " : "", typeName(t.type)); - - return t.toString(); -} - -function publicBaseList(t) -{ - let l = <ul/>; - for each (let b in t.bases) { - if (b.access == 'public') - l.* += <li><a href={"/en/%s".format(b.type.name)}>{b.type.name}</a></li>; - } - - if (l.*.length() == 0) - return <></>; - - return <> - <h2>Base Classes</h2> - {l} - </>; -} - -/** - * Get a source-link for a given location. - */ -function getLocLink(loc, text) -{ - return <a class="loc" - href={"http://hg.mozilla.org/mozilla-central/file/%s/[LOC%s]#l%i".format(options.rev, loc.file, loc.line)}>{text}</a>; -} - -function dumpType(t) -{ - print("DUMP-TYPE(%s)".format(t.name)); - - let methodOverview = <tbody />; - let methodList = <div/>; - let memberList = <></>; - - let shortNameMap = {}; - - let members = [m for (m in publicMembers(t))]; - - removeOverrides(members); - - for each (let m in members) { - let qname = m.memberOf.name + '::'; - - // we don't inherit constructors from base classes - if (m.isConstructor && m.memberOf !== t) - continue; - - if (m.name.indexOf(qname) != 0) - throw Error("Member name not qualified?"); - - let name = m.name.slice(qname.length); - - if (name.indexOf('~') == 0) - continue; - - if (m.isFunction) { - let innerList; - - let shortName = getShortName(m); - if (m.isConstructor) - shortName = 'Constructors'; - - if (shortNameMap.hasOwnProperty(shortName)) { - innerList = shortNameMap[shortName]; - } - else { - let overview = - <tr><td> - <a href={'#%s'.format(escape(shortName))}>{shortName}</a> - </td></tr>; - - if (m.isConstructor) - methodOverview.insertChildAfter(null, overview); - else - methodOverview.appendChild(overview); - - let shortMarkup = - <div> - <h3 id={shortName}>{shortName}</h3> - <dl/> - </div>; - - - if (m.isConstructor) - methodList.insertChildAfter(null, shortMarkup); - else - methodList.appendChild(shortMarkup); - - innerList = shortMarkup.dl; - shortNameMap[shortName] = innerList; - } - - let parameters = <ul/>; - for each (p in m.parameters) { - let name = p.name; - if (name == 'this') - continue; - - if (/^D_\d+$/.test(name)) - name = '<anonymous>'; - - parameters.* += <li>{typeName(p.type)} {name}</li>; - } - - innerList.* += - <> - <dt id={name} class="methodName"> - <code>{typeName(m.type.type)} {name}</code> - {getLocLink(m.loc, "source")} - </dt> - <dd> - {getDocComment(m.loc)} - {parameters.*.length() > 0 ? - <> - <h4>Parameters</h4> - {parameters} - </> : <></>} - </dd> - </>; - } - else { - memberList += <li class="member">{name}</li>; - } - } - - let r = - <body> - <p>{getLocLink(t.loc, "Class Declaration")}</p> - - {getDocComment(t.loc)} - - {dumpTypes.some(function(n) n == t.name) ? - <> - [MAP{t.name}-graph.map] - <img src={"/@api/deki/pages/=en%%252F%s/files/=%s-graph.png".format(t.name, t.name)} usemap="#classes" /> - </> : <></> - } - - {methodOverview.*.length() > 0 ? - <> - <h2>Method Overview</h2> - <table class="standard-table">{methodOverview}</table> - </> : - "" - } - - {publicBaseList(t)} - - <h2>Data Members</h2> - - {memberList.*.length() > 0 ? - memberList : - <p><em>No public members.</em></p> - } - - <h2>Methods</h2> - - {methodList.*.length() > 0 ? - methodList : - <p><em>No public methods.</em></p> - } - - </body>; - - write_file(t.name + ".html", r.toXMLString()); -} - -function graphType(t) -{ - print("GRAPH-TYPE(%s)".format(t.name)); - - let contents = "digraph classes {\n" - + " node [shape=rectangle fontsize=11]\n" - + " %s;\n".format(t.name); - - function graphClass(c) - { - contents += '%s [URL="http://developer.mozilla.org/en/%s"]\n'.format(c.name, c.name); - - for each (let st in c.subtypes) { - contents += " %s -> %s;\n".format(c.name, st.name); - graphClass(st); - } - } - - graphClass(t); - - contents += "}\n"; - - write_file(t.name + "-graph.gv", contents); -} - -function input_end() -{ - for (let p in typelist) - dumpType(typelist[p]); - - for (let n in interestingList) - graphType(interestingList[n]); -} diff --git a/xpcom/moz.build b/xpcom/moz.build index 670ea52a6..fe45fe208 100644 --- a/xpcom/moz.build +++ b/xpcom/moz.build @@ -35,8 +35,5 @@ TEST_TOOL_DIRS += [ # 'reflect/xptcall/tests, #] -if CONFIG['DEHYDRA_PATH']: - DIRS += ['analysis'] - MODULE = 'xpcom' diff --git a/xpcom/tests/moz.build b/xpcom/tests/moz.build index ea3f5a2c6..e8749921e 100644 --- a/xpcom/tests/moz.build +++ b/xpcom/tests/moz.build @@ -24,9 +24,6 @@ if CONFIG['WRAP_STL_INCLUDES']: 'TestSTLWrappers.cpp', ] -if CONFIG['DEHYDRA_PATH']: - DIRS += ['static-checker'] - MODULE = 'xpcom' XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini'] diff --git a/xpcom/tests/static-checker/Makefile.in b/xpcom/tests/static-checker/Makefile.in deleted file mode 100644 index cfacd6e70..000000000 --- a/xpcom/tests/static-checker/Makefile.in +++ /dev/null @@ -1,153 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DEPTH = @DEPTH@ -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -OUTPARAMS_WARNING_TESTCASES = \ - e1.cpp \ - e4.cpp \ - e6.cpp \ - e7.cpp \ - e8.cpp \ - e9.cpp \ - e10.cpp \ - e11.cpp \ - e12.cpp \ - e13.cpp \ - $(NULL) - -OUTPARAMS_NS_FAILED_TESTCASES = \ - e2.cpp \ - e5.cpp \ - $(NULL) - -OUTPARAMS_PASS_TESTCASES = \ - o1.cpp \ - o2.cpp \ - o3.cpp \ - o4.cpp \ - o5.cpp \ - o6.cpp \ - o7.cpp \ - o8.cpp \ - o9.cpp \ - o10.cpp \ - o11.cpp \ - o12.cpp \ - o13.cpp \ - o14.cpp \ - o15.cpp \ - o16.cpp \ - onull.cpp \ - onull2.cpp \ - opmember.cpp \ - $(NULL) - -FLOW_PASS_TESTCASES = \ - flow_through_pass.cpp - -FLOW_FAILURE_TESTCASES = \ - flow_through_fail.cpp - -MUST_OVERRIDE_PASS_TESTCASES = \ - OverrideOK1.cpp \ - OverrideOK2.cpp \ - OverrideOK3-NamespaceTypedef.cpp \ - $(NULL) - -MUST_OVERRIDE_FAILURE_TESTCASES = \ - OverrideFail1.cpp \ - OverrideFail2.cpp \ - OverrideFail3.cpp \ - OverrideFail4.cpp \ - $(NULL) - -OVERRIDE_PASS_TESTCASES = \ - override-pass.cpp \ - override-namespace-typedef.cpp \ - $(NULL) - -OVERRIDE_FAILURE_TESTCASES = \ - override-global.cpp \ - override-signature.cpp \ - override-static.cpp \ - override-virtual.cpp \ - $(NULL) - -STATIC_INIT_PASS_TESTCASES = \ - TestStaticInitStructOK.cpp \ - $(NULL) - -STATIC_INIT_WARNING_TESTCASES = \ - TestStaticInitAttr.cpp \ - TestStaticInitConstructor.cpp \ - TestStaticInitGlobal.cpp \ - TestStaticInitGlobalConst.cpp \ - $(NULL) - -STATIC_FAILURE_TESTCASES = \ - $(FLOW_FAILURE_TESTCASES) \ - $(MUST_OVERRIDE_FAILURE_TESTCASES) \ - $(OVERRIDE_FAILURE_TESTCASES) \ - $(NULL) - -STATIC_WARNING_TESTCASES = \ - $(OUTPARAMS_WARNING_TESTCASES) \ - $(STATIC_INIT_WARNING_TESTCASES) \ - $(NULL) - -STATIC_PASS_TESTCASES = \ - $(OUTPARAMS_NS_FAILED_TESTCASES) \ - $(OUTPARAMS_PASS_TESTCASES) \ - $(FLOW_PASS_TESTCASES) \ - $(MUST_OVERRIDE_PASS_TESTCASES) \ - $(OVERRIDE_PASS_TESTCASES) \ - $(STATIC_INIT_PASS_TESTCASES) \ - $(NULL) - - -include $(topsrcdir)/config/rules.mk - -# We want to compile each file and invert the result to ensure that -# compilation failed. -check:: \ - $(STATIC_FAILURE_TESTCASES:.cpp=.s-fail) \ - $(STATIC_WARNING_TESTCASES:.cpp=.s-warn) \ - $(STATIC_PASS_TESTCASES:.cpp=.s-pass) - -%.s-fail: %.cpp $(GLOBAL_DEPS) $(DEHYDRA_SCRIPTS) $(call mkdir_deps,$(MDDEPDIR)) - @printf "Compiling $(<F) to check that the static-analysis script is checking properly..." - @if $(CCC) $(OUTOPTION)/dev/null -S $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) >$(*F).errlog 2>&1; then \ - printf "fail:\nerror: compilation of $(<F) succeeded. It shouldn't have!\n"; \ - exit 1; \ - else \ - printf "ok.\n"; \ - fi - -%.s-warn: %.cpp $(GLOBAL_DEPS) $(DEHYDRA_SCRIPTS) $(call mkdir_deps,$(MDDEPDIR)) - @printf "Compiling $(<F) to check that the static-analysis script is checking properly..." - @if $(CCC) -Werror $(OUTOPTION)/dev/null -S $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) >$(*F).errlog 2>&1; then \ - printf "fail:\nerror: compilation of $(<F) succeeded with -Werror. It shouldn't have!\n"; \ - exit 1; \ - fi - @if $(CCC) $(OUTOPTION)/dev/null -S $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) >$(*F).werrlog 2>&1; then \ - printf "ok.\n"; \ - else \ - printf "fail:\nerror: compilation of $(<F) without -Werror failed. A warning should have been issued.\n"; \ - exit 1; \ - fi - -%.s-pass: %.cpp $(GLOBAL_DEPS) $(DEHYDRA_SCRIPTS) $(call mkdir_deps,$(MDDEPDIR)) - @printf "Compiling $(<F) to check that the static-analysis script is checking properly..." - @if $(CCC) -Werror $(OUTOPTION)/dev/null -S $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) >$(*F).errlog 2>&1; then \ - printf "ok.\n"; \ - else \ - printf "fail:\nerror: compilation of $(<F) failed. It shouldn't have!\n"; \ - exit 1; \ - fi diff --git a/xpcom/tests/static-checker/TestStaticInitAttr.cpp b/xpcom/tests/static-checker/TestStaticInitAttr.cpp deleted file mode 100644 index a50d7e4f2..000000000 --- a/xpcom/tests/static-checker/TestStaticInitAttr.cpp +++ /dev/null @@ -1,5 +0,0 @@ -int foo() __attribute__((constructor)); - -int foo() { - return 0; -} diff --git a/xpcom/tests/static-checker/TestStaticInitConstructor.cpp b/xpcom/tests/static-checker/TestStaticInitConstructor.cpp deleted file mode 100644 index d2d99468f..000000000 --- a/xpcom/tests/static-checker/TestStaticInitConstructor.cpp +++ /dev/null @@ -1,7 +0,0 @@ -struct Blah { - public: - Blah() { } - ~Blah() { } // raises call to __cxa_atexit -}; - -Blah b; diff --git a/xpcom/tests/static-checker/TestStaticInitGlobal.cpp b/xpcom/tests/static-checker/TestStaticInitGlobal.cpp deleted file mode 100644 index ca44a30f7..000000000 --- a/xpcom/tests/static-checker/TestStaticInitGlobal.cpp +++ /dev/null @@ -1,5 +0,0 @@ -int foo() { - return 0; -} - -int x = foo(); diff --git a/xpcom/tests/static-checker/TestStaticInitGlobalConst.cpp b/xpcom/tests/static-checker/TestStaticInitGlobalConst.cpp deleted file mode 100644 index c1efe10ea..000000000 --- a/xpcom/tests/static-checker/TestStaticInitGlobalConst.cpp +++ /dev/null @@ -1,5 +0,0 @@ -int foo() { - return 0; -} - -const static int x = foo(); diff --git a/xpcom/tests/static-checker/TestStaticInitStructOK.cpp b/xpcom/tests/static-checker/TestStaticInitStructOK.cpp deleted file mode 100644 index aadc44681..000000000 --- a/xpcom/tests/static-checker/TestStaticInitStructOK.cpp +++ /dev/null @@ -1,5 +0,0 @@ -struct Blah { - int i; -}; - -Blah b = { 3 }; diff --git a/xpcom/tests/static-checker/flow_through_fail.cpp b/xpcom/tests/static-checker/flow_through_fail.cpp deleted file mode 100644 index 9374e77e7..000000000 --- a/xpcom/tests/static-checker/flow_through_fail.cpp +++ /dev/null @@ -1,16 +0,0 @@ -static void MUST_FLOW_THROUGH(const char *label) { -} - -int test(int x, int y) { - MUST_FLOW_THROUGH("out"); - - if (!x) { - x = y; - goto out; - } - - return y; - out: - x--; - return x; -} diff --git a/xpcom/tests/static-checker/flow_through_pass.cpp b/xpcom/tests/static-checker/flow_through_pass.cpp deleted file mode 100644 index 164225f86..000000000 --- a/xpcom/tests/static-checker/flow_through_pass.cpp +++ /dev/null @@ -1,20 +0,0 @@ -static void MUST_FLOW_THROUGH(const char *label) { -} - -int test(int x, int y) { - if (x == 3) - return 0; - - if(x) - MUST_FLOW_THROUGH("out"); - - if (x) { - x = y; - goto out; - } - - return y; - out: - x--; - return x; -} diff --git a/xpcom/tests/static-checker/moz.build b/xpcom/tests/static-checker/moz.build deleted file mode 100644 index 895d11993..000000000 --- a/xpcom/tests/static-checker/moz.build +++ /dev/null @@ -1,6 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - |