Reputation: 1813
I am sitting here for hours looking at the code, and I just don't get it. It's about the std::vector canData which is used as a buffer for decoding and encoding data from a CAN DBC parser. The complete example of my problem is here.
Basically there is a value encoded to an array and then decoded again from this array. But the size of this array is always zero and even after clearing the array, although its zero, one can still decode data from it.
Can somebody please explain that to me?
Am I missing something?
unsigned int canIdentifier = 0x100;
std::vector<std::uint8_t> canData;
canData.reserve(4);
network.messages[canIdentifier].signals["multiplexor"].encode(canData, 0);
network.messages[canIdentifier].signals["signal_1"].encode(canData, 0x12);
std::cout << "size: " << canData.size() << std::endl;
canData.clear();
decodeMessage(canIdentifier, canData);
std::cout << "2size: " << canData.size() << std::endl;
Updated needed functions:
uint64_t Signal::decode(std::vector<uint8_t> & data)
{
/* safety check */
if (bitSize == 0) {
return 0;
}
/* copy bits */
uint64_t retVal = 0;
if (byteOrder == ByteOrder::BigEndian) {
/* start with MSB */
unsigned int srcBit = startBit;
unsigned int dstBit = bitSize - 1;
for (unsigned int i = 0; i < bitSize; ++i) {
/* copy bit */
if (data[srcBit / 8] & (1 << (srcBit % 8))) {
retVal |= (1ULL << dstBit);
}
/* calculate next position */
if ((srcBit % 8) == 0) {
srcBit += 15;
} else {
--srcBit;
}
--dstBit;
}
} else {
/* start with LSB */
unsigned int srcBit = startBit;
unsigned int dstBit = 0;
for (unsigned int i = 0; i < bitSize; ++i) {
/* copy bit */
if (data[srcBit / 8] & (1 << (srcBit % 8))) {
retVal |= (1ULL << dstBit);
}
/* calculate next position */
++srcBit;
++dstBit;
}
}
/* if signed, then fill all bits above MSB with 1 */
if (valueType == ValueType::Signed) {
if (retVal & (1 << (bitSize - 1))) {
for (unsigned int i = bitSize; i < 8 * sizeof(retVal); ++i) {
retVal |= (1ULL << i);
}
}
}
return retVal;
}
void Signal::encode(std::vector<uint8_t> & data, uint64_t rawValue)
{
/* safety check */
if (bitSize == 0) {
return;
}
/* copy bits */
if (byteOrder == ByteOrder::BigEndian) {
/* start with MSB */
unsigned int srcBit = startBit;
unsigned int dstBit = bitSize - 1;
for (unsigned int i = 0; i < bitSize; ++i) {
/* copy bit */
if (rawValue & (1ULL << dstBit)) {
data[srcBit / 8] |= (1 << (srcBit % 8));
} else {
data[srcBit / 8] &= ~(1 << (srcBit % 8));
}
/* calculate next position */
if ((srcBit % 8) == 0) {
srcBit += 15;
} else {
--srcBit;
}
--dstBit;
}
} else {
/* start with LSB */
unsigned int srcBit = startBit;
unsigned int dstBit = 0;
for (unsigned int i = 0; i < bitSize; ++i) {
/* copy bit */
if (rawValue & (1ULL << dstBit)) {
data[srcBit / 8] |= (1 << (srcBit % 8));
} else {
data[srcBit / 8] &= ~(1 << (srcBit % 8));
}
/* calculate next position */
++srcBit;
++dstBit;
}
}
}
Upvotes: 0
Views: 89
Reputation: 271
Looking at the code step by step:
canData.reserve(4);
allocates memory for vector that can contain (at least) 4 uint8_t, but contain 0 (canData.resize(4) would change vector size). canData.capacity() is then 4 (or more), but canData.size() is 0.
encode(...) method access vector using operator[]. It does not check if index is in range (so less than canData.size()), so there is no exception (if vector at() was used instead it would throw). Also, as accessed indexes are in allocated memory, nothing bad (in particular memory leak) happens there.
canData.clear()
destroy all vector elements, that are in range, so between index 0 and canData.size(). Thus, it does not touch elements above canData.size(), which is 0 in this case. clear() also does not shrink memory allocated for vector (or is not guaranteed to reallocate to shrink memory) - shrink_to_fit() would do so.
In the end, decodeMessage operates on memory that is allocated and filled with correct data, that was not destroyed. Again, usage of vector operator[] cause no exception / memory leak.
As stated in comments, lot of undefined behavior.
Upvotes: 1