aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-01-02 14:28:10 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-01-02 14:28:10 +0200
commit8d743ac19a1b0c15deccfb14525eaeef56b4135b (patch)
treea6ef7627068939f3de8f09c14d06ae67c313a3ab
parentaed0c46abaebd54e2df3777aaabf461c877012f7 (diff)
Fix few undefined behavior (ubsan) bugs
-rw-r--r--build2/function.cxx6
-rw-r--r--build2/function.hxx97
-rw-r--r--build2/functions-path.cxx2
-rw-r--r--build2/install/functions.cxx8
-rw-r--r--build2/parser.cxx6
-rw-r--r--build2/test/script/script.cxx6
-rw-r--r--build2/test/script/script.hxx8
-rw-r--r--build2/version/rule.cxx2
-rw-r--r--unit-tests/function/driver.cxx12
9 files changed, 77 insertions, 70 deletions
diff --git a/build2/function.cxx b/build2/function.cxx
index 4421c86..e71f158 100644
--- a/build2/function.cxx
+++ b/build2/function.cxx
@@ -97,7 +97,7 @@ namespace build2
}
pair<value, bool> function_map::
- call (const scope& base,
+ call (const scope* base,
const string& name,
vector_view<value> args,
const location& loc,
@@ -255,7 +255,7 @@ namespace build2
}
value function_family::
- default_thunk (const scope& base,
+ default_thunk (const scope* base,
vector_view<value> args,
const function_overload& f)
try
@@ -264,7 +264,7 @@ namespace build2
//
struct cast_data // Prefix of function_cast::data.
{
- value (*const thunk) (const scope&, vector_view<value>, const void*);
+ value (*const thunk) (const scope*, vector_view<value>, const void*);
};
auto d (reinterpret_cast<const cast_data*> (&f.data));
diff --git a/build2/function.hxx b/build2/function.hxx
index 7507bec..45fe4e8 100644
--- a/build2/function.hxx
+++ b/build2/function.hxx
@@ -46,7 +46,8 @@ namespace build2
// are conceptually "moved" and can be reused by the implementation.
//
// A function can also optionally receive the current scope by having the
- // first argument of the const scope& type.
+ // first argument of the const scope* type. It may be NULL is the function
+ // is called out of any scope (e.g., command line).
//
// Normally functions come in families that share a common qualification
// (e.g., string. or path.). The function_family class is a "registrar"
@@ -67,7 +68,7 @@ namespace build2
//
struct function_overload;
- using function_impl = value (const scope&,
+ using function_impl = value (const scope*,
vector_view<value>,
const function_overload&);
@@ -150,7 +151,7 @@ namespace build2
erase (iterator i) {map_.erase (i);}
value
- call (const scope& base,
+ call (const scope* base,
const string& name,
vector_view<value> args,
const location& l) const
@@ -164,7 +165,7 @@ namespace build2
// functions.
//
pair<value, bool>
- try_call (const scope& base,
+ try_call (const scope* base,
const string& name,
vector_view<value> args,
const location& l) const
@@ -193,7 +194,7 @@ namespace build2
private:
pair<value, bool>
- call (const scope&,
+ call (const scope*,
const string&,
vector_view<value>,
const location&,
@@ -215,7 +216,7 @@ namespace build2
// exceptions), you would normally call the default implementation.
//
static value
- default_thunk (const scope&, vector_view<value>, const function_overload&);
+ default_thunk (const scope*, vector_view<value>, const function_overload&);
// A function family uses a common qualification (though you can pass
// empty string to supress it). For an unqualified name (doesn't not
@@ -419,12 +420,12 @@ namespace build2
//
struct data
{
- value (*const thunk) (const scope&, vector_view<value>, const void*);
+ value (*const thunk) (const scope*, vector_view<value>, const void*);
R (*const impl) (A...);
};
static value
- thunk (const scope&, vector_view<value> args, const void* d)
+ thunk (const scope*, vector_view<value> args, const void* d)
{
return thunk (move (args),
static_cast<const data*> (d)->impl,
@@ -448,16 +449,16 @@ namespace build2
// argument.
//
template <typename R, typename... A>
- struct function_cast<R, const scope&, A...>
+ struct function_cast<R, const scope*, A...>
{
struct data
{
- value (*const thunk) (const scope&, vector_view<value>, const void*);
- R (*const impl) (const scope&, A...);
+ value (*const thunk) (const scope*, vector_view<value>, const void*);
+ R (*const impl) (const scope*, A...);
};
static value
- thunk (const scope& base, vector_view<value> args, const void* d)
+ thunk (const scope* base, vector_view<value> args, const void* d)
{
return thunk (base, move (args),
static_cast<const data*> (d)->impl,
@@ -466,8 +467,8 @@ namespace build2
template <size_t... i>
static value
- thunk (const scope& base, vector_view<value> args,
- R (*impl) (const scope&, A...),
+ thunk (const scope* base, vector_view<value> args,
+ R (*impl) (const scope*, A...),
std::index_sequence<i...>)
{
return value (
@@ -484,12 +485,12 @@ namespace build2
{
struct data
{
- value (*const thunk) (const scope&, vector_view<value>, const void*);
+ value (*const thunk) (const scope*, vector_view<value>, const void*);
void (*const impl) (A...);
};
static value
- thunk (const scope&, vector_view<value> args, const void* d)
+ thunk (const scope*, vector_view<value> args, const void* d)
{
thunk (move (args),
static_cast<const data*> (d)->impl,
@@ -508,16 +509,16 @@ namespace build2
};
template <typename... A>
- struct function_cast<void, const scope&, A...>
+ struct function_cast<void, const scope*, A...>
{
struct data
{
- value (*const thunk) (const scope&, vector_view<value>, const void*);
- void (*const impl) (const scope&, A...);
+ value (*const thunk) (const scope*, vector_view<value>, const void*);
+ void (*const impl) (const scope*, A...);
};
static value
- thunk (const scope& base, vector_view<value> args, const void* d)
+ thunk (const scope* base, vector_view<value> args, const void* d)
{
thunk (base, move (args),
static_cast<const data*> (d)->impl,
@@ -527,8 +528,8 @@ namespace build2
template <size_t... i>
static void
- thunk (const scope& base, vector_view<value> args,
- void (*impl) (const scope&, A...),
+ thunk (const scope* base, vector_view<value> args,
+ void (*impl) (const scope*, A...),
std::index_sequence<i...>)
{
impl (base,
@@ -544,12 +545,12 @@ namespace build2
{
struct data
{
- value (*const thunk) (const scope&, vector_view<value>, const void*);
+ value (*const thunk) (const scope*, vector_view<value>, const void*);
R (L::*const impl) (A...) const;
};
static value
- thunk (const scope&, vector_view<value> args, const void* d)
+ thunk (const scope*, vector_view<value> args, const void* d)
{
return thunk (move (args),
static_cast<const data*> (d)->impl,
@@ -572,16 +573,16 @@ namespace build2
};
template <typename L, typename R, typename... A>
- struct function_cast_lamb<L, R, const scope&, A...>
+ struct function_cast_lamb<L, R, const scope*, A...>
{
struct data
{
- value (*const thunk) (const scope&, vector_view<value>, const void*);
- R (L::*const impl) (const scope&, A...) const;
+ value (*const thunk) (const scope*, vector_view<value>, const void*);
+ R (L::*const impl) (const scope*, A...) const;
};
static value
- thunk (const scope& base, vector_view<value> args, const void* d)
+ thunk (const scope* base, vector_view<value> args, const void* d)
{
return thunk (base, move (args),
static_cast<const data*> (d)->impl,
@@ -590,8 +591,8 @@ namespace build2
template <size_t... i>
static value
- thunk (const scope& base, vector_view<value> args,
- R (L::*impl) (const scope&, A...) const,
+ thunk (const scope* base, vector_view<value> args,
+ R (L::*impl) (const scope*, A...) const,
std::index_sequence<i...>)
{
const L* l (nullptr); // Undefined behavior.
@@ -608,12 +609,12 @@ namespace build2
{
struct data
{
- value (*const thunk) (const scope&, vector_view<value>, const void*);
+ value (*const thunk) (const scope*, vector_view<value>, const void*);
void (L::*const impl) (A...) const;
};
static value
- thunk (const scope&, vector_view<value> args, const void* d)
+ thunk (const scope*, vector_view<value> args, const void* d)
{
thunk (move (args),
static_cast<const data*> (d)->impl,
@@ -635,16 +636,16 @@ namespace build2
};
template <typename L, typename... A>
- struct function_cast_lamb<L, void, const scope&, A...>
+ struct function_cast_lamb<L, void, const scope*, A...>
{
struct data
{
- value (*const thunk) (const scope&, vector_view<value>, const void*);
- void (L::*const impl) (const scope&, A...) const;
+ value (*const thunk) (const scope*, vector_view<value>, const void*);
+ void (L::*const impl) (const scope*, A...) const;
};
static value
- thunk (const scope& base, vector_view<value> args, const void* d)
+ thunk (const scope* base, vector_view<value> args, const void* d)
{
thunk (base, move (args),
static_cast<const data*> (d)->impl,
@@ -654,8 +655,8 @@ namespace build2
template <size_t... i>
static void
- thunk (const scope& base, vector_view<value> args,
- void (L::*impl) (const scope&, A...) const,
+ thunk (const scope* base, vector_view<value> args,
+ void (L::*impl) (const scope*, A...) const,
std::index_sequence<i...>)
{
const L* l (nullptr);
@@ -673,12 +674,12 @@ namespace build2
{
struct data
{
- value (*const thunk) (const scope&, vector_view<value>, const void*);
+ value (*const thunk) (const scope*, vector_view<value>, const void*);
R (T::*const impl) () const;
};
static value
- thunk (const scope&, vector_view<value> args, const void* d)
+ thunk (const scope*, vector_view<value> args, const void* d)
{
auto mf (static_cast<const data*> (d)->impl);
return value ((function_arg<T>::cast (&args[0]).*mf) ());
@@ -690,12 +691,12 @@ namespace build2
{
struct data
{
- value (*const thunk) (const scope&, vector_view<value>, const void*);
+ value (*const thunk) (const scope*, vector_view<value>, const void*);
void (T::*const impl) () const;
};
static value
- thunk (const scope&, vector_view<value> args, const void* d)
+ thunk (const scope*, vector_view<value> args, const void* d)
{
auto mf (static_cast<const data*> (d)->impl);
(function_arg<T>::cast (args[0]).*mf) ();
@@ -710,12 +711,12 @@ namespace build2
{
struct data
{
- value (*const thunk) (const scope&, vector_view<value>, const void*);
+ value (*const thunk) (const scope*, vector_view<value>, const void*);
R T::*const impl;
};
static value
- thunk (const scope&, vector_view<value> args, const void* d)
+ thunk (const scope*, vector_view<value> args, const void* d)
{
auto dm (static_cast<const data*> (d)->impl);
return value (move (function_arg<T>::cast (&args[0]).*dm));
@@ -747,10 +748,10 @@ namespace build2
template <typename R, typename... A>
void
- operator= (R (*impl) (const scope&, A...)) &&
+ operator= (R (*impl) (const scope*, A...)) &&
{
using args = function_args<A...>;
- using cast = function_cast<R, const scope&, A...>;
+ using cast = function_cast<R, const scope*, A...>;
insert (move (name),
function_overload (
@@ -797,10 +798,10 @@ namespace build2
template <typename L, typename R, typename... A>
void
- coerce_lambda (R (L::*op) (const scope&, A...) const) &&
+ coerce_lambda (R (L::*op) (const scope*, A...) const) &&
{
using args = function_args<A...>;
- using cast = function_cast_lamb<L, R, const scope&, A...>;
+ using cast = function_cast_lamb<L, R, const scope*, A...>;
insert (move (name),
function_overload (
diff --git a/build2/functions-path.cxx b/build2/functions-path.cxx
index 77c1464..1abaf40 100644
--- a/build2/functions-path.cxx
+++ b/build2/functions-path.cxx
@@ -10,7 +10,7 @@ using namespace std;
namespace build2
{
static value
- path_thunk (const scope& base,
+ path_thunk (const scope* base,
vector_view<value> args,
const function_overload& f)
try
diff --git a/build2/install/functions.cxx b/build2/install/functions.cxx
index b9298b2..dbe43c8 100644
--- a/build2/install/functions.cxx
+++ b/build2/install/functions.cxx
@@ -21,7 +21,13 @@ namespace build2
// Resolve potentially relative install.* value to an absolute directory
// based on (other) install.* values visible from the calling scope.
//
- f["resolve"] = &resolve_dir;
+ f[".resolve"] = [] (const scope* s, dir_path d)
+ {
+ if (s == nullptr)
+ fail << "install.resolve() called out of scope" << endf;
+
+ return resolve_dir (*s, move (d));
+ };
}
}
}
diff --git a/build2/parser.cxx b/build2/parser.cxx
index 48902b8..b21d51c 100644
--- a/build2/parser.cxx
+++ b/build2/parser.cxx
@@ -3248,7 +3248,7 @@ namespace build2
}));
p = functions.try_call (
- *scope_, "builtin.concat", vector_view<value> (a), loc);
+ scope_, "builtin.concat", vector_view<value> (a), loc);
}
if (!p.second)
@@ -3848,7 +3848,7 @@ namespace build2
// Note that we "move" args to call().
//
- result_data = functions.call (*scope_, name, args, loc);
+ result_data = functions.call (scope_, name, args, loc);
what = "function call";
}
else
@@ -3956,7 +3956,7 @@ namespace build2
}));
p = functions.try_call (
- *scope_, "string", vector_view<value> (&result_data, 1), loc);
+ scope_, "string", vector_view<value> (&result_data, 1), loc);
}
if (!p.second)
diff --git a/build2/test/script/script.cxx b/build2/test/script/script.cxx
index 5a9ad3c..99ace23 100644
--- a/build2/test/script/script.cxx
+++ b/build2/test/script/script.cxx
@@ -435,9 +435,9 @@ namespace build2
// scope
//
scope::
- scope (const string& id, scope* p)
+ scope (const string& id, scope* p, script* r)
: parent (p),
- root (p != nullptr ? p->root : static_cast<script*> (this)),
+ root (r),
vars (false /* global */),
id_path (cast<path> (assign (root->id_var) = path ())),
wd_path (cast<dir_path> (assign (root->wd_var) = dir_path ()))
@@ -528,7 +528,7 @@ namespace build2
//
script::
script (const target& tt, const testscript& st, const dir_path& rwd)
- : group (st.name == "testscript" ? string () : st.name),
+ : group (st.name == "testscript" ? string () : st.name, this),
test_target (tt),
script_target (st)
{
diff --git a/build2/test/script/script.hxx b/build2/test/script/script.hxx
index e76d0ba..c511f01 100644
--- a/build2/test/script/script.hxx
+++ b/build2/test/script/script.hxx
@@ -427,7 +427,7 @@ namespace build2
~scope () = default;
protected:
- scope (const string& id, scope* parent);
+ scope (const string& id, scope* parent, script* root);
// Pre-parse data.
//
@@ -452,10 +452,10 @@ namespace build2
vector<unique_ptr<scope>> scopes;
public:
- group (const string& id, group& p): scope (id, &p) {}
+ group (const string& id, group& p): scope (id, &p, p.root) {}
protected:
- group (const string& id): scope (id, nullptr) {} // For root.
+ group (const string& id, script* r): scope (id, nullptr, r) {}
// Pre-parse data.
//
@@ -486,7 +486,7 @@ namespace build2
class test: public scope
{
public:
- test (const string& id, group& p): scope (id, &p) {}
+ test (const string& id, group& p): scope (id, &p, p.root) {}
// Pre-parse data.
//
diff --git a/build2/version/rule.cxx b/build2/version/rule.cxx
index 962a75e..9e127ca 100644
--- a/build2/version/rule.cxx
+++ b/build2/version/rule.cxx
@@ -335,7 +335,7 @@ namespace build2
v.type == nullptr
? move (v)
: functions.call (
- t.base_scope (), "string", vector_view<value> (&v, 1), l));
+ &t.base_scope (), "string", vector_view<value> (&v, 1), l));
}
catch (const invalid_argument& e)
{
diff --git a/unit-tests/function/driver.cxx b/unit-tests/function/driver.cxx
index 80c4120..627f76a 100644
--- a/unit-tests/function/driver.cxx
+++ b/unit-tests/function/driver.cxx
@@ -23,13 +23,13 @@ namespace build2
};
static dir_path
- scoped (const scope&, dir_path d)
+ scoped (const scope*, dir_path d)
{
return d;
}
static void
- scoped_void (const scope&, dir_path)
+ scoped_void (const scope*, dir_path)
{
}
@@ -54,8 +54,8 @@ namespace build2
f["ambig"] = [](names a, optional<string>) {return a;};
f["ambig"] = [](names a, optional<uint64_t>) {return a;};
- f["scoped"] = [](const scope&, names a) {return a;};
- f["scoped_void"] = [](const scope&, names) {};
+ f["scoped"] = [](const scope*, names a) {return a;};
+ f["scoped_void"] = [](const scope*, names) {};
f["scoped"] = &scoped;
f["scoped_void"] = &scoped_void;
@@ -76,7 +76,7 @@ namespace build2
1,
function_overload::arg_variadic,
function_overload::types (arg_bool, 1),
- [] (const scope&, vector_view<value> args, const function_overload&)
+ [] (const scope*, vector_view<value> args, const function_overload&)
{
return value (static_cast<uint64_t> (args.size ()));
}));
@@ -90,7 +90,7 @@ namespace build2
0,
function_overload::arg_variadic,
function_overload::types (),
- [] (const scope&, vector_view<value> args, const function_overload&)
+ [] (const scope*, vector_view<value> args, const function_overload&)
{
for (value& a: args)
{