From 8d743ac19a1b0c15deccfb14525eaeef56b4135b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 2 Jan 2018 14:28:10 +0200 Subject: Fix few undefined behavior (ubsan) bugs --- build2/function.cxx | 6 +-- build2/function.hxx | 97 +++++++++++++++++++++--------------------- build2/functions-path.cxx | 2 +- build2/install/functions.cxx | 8 +++- build2/parser.cxx | 6 +-- build2/test/script/script.cxx | 6 +-- build2/test/script/script.hxx | 8 ++-- build2/version/rule.cxx | 2 +- unit-tests/function/driver.cxx | 12 +++--- 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 function_map:: - call (const scope& base, + call (const scope* base, const string& name, vector_view 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 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, const void*); + value (*const thunk) (const scope*, vector_view, const void*); }; auto d (reinterpret_cast (&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, 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 args, const location& l) const @@ -164,7 +165,7 @@ namespace build2 // functions. // pair - try_call (const scope& base, + try_call (const scope* base, const string& name, vector_view args, const location& l) const @@ -193,7 +194,7 @@ namespace build2 private: pair - call (const scope&, + call (const scope*, const string&, vector_view, const location&, @@ -215,7 +216,7 @@ namespace build2 // exceptions), you would normally call the default implementation. // static value - default_thunk (const scope&, vector_view, const function_overload&); + default_thunk (const scope*, vector_view, 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, const void*); + value (*const thunk) (const scope*, vector_view, const void*); R (*const impl) (A...); }; static value - thunk (const scope&, vector_view args, const void* d) + thunk (const scope*, vector_view args, const void* d) { return thunk (move (args), static_cast (d)->impl, @@ -448,16 +449,16 @@ namespace build2 // argument. // template - struct function_cast + struct function_cast { struct data { - value (*const thunk) (const scope&, vector_view, const void*); - R (*const impl) (const scope&, A...); + value (*const thunk) (const scope*, vector_view, const void*); + R (*const impl) (const scope*, A...); }; static value - thunk (const scope& base, vector_view args, const void* d) + thunk (const scope* base, vector_view args, const void* d) { return thunk (base, move (args), static_cast (d)->impl, @@ -466,8 +467,8 @@ namespace build2 template static value - thunk (const scope& base, vector_view args, - R (*impl) (const scope&, A...), + thunk (const scope* base, vector_view args, + R (*impl) (const scope*, A...), std::index_sequence) { return value ( @@ -484,12 +485,12 @@ namespace build2 { struct data { - value (*const thunk) (const scope&, vector_view, const void*); + value (*const thunk) (const scope*, vector_view, const void*); void (*const impl) (A...); }; static value - thunk (const scope&, vector_view args, const void* d) + thunk (const scope*, vector_view args, const void* d) { thunk (move (args), static_cast (d)->impl, @@ -508,16 +509,16 @@ namespace build2 }; template - struct function_cast + struct function_cast { struct data { - value (*const thunk) (const scope&, vector_view, const void*); - void (*const impl) (const scope&, A...); + value (*const thunk) (const scope*, vector_view, const void*); + void (*const impl) (const scope*, A...); }; static value - thunk (const scope& base, vector_view args, const void* d) + thunk (const scope* base, vector_view args, const void* d) { thunk (base, move (args), static_cast (d)->impl, @@ -527,8 +528,8 @@ namespace build2 template static void - thunk (const scope& base, vector_view args, - void (*impl) (const scope&, A...), + thunk (const scope* base, vector_view args, + void (*impl) (const scope*, A...), std::index_sequence) { impl (base, @@ -544,12 +545,12 @@ namespace build2 { struct data { - value (*const thunk) (const scope&, vector_view, const void*); + value (*const thunk) (const scope*, vector_view, const void*); R (L::*const impl) (A...) const; }; static value - thunk (const scope&, vector_view args, const void* d) + thunk (const scope*, vector_view args, const void* d) { return thunk (move (args), static_cast (d)->impl, @@ -572,16 +573,16 @@ namespace build2 }; template - struct function_cast_lamb + struct function_cast_lamb { struct data { - value (*const thunk) (const scope&, vector_view, const void*); - R (L::*const impl) (const scope&, A...) const; + value (*const thunk) (const scope*, vector_view, const void*); + R (L::*const impl) (const scope*, A...) const; }; static value - thunk (const scope& base, vector_view args, const void* d) + thunk (const scope* base, vector_view args, const void* d) { return thunk (base, move (args), static_cast (d)->impl, @@ -590,8 +591,8 @@ namespace build2 template static value - thunk (const scope& base, vector_view args, - R (L::*impl) (const scope&, A...) const, + thunk (const scope* base, vector_view args, + R (L::*impl) (const scope*, A...) const, std::index_sequence) { const L* l (nullptr); // Undefined behavior. @@ -608,12 +609,12 @@ namespace build2 { struct data { - value (*const thunk) (const scope&, vector_view, const void*); + value (*const thunk) (const scope*, vector_view, const void*); void (L::*const impl) (A...) const; }; static value - thunk (const scope&, vector_view args, const void* d) + thunk (const scope*, vector_view args, const void* d) { thunk (move (args), static_cast (d)->impl, @@ -635,16 +636,16 @@ namespace build2 }; template - struct function_cast_lamb + struct function_cast_lamb { struct data { - value (*const thunk) (const scope&, vector_view, const void*); - void (L::*const impl) (const scope&, A...) const; + value (*const thunk) (const scope*, vector_view, const void*); + void (L::*const impl) (const scope*, A...) const; }; static value - thunk (const scope& base, vector_view args, const void* d) + thunk (const scope* base, vector_view args, const void* d) { thunk (base, move (args), static_cast (d)->impl, @@ -654,8 +655,8 @@ namespace build2 template static void - thunk (const scope& base, vector_view args, - void (L::*impl) (const scope&, A...) const, + thunk (const scope* base, vector_view args, + void (L::*impl) (const scope*, A...) const, std::index_sequence) { const L* l (nullptr); @@ -673,12 +674,12 @@ namespace build2 { struct data { - value (*const thunk) (const scope&, vector_view, const void*); + value (*const thunk) (const scope*, vector_view, const void*); R (T::*const impl) () const; }; static value - thunk (const scope&, vector_view args, const void* d) + thunk (const scope*, vector_view args, const void* d) { auto mf (static_cast (d)->impl); return value ((function_arg::cast (&args[0]).*mf) ()); @@ -690,12 +691,12 @@ namespace build2 { struct data { - value (*const thunk) (const scope&, vector_view, const void*); + value (*const thunk) (const scope*, vector_view, const void*); void (T::*const impl) () const; }; static value - thunk (const scope&, vector_view args, const void* d) + thunk (const scope*, vector_view args, const void* d) { auto mf (static_cast (d)->impl); (function_arg::cast (args[0]).*mf) (); @@ -710,12 +711,12 @@ namespace build2 { struct data { - value (*const thunk) (const scope&, vector_view, const void*); + value (*const thunk) (const scope*, vector_view, const void*); R T::*const impl; }; static value - thunk (const scope&, vector_view args, const void* d) + thunk (const scope*, vector_view args, const void* d) { auto dm (static_cast (d)->impl); return value (move (function_arg::cast (&args[0]).*dm)); @@ -747,10 +748,10 @@ namespace build2 template void - operator= (R (*impl) (const scope&, A...)) && + operator= (R (*impl) (const scope*, A...)) && { using args = function_args; - using cast = function_cast; + using cast = function_cast; insert (move (name), function_overload ( @@ -797,10 +798,10 @@ namespace build2 template void - coerce_lambda (R (L::*op) (const scope&, A...) const) && + coerce_lambda (R (L::*op) (const scope*, A...) const) && { using args = function_args; - using cast = function_cast_lamb; + using cast = function_cast_lamb; 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 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 (a), loc); + scope_, "builtin.concat", vector_view (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 (&result_data, 1), loc); + scope_, "string", vector_view (&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 (this)), + root (r), vars (false /* global */), id_path (cast (assign (root->id_var) = path ())), wd_path (cast (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> 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 (&v, 1), l)); + &t.base_scope (), "string", vector_view (&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) {return a;}; f["ambig"] = [](names a, optional) {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 args, const function_overload&) + [] (const scope*, vector_view args, const function_overload&) { return value (static_cast (args.size ())); })); @@ -90,7 +90,7 @@ namespace build2 0, function_overload::arg_variadic, function_overload::types (), - [] (const scope&, vector_view args, const function_overload&) + [] (const scope*, vector_view args, const function_overload&) { for (value& a: args) { -- cgit v1.1