BIND 10 #3080: New DB backend: Postgres (patch)
BIND 10 Development
do-not-reply at isc.org
Tue Apr 1 19:25:35 UTC 2014
#3080: New DB backend: Postgres (patch)
-------------------------------------+-------------------------------------
Reporter: dclink | Owner:
Type: enhancement | marcin
Priority: medium | Status:
Component: dhcpdb | reviewing
Keywords: | Milestone: DHCP-
Sensitive: 0 | Kea0.9-alpha
Sub-Project: DHCP | Resolution:
Estimated Difficulty: 3 | CVSS Scoring:
Total Hours: 55 | Defect Severity: N/A
| Feature Depending on Ticket: 2592
| Add Hours to Ticket: 5
| Internal?: 0
-------------------------------------+-------------------------------------
Comment (by marcin):
I went over the code in commit 8e7f2f910d6c7901706e60656b9107177470e725
Several things listed below are nits. Several other things are more
important and indicate that operations we perform here are unsafe (e.g.
memcpy). In most cases they will not show up I guess. In case of memcpy,
unless someone messes up in the lease database, the length of the data
will remain within the boundary of the allocated buffer.
Also, I don't think that our server's code will allow passing NULL leases
to functions like addLease etc, therefore the NULL pointer assert may not
show up.
But, I insist that we rework the whole backend as soon as possible after
the BIND10 1.2 release and treat this as urgent.
The comments below will be referenced in #3382 as we probably want to
address most of these issues there.
'''src/lib/dhcpsrv/pgsql_lease_mgr.cc'''
Functions in PgSqlLease4Exchange and PgSqlLease6Exchange should be
documented.
Also, the inner parts of the functions deserve some commentary too.
createBindForSend doesn't check the lease object for being NULL. Note,
that this function is directly called by the public functions of the lease
manager. When someone passes a NULL pointer to these functions they will
result in an assert which gets logged but is completely useless because
there is no information where the assert origins.
The exception thrown at line 282 is fubared. There is an opening
paranthesis after !''longer!'' but not closing one. The maximal value is
not in paranthesis at all.
Nit: I tend to agree with Stephen that we should rather avoid the names
for variables like !''tmp!''. This simply doesn't mean anything, except
that it is a temporary variable (as almost all variables in the function
scope) :)
I guess it was out of scope to turn istringstream to lexical_cast?
I wonder what is the benefit of initializing !''params!'' as a member of
the !PgSqlLease4Exchange? There may be a benefit if params is returned as
const reference, so as you don't have to copy construct the returned
value. But, params are returned by value. Maybe they should be returned by
const reference?
convertFromDatabase: so pointer to !''r!'' is passed by reference? Any
need for this?
{{{
convertFromDatabase(PGresult *& r, int line) {
}}}
I wonder if this is really safe operation:
{{{
memcpy(hwaddr_buffer_, hwaddr_str, hwaddr_length_);
memcpy(client_id_buffer_, client_id_str, client_id_length_);
}}}
The hwaddr_length_ and client_id_length_ are set by the PQunescapeBytea
which have undefined length? If they happen to be longer than the
!HWAddr::MAX_HWADDR_LEN and !ClientId::MAX_CLIENT_ID_LEN they the memcpy
will overrun the allocated array and cause undefined behavior.
PgSqlLease4Exchange: hostname_ and hwaddr_ are unused.
PgSqlLease6Exchange: duid_ is unused.
convertFromDatabase: Perhaps instead of the switch construct we could just
use cast:
{{{
if (lease_type > Lease6::TYPE_PD) {
isc_throw(BadValue, "invalid lease type returned (" <<
lease_type_ << ") for lease with address " <<
addr6_ << ". Only 0, 1, or 2 are allowed.");
}
Lease6::Type type = static_cast<Lease6::Type>(lease_type);
}}}
openDatabase:
{{{
if (PQstatus(conn_) != CONNECTION_OK) {
// If we have a connection object, we have to call finish
// to release it, but grab the error message first.
std::string error_message = PQerrorMessage(conn_);
PQfinish(conn_);
isc_throw(DbOpenError, error_message);
}
}}}
AIUI, when database fails to open, the PQfinish will release the memory
for conn_, but are we sure that the conn_ will be set to NULL by PQfinish?
My guess is that it is not guaranteed, which in turn implies that the
destructor may not invoke this:
{{{
if (conn_) {
// Deallocate the prepared queries.
PGresult* r = PQexec(conn_, "DEALLOCATE all");
if(PQresultStatus(r) != PGRES_COMMAND_OK) {
// Highly unlikely but we'll log it and go on.
LOG_ERROR(dhcpsrv_logger, DHCPSRV_PGSQL_DEALLOC_ERROR)
.arg(PQerrorMessage(conn_));
}
PQclear(r);
PQfinish(conn_);
}
}}}
I am not sure whether it is an issue or not, but I woiuld set the conn_ to
NULL to be sure.
PgSqlLeaseMgr constructor: conn_, exchange4_ and exchange6_ could be
initialized using the constructor's initialization list, rather than be
initialized in the constructor's body.
prepareStatements: There is no reason to call clear() before resize(). The
resize() and then bunch of assignments should effectively remove and
destroy objects present in the container.
--
Ticket URL: <http://bind10.isc.org/ticket/3080#comment:19>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list