Fixed a memory bug due to a shallow copy in value_t::storage_t.
This commit is contained in:
parent
f0f2b34ea9
commit
14de0694a9
4 changed files with 48 additions and 32 deletions
|
|
@ -492,18 +492,16 @@ parser_t::parse_value_term(std::istream& in, scope_t& scope, const flags_t tflag
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
case token_t::DOLLAR:
|
case token_t::DOLLAR:
|
||||||
tok = next_token(in, tflags);
|
tok = next_token(in, tflags);
|
||||||
if (tok.kind != token_t::IDENT)
|
if (tok.kind != token_t::IDENT)
|
||||||
throw parse_error("$ symbol must be followed by variable name");
|
throw parse_error("$ symbol must be followed by variable name");
|
||||||
|
|
||||||
#if 0
|
|
||||||
node = new op_t(op_t::VAR_NAME);
|
node = new op_t(op_t::VAR_NAME);
|
||||||
node->set_string(tok.value.as_string());
|
node->set_string(tok.value.as_string());
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if 0
|
|
||||||
case token_t::DOT:
|
case token_t::DOT:
|
||||||
node = new op_t(op_t::NODE_ID);
|
node = new op_t(op_t::NODE_ID);
|
||||||
node->set_name(document_t::CURRENT);
|
node->set_name(document_t::CURRENT);
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,11 @@ bool compute_amount(ptr_op_t expr, amount_t& amt,
|
||||||
value_t result;
|
value_t result;
|
||||||
try {
|
try {
|
||||||
expr->compute(result, xact ? details_t(*xact) : details_t(), context);
|
expr->compute(result, xact ? details_t(*xact) : details_t(), context);
|
||||||
result.cast(value_t::AMOUNT);
|
|
||||||
amt = result.as_amount_lval();
|
// Most of the time when computing the amount of a transaction this cast
|
||||||
|
// will do nothing at all.
|
||||||
|
result.in_place_cast(value_t::AMOUNT);
|
||||||
|
amt = result.as_amount();
|
||||||
}
|
}
|
||||||
catch (error * err) {
|
catch (error * err) {
|
||||||
if (err->context.empty() ||
|
if (err->context.empty() ||
|
||||||
|
|
|
||||||
61
value.cc
61
value.cc
|
|
@ -36,6 +36,45 @@ namespace ledger {
|
||||||
intrusive_ptr<value_t::storage_t> value_t::true_value;
|
intrusive_ptr<value_t::storage_t> value_t::true_value;
|
||||||
intrusive_ptr<value_t::storage_t> value_t::false_value;
|
intrusive_ptr<value_t::storage_t> value_t::false_value;
|
||||||
|
|
||||||
|
value_t::storage_t& value_t::storage_t::operator=(const value_t::storage_t& rhs)
|
||||||
|
{
|
||||||
|
type = rhs.type;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case DATETIME:
|
||||||
|
new((datetime_t *) data) datetime_t(*(datetime_t *) rhs.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AMOUNT:
|
||||||
|
new((amount_t *) data) amount_t(*(amount_t *) rhs.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BALANCE:
|
||||||
|
*(balance_t **) data = new balance_t(**(balance_t **) rhs.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BALANCE_PAIR:
|
||||||
|
*(balance_pair_t **) data =
|
||||||
|
new balance_pair_t(**(balance_pair_t **) rhs.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STRING:
|
||||||
|
new((string *) data) string(*(string *) rhs.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEQUENCE:
|
||||||
|
*(sequence_t **) data = new sequence_t(**(sequence_t **) rhs.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// The rest are fundamental types, which can copy using std::memcpy
|
||||||
|
std::memcpy(data, rhs.data, sizeof(data));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void value_t::storage_t::destroy()
|
void value_t::storage_t::destroy()
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
@ -119,28 +158,8 @@ void value_t::shutdown()
|
||||||
void value_t::_dup()
|
void value_t::_dup()
|
||||||
{
|
{
|
||||||
assert(storage);
|
assert(storage);
|
||||||
if (storage->refc > 1) {
|
if (storage->refc > 1)
|
||||||
storage = new storage_t(*storage.get());
|
storage = new storage_t(*storage.get());
|
||||||
|
|
||||||
// If the data referenced by storage is an allocated pointer, we
|
|
||||||
// need to create a new object in order to achieve duplication.
|
|
||||||
switch (storage->type) {
|
|
||||||
case BALANCE:
|
|
||||||
*(balance_t **) storage->data =
|
|
||||||
new balance_t(**(balance_t **) storage->data);
|
|
||||||
break;
|
|
||||||
case BALANCE_PAIR:
|
|
||||||
*(balance_pair_t **) storage->data =
|
|
||||||
new balance_pair_t(**(balance_pair_t **) storage->data);
|
|
||||||
break;
|
|
||||||
case SEQUENCE:
|
|
||||||
*(sequence_t **) storage->data =
|
|
||||||
new sequence_t(**(sequence_t **) storage->data);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break; // everything else has been duplicated
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t::operator bool() const
|
value_t::operator bool() const
|
||||||
|
|
|
||||||
8
value.h
8
value.h
|
|
@ -164,13 +164,9 @@ private:
|
||||||
explicit storage_t(const storage_t& rhs)
|
explicit storage_t(const storage_t& rhs)
|
||||||
: type(rhs.type), refc(0) {
|
: type(rhs.type), refc(0) {
|
||||||
TRACE_CTOR(value_t::storage_t, "");
|
TRACE_CTOR(value_t::storage_t, "");
|
||||||
std::memcpy(data, rhs.data, sizeof(data));
|
*this = rhs;
|
||||||
}
|
|
||||||
storage_t& operator=(const storage_t& rhs) {
|
|
||||||
type = rhs.type;
|
|
||||||
std::memcpy(data, rhs.data, sizeof(data));
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
storage_t& operator=(const storage_t& rhs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reference counting methods. The intrusive_ptr_* methods are
|
* Reference counting methods. The intrusive_ptr_* methods are
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue