Add a max string len param to deserializeString()
Defaults to INT32_MAX if not provided, but several places in pvAccess can set limits, e.g. MAX_CHANNEL_NAME_LENGTH, and this is the best way to harden them against huge values. Document that SerializeHelper::readSize() returns -1 for NULL.
This commit is contained in:
1 parent
5012ff95b2
commit
2c5854a7ec
2 files changed
+50
-46
No files matched your search
@@ -50,7 +50,7 @@ namespace epics {
|
||||
*
|
||||
* @param[in] buffer deserialization buffer.
|
||||
* @param[in] control the DeserializableControl.
|
||||
* @returns array size.
|
||||
* @returns array size, or (size_t) -1.
|
||||
*/
|
||||
static std::size_t readSize(ByteBuffer* buffer,
|
||||
DeserializableControl* control);
|
||||
@@ -80,20 +80,22 @@ namespace epics {
|
||||
|
||||
/**
|
||||
* std::string deserialization helper method.
|
||||
* TODO This method cannot return "null", but Java implementation
|
||||
* could have serialized "null" value as well. We need to decide
|
||||
* how to deserialize "null".
|
||||
*
|
||||
* @param[in] buffer deserialization buffer
|
||||
* @param[in] control control
|
||||
* @param[in] max length limit
|
||||
* @returns deserialized string
|
||||
*
|
||||
* @todo This method cannot return "null", but Java implementation
|
||||
* could have serialized "null" value as well. We need to decide
|
||||
* how to deserialize "null".
|
||||
* could have serialized "null" value as well. This implementation
|
||||
* returns an empty string in that event.
|
||||
*
|
||||
* @since UNRELEASED Added the max argument.
|
||||
* Test for the DESERIALIZE_STRING_HAS_LIMIT macro to detect.
|
||||
* Retroactive default is 2 GiB
|
||||
*/
|
||||
static std::string deserializeString(ByteBuffer* buffer,
|
||||
DeserializableControl* control);
|
||||
DeserializableControl* control, std::size_t max = 0x7fffffff);
|
||||
|
||||
private:
|
||||
SerializeHelper() {};
|
||||
@@ -112,4 +114,12 @@ namespace epics {
|
||||
}
|
||||
}
|
||||
|
||||
/** Feature test macro for max argument
|
||||
*
|
||||
* of SerializeHelper::deserializeString()
|
||||
*
|
||||
* @since UNRELEASED added
|
||||
*/
|
||||
#define DESERIALIZE_STRING_HAS_LIMIT
|
||||
|
||||
#endif /* SERIALIZEHELPER_H_ */
|
||||
@@ -47,12 +47,13 @@ namespace epics {
|
||||
DeserializableControl* control) {
|
||||
control->ensureData(1);
|
||||
int8 b = buffer->getByte();
|
||||
if(b==-1)
|
||||
return -1;
|
||||
else if(b==-2) {
|
||||
if (b == -1)
|
||||
return -1; // NULL
|
||||
else if (b == -2) {
|
||||
control->ensureData(sizeof(int32));
|
||||
int32 s = buffer->getInt();
|
||||
if(s<0) THROW_BASE_EXCEPTION("negative size");
|
||||
if (s < 0)
|
||||
THROW_BASE_EXCEPTION("negative size");
|
||||
return s;
|
||||
}
|
||||
else
|
||||
@@ -100,44 +101,37 @@ namespace epics {
|
||||
}
|
||||
|
||||
string SerializeHelper::deserializeString(ByteBuffer* buffer,
|
||||
DeserializableControl* control) {
|
||||
DeserializableControl* control, std::size_t max) {
|
||||
|
||||
std::size_t size = SerializeHelper::readSize(buffer, control);
|
||||
if(size!=(size_t)-1) // TODO null strings check, to be removed in the future
|
||||
{
|
||||
if (buffer->getRemaining()>=size)
|
||||
{
|
||||
// entire string is in buffer, simply create a string out of it (copy)
|
||||
std::size_t pos = buffer->getPosition();
|
||||
string str(buffer->getBuffer()+pos, size);
|
||||
buffer->setPosition(pos+size);
|
||||
return str;
|
||||
}
|
||||
else
|
||||
{
|
||||
string str;
|
||||
str.reserve(size);
|
||||
try {
|
||||
std::size_t i = 0;
|
||||
while(true) {
|
||||
std::size_t toRead = min(size-i, buffer->getRemaining());
|
||||
std::size_t pos = buffer->getPosition();
|
||||
str.append(buffer->getBuffer()+pos, toRead);
|
||||
buffer->setPosition(pos+toRead);
|
||||
i += toRead;
|
||||
if(i<size)
|
||||
control->ensureData(1); // at least one
|
||||
else
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
} catch(...) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
if (size == (std::size_t) -1)
|
||||
return std::string(); // NULL from old implementations
|
||||
|
||||
if (size > max)
|
||||
THROW_BASE_EXCEPTION("string too long");
|
||||
|
||||
if (buffer->getRemaining() >= size) { // All present
|
||||
std::size_t pos = buffer->getPosition();
|
||||
string str(buffer->getBuffer() + pos, size);
|
||||
buffer->setPosition(pos + size);
|
||||
return str;
|
||||
}
|
||||
else
|
||||
return std::string();
|
||||
|
||||
string str;
|
||||
str.reserve(size);
|
||||
std::size_t i = 0;
|
||||
while (true) {
|
||||
std::size_t toRead = min(size-i, buffer->getRemaining());
|
||||
std::size_t pos = buffer->getPosition();
|
||||
str.append(buffer->getBuffer() + pos, toRead);
|
||||
buffer->setPosition(pos + toRead);
|
||||
i += toRead;
|
||||
if (i < size)
|
||||
control->ensureData(1); // at least one
|
||||
else
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user