defensive-coding-guide/_preview/fedora/master/en-US/tasks/Tasks-Library_Design.html

425 lines
20 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Defensive Coding Guide | Defensive Coding Guide | Specific Programming Tasks | Library Design</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<!-- Overpass Font -->
<link rel="stylesheet" href="https://overpass-30e2.kxcdn.com/overpass.css">
<link href="../../../master/_stylesheets/asciibinder.css" rel="stylesheet" />
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<link href="../../../master/_images/favicon32x32.png" rel="shortcut icon" type="text/css">
<!--[if IE]><link rel="shortcut icon" href="../../../master/_images/favicon.ico"><![endif]-->
<meta content="AsciiBinder" name="application-name">
</head>
<body>
<div class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="https://docs.fedoraproject.org/"><img alt="Fedora Documentation" src="../../../master/_images/fedora.svg"></a>
</div>
</div>
</div>
<div class="container">
<p class="toggle-nav visible-xs pull-left">
<button class="btn btn-default btn-sm" type="button" data-toggle="offcanvas">Toggle nav</button>
</p>
<ol class="breadcrumb">
<li class="sitename">
<a href="../../../index.html">Home</a>
</li>
<li class="hidden-xs active">
<a href="../../en-US/index.html">Defensive Coding Guide </a>
</li>
<li class="hidden-xs active">
<a href="../../en-US/index.html">Defensive Coding Guide</a>
</li>
<li class="hidden-xs active"><a href="../../en-US/tasks/Tasks-Library_Design.html">Specific Programming Tasks</a></li>
<li class="hidden-xs active">
Library Design
</li>
</ol>
<div class="row row-offcanvas row-offcanvas-left">
<div class="col-xs-8 col-sm-3 col-md-3 sidebar sidebar-offcanvas">
<ul class="nav nav-sidebar">
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicGroup0">
<span id="tgSpan0" class="fa fa-angle-down"></span>Defensive Coding Guide
</a>
<ul id="topicGroup0" class="collapse in list-unstyled">
<li><a class="" href="../../en-US/index.html">Book Information</a></li>
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-1">
<span id="sgSpan-0-1" class="fa fa-caret-right"></span>&nbsp;Programming Languages
</a>
<ul id="topicSubGroup-0-1" class="nav-tertiary list-unstyled collapse">
<li><a class="" href="../../en-US/programming-languages/C.html">The C Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/CXX.html">The C++ Programming&nbsp;Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Java.html">The Java Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Python.html">The Python Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Shell.html">Shell Programming and bash</a></li>
<li><a class="" href="../../en-US/programming-languages/Go.html">The Go Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Vala.html">The Vala Programming Language</a></li>
</ul>
</li>
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-2">
<span id="sgSpan-0-2" class="fa fa-caret-down"></span>&nbsp;Specific Programming Tasks
</a>
<ul id="topicSubGroup-0-2" class="nav-tertiary list-unstyled collapse in">
<li><a class=" active" href="../../en-US/tasks/Tasks-Library_Design.html">Library Design</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Descriptors.html">File Descriptor Management</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-File_System.html">File System Manipulation</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Temporary_Files.html">Temporary Files</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Processes.html">Processes</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Serialization.html">Serialization and Deserialization</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Cryptography.html">Cryptography</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Packaging.html">RPM Packaging</a></li>
</ul>
</li>
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-3">
<span id="sgSpan-0-3" class="fa fa-caret-right"></span>&nbsp;Implementing Security Features
</a>
<ul id="topicSubGroup-0-3" class="nav-tertiary list-unstyled collapse">
<li><a class="" href="../../en-US/features/Features-Authentication.html">Authentication and Authorization</a></li>
<li><a class="" href="../../en-US/features/Features-TLS.html">Transport Layer Security (TLS)</a></li>
<li><a class="" href="../../en-US/features/Features-HSM.html">Hardware Security Modules and Smart Cards</a></li>
</ul>
</li>
<li><a class="" href="../../en-US/Revision_History.html">Revision History</a></li>
</ul>
</li>
</ul>
</div>
<div class="col-xs-12 col-sm-9 col-md-9 main">
<div class="page-header">
<h2>Library Design</h2>
</div>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Through this section, the term <strong>client code</strong>
refers to applications and other libraries using the library.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="state-management"><a class="anchor" href="#state-management"></a>State Management</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="global-state"><a class="anchor" href="#global-state"></a>Global State</h3>
<div class="paragraph">
<p>Global state should be avoided.</p>
</div>
<div class="paragraph">
<p>If this is impossible, the global state must be protected with
a lock. For C/C++, you can use the
<code>pthread_mutex_lock</code>
and <code>pthread_mutex_unlock</code>
functions without linking against <code>-lpthread</code>
because the system provides stubs for non-threaded processes.</p>
</div>
<div class="paragraph">
<p>For compatibility with <code>fork</code>, these locks
should be acquired and released in helpers registered with
<code>pthread_atfork</code>. This function is not
available without <code>-lpthread</code>, so you need to
use <code>dlsym</code> or a weak symbol to obtain its
address.</p>
</div>
<div class="paragraph">
<p>If you need <code>fork</code> protection for other
reasons, you should store the process ID and compare it to the
value returned by <code>getpid</code> each time you
access the global state. (<code>getpid</code> is not
implemented as a system call and is fast.) If the value
changes, you know that you have to re-create the state object.
(This needs to be combined with locking, of course.)</p>
</div>
</div>
<div class="sect2">
<h3 id="handles"><a class="anchor" href="#handles"></a>Handles</h3>
<div class="paragraph">
<p>Library state should be kept behind a curtain. Client code
should receive only a handle. In C, the handle can be a
pointer to an incomplete <code>struct</code>. In C++,
the handle can be a pointer to an abstract base class, or it
can be hidden using the pointer-to-implementation idiom.</p>
</div>
<div class="paragraph">
<p>The library should provide functions for creating and
destroying handles. (In C++, it is possible to use virtual
destructors for the latter.) Consistency between creation and
destruction of handles is strongly recommended: If the client
code created a handle, it is the responsibility of the client
code to destroy it. (This is not always possible or
convenient, so sometimes, a transfer of ownership has to
happen.)</p>
</div>
<div class="paragraph">
<p>Using handles ensures that it is possible to change the way
the library represents state in a way that is transparent to
client code. This is important to facilitate security updates
and many other code changes.</p>
</div>
<div class="paragraph">
<p>It is not always necessary to protect state behind a handle
with a lock. This depends on the level of thread safety
the library provides.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="object-orientation"><a class="anchor" href="#object-orientation"></a>Object Orientation</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Classes should be either designed as base classes, or it should
be impossible to use them as base classes (like
<code>final</code> classes in Java). Classes which are
not designed for inheritance and are used as base classes
nevertheless create potential maintenance hazards because it is
difficult to predict how client code will react when calls to
virtual methods are added, reordered or removed.</p>
</div>
<div class="paragraph">
<p>Virtual member functions can be used as callbacks. See
<a href="#sect-Defensive_Coding-Tasks-Library_Design-Callbacks">Callbacks</a>
for some of the challenges involved.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-Tasks-Library_Design-Callbacks"><a class="anchor" href="#sect-Defensive_Coding-Tasks-Library_Design-Callbacks"></a>Callbacks</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Higher-order code is difficult to analyze for humans and
computers alike, so it should be avoided. Often, an
iterator-based interface (a library function which is called
repeatedly by client code and returns a stream of events) leads
to a better design which is easier to document and use.</p>
</div>
<div class="paragraph">
<p>If callbacks are unavoidable, some guidelines for them follow.</p>
</div>
<div class="paragraph">
<p>In modern C++ code, <code>std::function</code> objects
should be used for callbacks.</p>
</div>
<div class="paragraph">
<p>In older C++ code and in C code, all callbacks must have an
additional closure parameter of type <code>void *</code>,
the value of which can be specified by client code. If
possible, the value of the closure parameter should be provided
by client code at the same time a specific callback is
registered (or specified as a function argument). If a single
closure parameter is shared by multiple callbacks, flexibility
is greatly reduced, and conflicts between different pieces of
client code using the same library object could be unresolvable.
In some cases, it makes sense to provide a de-registration
callback which can be used to destroy the closure parameter when
the callback is no longer used.</p>
</div>
<div class="paragraph">
<p>Callbacks can throw exceptions or call
<code>longjmp</code>. If possible, all library objects
should remain in a valid state. (All further operations on them
can fail, but it should be possible to deallocate them without
causing resource leaks.)</p>
</div>
<div class="paragraph">
<p>The presence of callbacks raises the question if functions
provided by the library are <strong>reentrant</strong>.
Unless a library was designed for such use, bad things will
happen if a callback function uses functions in the same library
(particularly if they are invoked on the same objects and
manipulate the same state). When the callback is invoked, the
library can be in an inconsistent state. Reentrant functions
are more difficult to write than thread-safe functions (by
definition, simple locking would immediately lead to deadlocks).
It is also difficult to decide what to do when destruction of an
object which is currently processing a callback is requested.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="process-attributes"><a class="anchor" href="#process-attributes"></a>Process Attributes</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Several attributes are global and affect all code in the
process, not just the library that manipulates them.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>environment variables
(see <a href="#sect-Defensive_Coding-Tasks-secure_getenv">[sect-Defensive_Coding-Tasks-secure_getenv]</a>)</p>
</li>
<li>
<p>umask</p>
</li>
<li>
<p>user IDs, group IDs and capabilities</p>
</li>
<li>
<p>current working directory</p>
</li>
<li>
<p>signal handlers, signal masks and signal delivery</p>
</li>
<li>
<p>file locks (especially <code>fcntl</code> locks
behave in surprising ways, not just in a multi-threaded
environment)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Library code should avoid manipulating these global process
attributes. It should not rely on environment variables, umask,
the current working directory and signal masks because these
attributes can be inherited from an untrusted source.</p>
</div>
<div class="paragraph">
<p>In addition, there are obvious process-wide aspects such as the
virtual memory layout, the set of open files and dynamic shared
objects, but with the exception of shared objects, these can be
manipulated in a relatively isolated way.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="bottom" class="text-muted py-3" >
<div class="foot">
<div class="container">
<div class="row footerlinks">
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title">About</h3>
<div class="widget-body">
<dl>
<dd><a href="https://fedoraproject.org/wiki/Overview">About Fedora</a></dd>
<dd><a href="https://getfedora.org/en/sponsors">Sponsors</a></dd>
<dd><a href="https://fedoramagazine.org">Fedora Magazine</a></dd>
<dd><a href="https://fedoraproject.org/wiki/Legal:Main#Legal">Legal</a></dd>
</dl>
<ul class="list-inline">
<li>
<a href="https://www.facebook.com/TheFedoraProject" class="btn-social btn-outline"><i class="fa fa-fw fa-facebook"></i></a>
</li>
<li>
<a href="https://plus.google.com/112917221531140868607" class="btn-social btn-outline"><i class="fa fa-fw fa-google-plus"></i></a>
</li>
<li>
<a href="https://twitter.com/fedora" class="btn-social btn-outline"><i class="fa fa-fw fa-twitter"></i></a>
</li>
</ul>
</div>
</div>
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title uppercase">Download</h3>
<div class="widget-body">
<dl>
<dd><a href="https://getfedora.org/en/workstation/download">Get Fedora Workstation</a></dd>
<dd><a href="https://getfedora.org/en/server/download">Get Fedora Server</a></dd>
<dd><a href="https://getfedora.org/en/atomic/download">Get Fedora Atomic</a></dd>
<dd><a href="https://spins.fedoraproject.org">Fedora Spins</a></dd>
<dd><a href="https://labs.fedoraproject.org">Fedora Labs</a></dd>
<dd><a href="https://arm.fedoraproject.org">Fedora ARM<span class="sup">&reg;</span></a></dd>
<dd><a href="https://alt.fedoraproject.org/">Alternative Downloads</a></dd>
</dl>
</div>
</div>
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title">Support</h3>
<div class="widget-body">
<dl>
<dd><a href="https://fedoraproject.org/wiki/Communicating_and_getting_help">Get Help</a></dd>
<dd><a href="https://ask.fedoraproject.org/">Ask Fedora</a></dd>
<dd><a href="https://fedoraproject.org/wiki/Common_F27_bugs">Common Bugs</a></dd>
<dd><a href="https://developer.fedoraproject.org/">Fedora Developer Portal</a></dd>
<dd><a href="https://docs.fedoraproject.org/f27/install-guide/index.html">Installation Guide</a></dd>
</dl>
</div>
</div>
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title">Join</h3>
<div class="widget-body">
<dl>
<dd><a href="https://fedoraproject.org/wiki/Join">Join Fedora</a></dd>
<dd><a href="http://fedoraplanet.org">Planet Fedora</a></dd>
<dd><a href="https://fedoraproject.org/wiki/SIGs">Fedora SIGs</a></dd>
<dd><a href="https://admin.fedoraproject.org/accounts/">Fedora Account System</a></dd>
<dd><a href="https://fedoracommunity.org/">Fedora Community</a></dd>
</dl>
</div>
</div>
</div> <!-- /row of widgets -->
<div class="row">
<div class="col-md-2">
<div class="widget-body">
<a href="https://www.redhat.com/"><img class="rh-logo" src="../../../master/_images/redhat-logo.png" alt="Red Hat Logo" /></a>
</div>
</div>
<div class="col-md-7">
<div class="widget-body">
<p class="sponsor">Fedora is sponsored by Red Hat.</p>
<p class="sponsor"><a href="https://www.redhat.com/en/technologies/linux-platforms/articles/relationship-between-fedora-and-rhel">Learn more about the relationship between Red Hat and Fedora &raquo;</a></p>
<p class="copy">&copy; 2017 Red Hat, Inc. and others. Please send any comments or corrections to the <a href="https://pagure.io/fedora-docs/docs-fp-o">documentation team</a></p>
</div>
</div>
</div> <!-- /row of widgets -->
</div>
</div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="../../../master/_javascripts/bootstrap-offcanvas.js" type="text/javascript"></script>
<script type="text/javascript">
/*<![CDATA[*/
$(document).ready(function() {
$("[id^='topicGroup']").on('show.bs.collapse', function (event) {
if (!($(event.target).attr('id').match(/^topicSubGroup/))) {
$(this).parent().find("[id^='tgSpan']").toggleClass("fa-angle-right fa-angle-down");
}
});
$("[id^='topicGroup']").on('hide.bs.collapse', function (event) {
if (!($(event.target).attr('id').match(/^topicSubGroup/))) {
$(this).parent().find("[id^='tgSpan']").toggleClass("fa-angle-right fa-angle-down");
}
});
$("[id^='topicSubGroup']").on('show.bs.collapse', function () {
$(this).parent().find("[id^='sgSpan']").toggleClass("fa-caret-right fa-caret-down");
});
$("[id^='topicSubGroup']").on('hide.bs.collapse', function () {
$(this).parent().find("[id^='sgSpan']").toggleClass("fa-caret-right fa-caret-down");
});
});
/*]]>*/
</script>
</body>
</html>