// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2016-2020 Red Hat, Inc.
//
// Author: Dodji Seketeli
/// @file
///
/// This contains the private implementation of the suppression engine
/// of libabigail.
#ifndef __ABG_SUPPRESSION_PRIV_H__
#define __ABG_SUPPRESSION_PRIV_H__
#include "abg-fwd.h"
#include "abg-regex.h"
#include "abg-sptr-utils.h"
#include "abg-suppression.h"
namespace abigail
{
namespace suppr
{
//
/// The private data of @ref suppression_base.
class suppression_base::priv
{
bool is_artificial_;
bool drops_artifact_;
string label_;
string file_name_regex_str_;
mutable regex::regex_t_sptr file_name_regex_;
string file_name_not_regex_str_;
mutable regex::regex_t_sptr file_name_not_regex_;
string soname_regex_str_;
mutable regex::regex_t_sptr soname_regex_;
string soname_not_regex_str_;
mutable regex::regex_t_sptr soname_not_regex_;
public:
priv()
: is_artificial_(),
drops_artifact_()
{}
priv(const string& label)
: is_artificial_(),
drops_artifact_(),
label_(label)
{}
priv(const string& label,
const string& file_name_regex_str,
const string& file_name_not_regex_str)
: is_artificial_(),
drops_artifact_(),
label_(label),
file_name_regex_str_(file_name_regex_str),
file_name_not_regex_str_(file_name_not_regex_str)
{}
friend class suppression_base;
/// Get the regular expression object associated to the 'file_name_regex'
/// property of @ref suppression_base.
///
/// If the regular expression object is not created, this method
/// creates it and returns it.
///
/// If the 'file_name_regex' property of @ref suppression_base is
/// empty then this method returns nil.
const regex::regex_t_sptr&
get_file_name_regex() const
{
if (!file_name_regex_ && !file_name_regex_str_.empty())
file_name_regex_ = regex::compile(file_name_regex_str_);
return file_name_regex_;
}
/// Get the regular expression object associated to the
/// 'file_name_not_regex' property of @ref suppression_base.
///
/// If the regular expression object is not created, this method
/// creates it and returns it.
///
/// If the 'file_name_not_regex' property of @ref suppression_base
/// is empty then this method returns nil.
const regex::regex_t_sptr&
get_file_name_not_regex() const
{
if (!file_name_not_regex_ && !file_name_not_regex_str_.empty())
file_name_not_regex_ = regex::compile(file_name_not_regex_str_);
return file_name_not_regex_;
}
/// Get the regular expression object associated to the
/// 'soname_regex' property of @ref suppression_base.
///
/// If the regular expression object is not created, this method
/// creates it and returns it.
///
/// If the 'soname_regex' property of @ref suppression_base is empty
/// then this method returns nil.
const regex::regex_t_sptr&
get_soname_regex() const
{
if (!soname_regex_ && !soname_regex_str_.empty())
soname_regex_ = regex::compile(soname_regex_str_);
return soname_regex_;
}
/// Get the regular expression object associated to the
/// 'soname_not_regex' property of @ref suppression_base.
///
/// If the regular expression object is not created, this method
/// creates it and returns it.
///
/// If the 'soname_not_regex' property of @ref suppression_base is
/// empty then this method returns nil.
const regex::regex_t_sptr&
get_soname_not_regex() const
{
if (!soname_not_regex_ && !soname_not_regex_str_.empty())
soname_not_regex_ = regex::compile(soname_not_regex_str_);
return soname_not_regex_;
}
/// Test if the current suppression matches a given SONAME.
///
/// @param soname the SONAME to consider.
///
/// @return true iff the suppression matches the SONAME denoted by
/// @p soname.
///
/// Note that if the suppression contains no property that is
/// related to SONAMEs, the function returns false.
bool
matches_soname(const string& soname) const
{
bool has_regexp = false;
if (regex::regex_t_sptr regexp = get_soname_regex())
{
has_regexp = true;
if (!regex::match(regexp, soname))
return false;
}
if (regex::regex_t_sptr regexp = get_soname_not_regex())
{
has_regexp = true;
if (regex::match(regexp, soname))
return false;
}
if (!has_regexp)
return false;
return true;
}
/// Test if the current suppression matches the full file path to a
/// given binary.
///
/// @param binary_name the full path to the binary.
///
/// @return true iff the suppression matches the path denoted by @p
/// binary_name.
///
/// Note that if the suppression contains no property that is
/// related to file name, the function returns false.
bool
matches_binary_name(const string& binary_name) const
{
bool has_regexp = false;
if (regex::regex_t_sptr regexp = get_file_name_regex())
{
has_regexp = true;
if (!regex::match(regexp, binary_name))
return false;
}
if (regex::regex_t_sptr regexp = get_file_name_not_regex())
{
has_regexp = true;
if (regex::match(regexp, binary_name))
return false;
}
if (!has_regexp)
return false;
return true;
}
}; // end clas suppression_base::priv
//
//
class function_suppression::parameter_spec::priv
{
friend class function_suppression::parameter_spec;
friend class function_suppression;
size_t index_;
string type_name_;
string type_name_regex_str_;
mutable regex::regex_t_sptr type_name_regex_;
priv()
: index_()
{}
priv(size_t i, const string& tn)
: index_(i), type_name_(tn)
{}
priv(size_t i, const string& tn, const string& tn_regex)
: index_(i), type_name_(tn), type_name_regex_str_(tn_regex)
{}
const regex::regex_t_sptr
get_type_name_regex() const
{
if (!type_name_regex_ && !type_name_regex_str_.empty())
type_name_regex_ = regex::compile(type_name_regex_str_);
return type_name_regex_;
}
}; // end class function_suppression::parameter_spec::priv
/// The type of the private data of the @ref function_suppression
/// type.
struct function_suppression::priv
{
friend class function_suppression;
change_kind change_kind_;
string name_;
string name_regex_str_;
mutable regex::regex_t_sptr name_regex_;
string name_not_regex_str_;
mutable regex::regex_t_sptr name_not_regex_;
string return_type_name_;
string return_type_regex_str_;
mutable regex::regex_t_sptr return_type_regex_;
parameter_specs_type parm_specs_;
string symbol_name_;
string symbol_name_regex_str_;
mutable regex::regex_t_sptr symbol_name_regex_;
string symbol_name_not_regex_str_;
mutable regex::regex_t_sptr symbol_name_not_regex_;
string symbol_version_;
string symbol_version_regex_str_;
mutable regex::regex_t_sptr symbol_version_regex_;
bool allow_other_aliases_;
priv():
change_kind_(ALL_CHANGE_KIND),
allow_other_aliases_(true)
{}
priv(const string& name,
const string& name_regex_str,
const string& return_type_name,
const string& return_type_regex_str,
const parameter_specs_type& parm_specs,
const string& symbol_name,
const string& symbol_name_regex_str,
const string& symbol_version,
const string& symbol_version_regex_str)
: change_kind_(ALL_CHANGE_KIND),
name_(name),
name_regex_str_(name_regex_str),
return_type_name_(return_type_name),
return_type_regex_str_(return_type_regex_str),
parm_specs_(parm_specs),
symbol_name_(symbol_name),
symbol_name_regex_str_(symbol_name_regex_str),
symbol_version_(symbol_version),
symbol_version_regex_str_(symbol_version_regex_str),
allow_other_aliases_(true)
{}
/// Getter for a pointer to a regular expression object built from
/// the regular expression string
/// function_suppression::priv::name_regex_str_.
///
/// If that string is empty, then an empty regular expression object
/// pointer is returned.
///
/// @return a pointer to the regular expression object of
/// function_suppression::priv::name_regex_str_..
const regex::regex_t_sptr
get_name_regex() const
{
if (!name_regex_ && !name_regex_str_.empty())
name_regex_ = regex::compile(name_regex_str_);
return name_regex_;
}
/// Getter for a pointer to a regular expression object built from
/// the regular expression string
/// function_suppression::priv::name_not_regex_str_.
///
/// If that string is empty, then an empty regular expression object
/// pointer is returned.
///
/// @return a pointer to the regular expression object of
/// function_suppression::priv::name_not_regex_str_..
const regex::regex_t_sptr
get_name_not_regex() const
{
if (!name_not_regex_ && !name_not_regex_str_.empty())
name_not_regex_ = regex::compile(name_not_regex_str_);
return name_not_regex_;
}
/// Getter for a pointer to a regular expression object built from
/// the regular expression string
/// function_suppression::priv::return_type_regex_str_.
///
/// If that string is empty, then an empty regular expression object
/// pointer is returned.
///
/// @return a pointer to the regular expression object of
/// function_suppression::priv::return_type_regex_str_.
const regex::regex_t_sptr
get_return_type_regex() const
{
if (!return_type_regex_ && !return_type_regex_str_.empty())
return_type_regex_ = regex::compile(return_type_regex_str_);
return return_type_regex_;
}
/// Getter for a pointer to a regular expression object built from
/// the regular expression string
/// function_suppression::priv::symbol_name_regex_str_.
///
/// If that string is empty, then an empty regular expression object
/// pointer is returned.
///
/// @return a pointer to the regular expression object of
/// function_suppression::priv::symbol_name_regex_str_.
const regex::regex_t_sptr
get_symbol_name_regex() const
{
if (!symbol_name_regex_ && !symbol_name_regex_str_.empty())
symbol_name_regex_ = regex::compile(symbol_name_regex_str_);
return symbol_name_regex_;
}
/// Getter for a pointer to a regular expression object built from
/// the regular expression string
/// function_suppression::priv::symbol_name_not_regex_str_.
///
/// If that string is empty, then an empty regular expression object
/// pointer is returned.
///
/// @return a pointer to the regular expression object of
/// function_suppression::priv::symbol_name_not_regex_str_.
const regex::regex_t_sptr
get_symbol_name_not_regex() const
{
if (!symbol_name_not_regex_ && !symbol_name_not_regex_str_.empty())
symbol_name_not_regex_ = regex::compile(symbol_name_not_regex_str_);
return symbol_name_not_regex_;
}
/// Getter for a pointer to a regular expression object built from
/// the regular expression string
/// function_suppression::priv::symbol_version_regex_str_.
///
/// If that string is empty, then an empty regular expression object
/// pointer is returned.
///
/// @return a pointer to the regular expression object of
/// function_suppression::priv::symbol_version_regex_str_.
const regex::regex_t_sptr
get_symbol_version_regex() const
{
if (!symbol_version_regex_ && !symbol_version_regex_str_.empty())
symbol_version_regex_ = regex::compile(symbol_version_regex_str_);
return symbol_version_regex_;
}
}; // end class function_suppression::priv
bool
suppression_matches_function_name(const suppr::function_suppression& s,
const string& fn_name);
bool
suppression_matches_function_sym_name(const suppr::function_suppression& s,
const string& fn_linkage_name);
bool
suppression_matches_variable_name(const suppr::variable_suppression& s,
const string& var_name);
bool
suppression_matches_variable_sym_name(const suppr::variable_suppression& s,
const string& var_linkage_name);
/// Test if a given function denoted by its name and linkage name is
/// suppressed by any of the suppression specifications associated to
/// a given read context used to build the current internal
/// representation of ABI corpus.
///
/// @param ctxt the reading context of interest.
///
/// @param fn_name the name of the function that a specification can
/// match.
///
/// @param fn_linkage_name the linkage name of the function that a
/// specification can match.
///
/// @param require_drop_property if set to "true", tests if the
/// function is suppressed and if its representation is dropped from
/// the ABI corpus being built. Otherwise, if set to "false", only
/// test if the function is suppressed.
///
/// @return true iff at least one function specification matches a
/// function with name @p fn_name or with linkage name @p
/// fn_linkage_name.
template
bool
function_is_suppressed(const ReadContextType& ctxt,
const string& fn_name,
const string& fn_linkage_name,
bool require_drop_property = false)
{
for (suppr::suppressions_type::const_iterator i =
ctxt.get_suppressions().begin();
i != ctxt.get_suppressions().end();
++i)
if (suppr::function_suppression_sptr suppr = is_function_suppression(*i))
{
if (require_drop_property && !(*i)->get_drops_artifact_from_ir())
continue;
if (!fn_name.empty()
&& ctxt.suppression_matches_function_name(*suppr, fn_name))
return true;
if (!fn_linkage_name.empty()
&& ctxt.suppression_matches_function_sym_name(*suppr,
fn_linkage_name))
return true;
}
return false;
}
//
//
/// The type of the private data of the @ref variable_suppression
/// type.
struct variable_suppression::priv
{
friend class variable_suppression;
change_kind change_kind_;
string name_;
string name_regex_str_;
mutable regex::regex_t_sptr name_regex_;
string name_not_regex_str_;
mutable regex::regex_t_sptr name_not_regex_;
string symbol_name_;
string symbol_name_regex_str_;
mutable regex::regex_t_sptr symbol_name_regex_;
string symbol_name_not_regex_str_;
mutable regex::regex_t_sptr symbol_name_not_regex_;
string symbol_version_;
string symbol_version_regex_str_;
mutable regex::regex_t_sptr symbol_version_regex_;
string type_name_;
string type_name_regex_str_;
mutable regex::regex_t_sptr type_name_regex_;
priv(const string& name,
const string& name_regex_str,
const string& symbol_name,
const string& symbol_name_regex_str,
const string& symbol_version,
const string& symbol_version_regex_str,
const string& type_name,
const string& type_name_regex_str)
: change_kind_(ALL_CHANGE_KIND),
name_(name),
name_regex_str_(name_regex_str),
symbol_name_(symbol_name),
symbol_name_regex_str_(symbol_name_regex_str),
symbol_version_(symbol_version),
symbol_version_regex_str_(symbol_version_regex_str),
type_name_(type_name),
type_name_regex_str_(type_name_regex_str)
{}
/// Getter for a pointer to a regular expression object built from
/// the regular expression string
/// variable_suppression::priv::name_regex_str_.
///
/// If that string is empty, then an empty regular expression object
/// pointer is returned.
///
/// @return a pointer to the regular expression object of
/// variable_suppression::priv::name_regex_str_.
const regex::regex_t_sptr
get_name_regex() const
{
if (!name_regex_ && !name_regex_str_.empty())
name_regex_ = regex::compile(name_regex_str_);
return name_regex_;
}
/// Getter for a pointer to a regular expression object built from
/// the regular expression string
/// variable_suppression::priv::name_not_regex_str_.
///
/// If that string is empty, then an empty regular expression object
/// pointer is returned.
///
/// @return a pointer to the regular expression object of
/// variable_suppression::priv::name_not_regex_str_..
const regex::regex_t_sptr
get_name_not_regex() const
{
if (!name_not_regex_ && !name_not_regex_str_.empty())
name_not_regex_ = regex::compile(name_not_regex_str_);
return name_not_regex_;
}
/// Getter for a pointer to a regular expression object built from
/// the regular expression string
/// variable_suppression::priv::symbol_name_regex_str_.
///
/// If that string is empty, then an empty regular expression object
/// pointer is returned.
///
/// @return a pointer to the regular expression object of
/// variable_suppression::priv::symbol_name_regex_str_.
const regex::regex_t_sptr
get_symbol_name_regex() const
{
if (!symbol_name_regex_ && !symbol_name_regex_str_.empty())
symbol_name_regex_ = regex::compile(symbol_name_regex_str_);
return symbol_name_regex_;
}
/// Getter for a pointer to a regular expression object built from
/// the regular expression string
/// variable_suppression::priv::symbol_name_not_regex_str_.
///
/// If that string is empty, then an empty regular expression object
/// pointer is returned.
///
/// @return a pointer to the regular expression object of
/// variable_suppression::priv::symbol_name_not_regex_str_.
const regex::regex_t_sptr
get_symbol_name_not_regex() const
{
if (!symbol_name_not_regex_ && !symbol_name_not_regex_str_.empty())
symbol_name_not_regex_ = regex::compile(symbol_name_not_regex_str_);
return symbol_name_not_regex_;
}
/// Getter for a pointer to a regular expression object built from
/// the regular expression string
/// variable_suppression::priv::symbol_version_regex_str_.
///
/// If that string is empty, then an empty regular expression object
/// pointer is returned.
///
/// @return a pointer to the regular expression object of
/// variable_suppression::priv::symbol_version_regex_str_.
const regex::regex_t_sptr
get_symbol_version_regex() const
{
if (!symbol_version_regex_ && !symbol_version_regex_str_.empty())
symbol_version_regex_ = regex::compile(symbol_version_regex_str_);
return symbol_version_regex_;
}
/// Getter for a pointer to a regular expression object built from
/// the regular expression string
/// variable_suppression::priv::type_name_regex_str_.
///
/// If that string is empty, then an empty regular expression object
/// pointer is returned.
///
/// @return a pointer to the regular expression object of
/// variable_suppression::priv::type_name_regex_str_.
const regex::regex_t_sptr
get_type_name_regex() const
{
if (!type_name_regex_ && !type_name_regex_str_.empty())
type_name_regex_ = regex::compile(type_name_regex_str_);
return type_name_regex_;
}
};// end class variable_supppression::priv
template
bool
variable_is_suppressed(const ReadContextType& ctxt,
const string& var_name,
const string& var_linkage_name,
bool require_drop_property = false)
{
for (suppr::suppressions_type::const_iterator i =
ctxt.get_suppressions().begin();
i != ctxt.get_suppressions().end();
++i)
if (suppr::variable_suppression_sptr suppr = is_variable_suppression(*i))
{
if (require_drop_property && !(*i)->get_drops_artifact_from_ir())
continue;
if (!var_name.empty()
&& ctxt.suppression_matches_variable_name(*suppr, var_name))
return true;
if (!var_linkage_name.empty()
&& ctxt.suppression_matches_variable_sym_name(*suppr,
var_linkage_name))
return true;
}
return false;
}
//
//
/// The private data for @ref type_suppression.
class type_suppression::priv
{
string type_name_regex_str_;
mutable regex::regex_t_sptr type_name_regex_;
string type_name_;
string type_name_not_regex_str_;
mutable regex::regex_t_sptr type_name_not_regex_;
bool consider_type_kind_;
type_suppression::type_kind type_kind_;
bool consider_reach_kind_;
type_suppression::reach_kind reach_kind_;
type_suppression::insertion_ranges insertion_ranges_;
unordered_set source_locations_to_keep_;
string source_location_to_keep_regex_str_;
mutable regex::regex_t_sptr source_location_to_keep_regex_;
mutable vector changed_enumerator_names_;
priv();
public:
priv(const string& type_name_regexp,
const string& type_name,
bool consider_type_kind,
type_suppression::type_kind type_kind,
bool consider_reach_kind,
type_suppression::reach_kind reach_kind)
: type_name_regex_str_(type_name_regexp),
type_name_(type_name),
consider_type_kind_(consider_type_kind),
type_kind_(type_kind),
consider_reach_kind_(consider_reach_kind),
reach_kind_(reach_kind)
{}
/// Get the regular expression object associated to the 'type_name_regex'
/// property of @ref type_suppression.
///
/// If the regular expression object is not created, this method
/// creates it and returns it.
///
/// If the 'type_name_regex' property of @ref type_suppression is
/// empty then this method returns nil.
const regex::regex_t_sptr
get_type_name_regex() const
{
if (!type_name_regex_ && !type_name_regex_str_.empty())
type_name_regex_ = regex::compile(type_name_regex_str_);
return type_name_regex_;
}
/// Setter for the type_name_regex object.
///
/// @param r the new type_name_regex object.
void
set_type_name_regex(regex::regex_t_sptr r)
{type_name_regex_ = r;}
/// Get the regular expression object associated to the
/// 'type_name_not_regex' property of @ref type_suppression.
///
/// If the regular expression object is not created, this method
/// creates it and returns it.
///
/// If the 'type_name_not_regex' property of @ref type_suppression is
/// empty then this method returns nil.
const regex::regex_t_sptr
get_type_name_not_regex() const
{
if (!type_name_not_regex_ && !type_name_not_regex_str_.empty())
type_name_not_regex_ = regex::compile(type_name_not_regex_str_);
return type_name_not_regex_;
}
/// Setter for the type_name_not_regex object.
///
/// @param r the new type_name_not_regex object.
void
set_type_name_not_regex(regex::regex_t_sptr r)
{type_name_not_regex_ = r;}
/// Getter for the string that denotes the 'type_name_not_regex'
/// property.
///
/// @return the value of the string value of the
/// 'type_name_not_regex' property.
const string&
get_type_name_not_regex_str() const
{return type_name_not_regex_str_;}
/// Setter for the string that denotes the 'type_name_not_regex'
/// property.
///
/// @return the value of the string value of the
/// 'type_name_not_regex' property.
void
set_type_name_not_regex_str(const string regex_str)
{type_name_not_regex_str_ = regex_str;}
/// Getter for the source_location_to_keep_regex object.
///
/// This function builds the regex if it's not yet built.
const regex::regex_t_sptr
get_source_location_to_keep_regex() const
{
if (!source_location_to_keep_regex_
&& !source_location_to_keep_regex_str_.empty())
source_location_to_keep_regex_ =
regex::compile(source_location_to_keep_regex_str_);
return source_location_to_keep_regex_;
}
/// Setter for the source_location_to_keep_regex object.
///
/// @param r the new regex object.
void
set_source_location_to_keep_regex(regex::regex_t_sptr r)
{source_location_to_keep_regex_ = r;}
friend class type_suppression;
}; // class type_suppression::priv
bool
suppression_matches_type_name(const suppr::type_suppression& s,
const string& type_name);
bool
suppression_matches_type_name(const suppr::type_suppression& s,
const scope_decl* scope,
const type_base_sptr& type);
bool
suppression_matches_type_location(const type_suppression& s,
const location& loc);
bool
suppression_matches_type_location(const type_suppression& s,
const type_base_sptr& type);
bool
suppression_matches_type_name_or_location(const type_suppression& s,
const string& type_name,
const location& type_location);
/// Test if a type (designated by its name and location) is suppressed
/// by at least one suppression specification associated with a given
/// read context.
///
/// @param ctxt the read context to consider.
///
/// @param type_name the name of the type to consider.
///
/// @param type_location the location of the type to consider.
///
/// @param require_drop_property if set to "true", tests if the type
/// is suppressed and if its representation is dropped from the ABI
/// corpus being built. Otherwise, if set to "false", only test if
/// the type is suppressed.
///
/// @return true iff at least one type specification matches a type
/// with name @p type_name and with location @p type_location.
template
bool
type_is_suppressed(const ReadContextType& ctxt,
const string& type_name,
const location& type_location)
{
bool type_is_private = false;
return type_is_suppressed(ctxt, type_name, type_location, type_is_private);
}
/// Test if a type (designated by its name and location) is suppressed
/// by at least one suppression specification associated with a given
/// read context.
///
/// @param ctxt the read context to consider.
///
/// @param type_name the name of the type to consider.
///
/// @param type_location the location of the type to consider.
///
/// @param type_is_private out parameter. If the type is suppressed
/// because it's private then this out parameter is set to true.
///
/// @param require_drop_property if set to "true", tests if the type
/// is suppressed and if its representation is dropped from the ABI
/// corpus being built. Otherwise, if set to "false", only test if
/// the type is suppressed.
///
/// @return true iff at least one type specification matches a type
/// with name @p type_name and with location @p type_location.
template
bool
type_is_suppressed(const ReadContextType& ctxt,
const string& type_name,
const location& type_location,
bool& type_is_private,
bool require_drop_property = false)
{
for (suppr::suppressions_type::const_iterator i =
ctxt.get_suppressions().begin();
i != ctxt.get_suppressions().end();
++i)
if (suppr::type_suppression_sptr suppr = is_type_suppression(*i))
{
if (require_drop_property && !(*i)->get_drops_artifact_from_ir())
continue;
if (ctxt.suppression_matches_type_name_or_location(*suppr, type_name,
type_location))
{
if (is_private_type_suppr_spec(*suppr))
type_is_private = true;
return true;
}
}
type_is_private = false;
return false;
}
/// Test if a given ELF symbol is suppressed by a suppression
/// specification.
///
/// @param ctxt the read context to use.
///
/// @param sym_name the name of the symbol to consider.
///
/// @param sym_type the type of the symbol to consider.
///
/// @return true iff the elf symbol denoted by @p sym_name and @p
/// sym_type is suppressed.
template
bool
is_elf_symbol_suppressed(const ReadContextType& ctxt,
const string& sym_name,
elf_symbol::type sym_type)
{
if (elf_symbol_is_function(sym_type))
return suppr::function_is_suppressed(ctxt, /*fn_name=*/"",
/*symbol_name=*/sym_name);
else if (elf_symbol_is_variable(sym_type))
return suppr::variable_is_suppressed(ctxt, /*var_name=*/"",
/*symbol_name=*/sym_name);
return false;
}
//
}// end namespace suppr
} // end namespace abigail
#endif // __ABG_SUPPRESSION_PRIV_H__