mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
core(persistence): fix "use after free" bug
- do not store user-controlled "FileStorage" pointer - store FileStorage::Impl pointer instead
This commit is contained in:
parent
a199d7adf1
commit
ffe0d50447
@ -510,6 +510,8 @@ public:
|
|||||||
@param fs Pointer to the file storage structure.
|
@param fs Pointer to the file storage structure.
|
||||||
@param blockIdx Index of the memory block where the file node is stored
|
@param blockIdx Index of the memory block where the file node is stored
|
||||||
@param ofs Offset in bytes from the beginning of the serialized storage
|
@param ofs Offset in bytes from the beginning of the serialized storage
|
||||||
|
|
||||||
|
@deprecated
|
||||||
*/
|
*/
|
||||||
FileNode(const FileStorage* fs, size_t blockIdx, size_t ofs);
|
FileNode(const FileStorage* fs, size_t blockIdx, size_t ofs);
|
||||||
|
|
||||||
@ -614,7 +616,9 @@ public:
|
|||||||
CV_WRAP Mat mat() const;
|
CV_WRAP Mat mat() const;
|
||||||
|
|
||||||
//protected:
|
//protected:
|
||||||
const FileStorage* fs;
|
FileNode(FileStorage::Impl* fs, size_t blockIdx, size_t ofs);
|
||||||
|
|
||||||
|
FileStorage::Impl* fs;
|
||||||
size_t blockIdx;
|
size_t blockIdx;
|
||||||
size_t ofs;
|
size_t ofs;
|
||||||
};
|
};
|
||||||
@ -679,7 +683,7 @@ public:
|
|||||||
bool equalTo(const FileNodeIterator& it) const;
|
bool equalTo(const FileNodeIterator& it) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const FileStorage* fs;
|
FileStorage::Impl* fs;
|
||||||
size_t blockIdx;
|
size_t blockIdx;
|
||||||
size_t ofs;
|
size_t ofs;
|
||||||
size_t blockSize;
|
size_t blockSize;
|
||||||
|
@ -1376,9 +1376,9 @@ public:
|
|||||||
return new_ptr;
|
return new_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned getStringOfs( const std::string& key )
|
unsigned getStringOfs( const std::string& key ) const
|
||||||
{
|
{
|
||||||
str_hash_t::iterator it = str_hash.find(key);
|
str_hash_t::const_iterator it = str_hash.find(key);
|
||||||
return it != str_hash.end() ? it->second : 0;
|
return it != str_hash.end() ? it->second : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1468,7 +1468,7 @@ public:
|
|||||||
writeInt(ptr, (int)rawSize);
|
writeInt(ptr, (int)rawSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void normalizeNodeOfs(size_t& blockIdx, size_t& ofs)
|
void normalizeNodeOfs(size_t& blockIdx, size_t& ofs) const
|
||||||
{
|
{
|
||||||
while( ofs >= fs_data_blksz[blockIdx] )
|
while( ofs >= fs_data_blksz[blockIdx] )
|
||||||
{
|
{
|
||||||
@ -2048,18 +2048,24 @@ FileStorage& operator << (FileStorage& fs, const String& str)
|
|||||||
|
|
||||||
|
|
||||||
FileNode::FileNode()
|
FileNode::FileNode()
|
||||||
|
: fs(NULL)
|
||||||
{
|
{
|
||||||
fs = 0;
|
|
||||||
blockIdx = ofs = 0;
|
blockIdx = ofs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileNode::FileNode(const FileStorage* _fs, size_t _blockIdx, size_t _ofs)
|
FileNode::FileNode(FileStorage::Impl* _fs, size_t _blockIdx, size_t _ofs)
|
||||||
|
: fs(_fs)
|
||||||
{
|
{
|
||||||
fs = _fs;
|
|
||||||
blockIdx = _blockIdx;
|
blockIdx = _blockIdx;
|
||||||
ofs = _ofs;
|
ofs = _ofs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileNode::FileNode(const FileStorage* _fs, size_t _blockIdx, size_t _ofs)
|
||||||
|
: FileNode(_fs->p.get(), _blockIdx, _ofs)
|
||||||
|
{
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
FileNode::FileNode(const FileNode& node)
|
FileNode::FileNode(const FileNode& node)
|
||||||
{
|
{
|
||||||
fs = node.fs;
|
fs = node.fs;
|
||||||
@ -2082,7 +2088,7 @@ FileNode FileNode::operator[](const std::string& nodename) const
|
|||||||
|
|
||||||
CV_Assert( isMap() );
|
CV_Assert( isMap() );
|
||||||
|
|
||||||
unsigned key = fs->p->getStringOfs(nodename);
|
unsigned key = fs->getStringOfs(nodename);
|
||||||
size_t i, sz = size();
|
size_t i, sz = size();
|
||||||
FileNodeIterator it = begin();
|
FileNodeIterator it = begin();
|
||||||
|
|
||||||
@ -2091,7 +2097,7 @@ FileNode FileNode::operator[](const std::string& nodename) const
|
|||||||
FileNode n = *it;
|
FileNode n = *it;
|
||||||
const uchar* p = n.ptr();
|
const uchar* p = n.ptr();
|
||||||
unsigned key2 = (unsigned)readInt(p + 1);
|
unsigned key2 = (unsigned)readInt(p + 1);
|
||||||
CV_Assert( key2 < fs->p->str_hash_data.size() );
|
CV_Assert( key2 < fs->str_hash_data.size() );
|
||||||
if( key == key2 )
|
if( key == key2 )
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@ -2167,7 +2173,7 @@ std::string FileNode::name() const
|
|||||||
if(!p)
|
if(!p)
|
||||||
return std::string();
|
return std::string();
|
||||||
size_t nameofs = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24);
|
size_t nameofs = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24);
|
||||||
return fs->p->getName(nameofs);
|
return fs->getName(nameofs);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileNode::operator int() const
|
FileNode::operator int() const
|
||||||
@ -2292,12 +2298,12 @@ size_t FileNode::rawSize() const
|
|||||||
|
|
||||||
uchar* FileNode::ptr()
|
uchar* FileNode::ptr()
|
||||||
{
|
{
|
||||||
return !fs ? 0 : (uchar*)fs->p->getNodePtr(blockIdx, ofs);
|
return !fs ? 0 : (uchar*)fs->getNodePtr(blockIdx, ofs);
|
||||||
}
|
}
|
||||||
|
|
||||||
const uchar* FileNode::ptr() const
|
const uchar* FileNode::ptr() const
|
||||||
{
|
{
|
||||||
return !fs ? 0 : fs->p->getNodePtr(blockIdx, ofs);
|
return !fs ? 0 : fs->getNodePtr(blockIdx, ofs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileNode::setValue( int type, const void* value, int len )
|
void FileNode::setValue( int type, const void* value, int len )
|
||||||
@ -2328,7 +2334,7 @@ void FileNode::setValue( int type, const void* value, int len )
|
|||||||
else
|
else
|
||||||
CV_Error(Error::StsNotImplemented, "Only scalar types can be dynamically assigned to a file node");
|
CV_Error(Error::StsNotImplemented, "Only scalar types can be dynamically assigned to a file node");
|
||||||
|
|
||||||
p = fs->p->reserveNodeSpace(*this, sz);
|
p = fs->reserveNodeSpace(*this, sz);
|
||||||
*p++ = (uchar)(type | (tag & NAMED));
|
*p++ = (uchar)(type | (tag & NAMED));
|
||||||
if( tag & NAMED )
|
if( tag & NAMED )
|
||||||
p += 4;
|
p += 4;
|
||||||
@ -2402,8 +2408,8 @@ FileNodeIterator::FileNodeIterator( const FileNode& node, bool seekEnd )
|
|||||||
idx = nodeNElems;
|
idx = nodeNElems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fs->p->normalizeNodeOfs(blockIdx, ofs);
|
fs->normalizeNodeOfs(blockIdx, ofs);
|
||||||
blockSize = fs->p->fs_data_blksz[blockIdx];
|
blockSize = fs->fs_data_blksz[blockIdx];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2430,7 +2436,7 @@ FileNodeIterator& FileNodeIterator::operator=(const FileNodeIterator& it)
|
|||||||
|
|
||||||
FileNode FileNodeIterator::operator *() const
|
FileNode FileNodeIterator::operator *() const
|
||||||
{
|
{
|
||||||
return FileNode(idx < nodeNElems ? fs : 0, blockIdx, ofs);
|
return FileNode(idx < nodeNElems ? fs : NULL, blockIdx, ofs);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileNodeIterator& FileNodeIterator::operator ++ ()
|
FileNodeIterator& FileNodeIterator::operator ++ ()
|
||||||
@ -2442,8 +2448,8 @@ FileNodeIterator& FileNodeIterator::operator ++ ()
|
|||||||
ofs += n.rawSize();
|
ofs += n.rawSize();
|
||||||
if( ofs >= blockSize )
|
if( ofs >= blockSize )
|
||||||
{
|
{
|
||||||
fs->p->normalizeNodeOfs(blockIdx, ofs);
|
fs->normalizeNodeOfs(blockIdx, ofs);
|
||||||
blockSize = fs->p->fs_data_blksz[blockIdx];
|
blockSize = fs->fs_data_blksz[blockIdx];
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -1788,4 +1788,27 @@ TEST(Core_InputOutput, FileStorage_copy_constructor_17412)
|
|||||||
EXPECT_EQ(0, remove(fname.c_str()));
|
EXPECT_EQ(0, remove(fname.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Core_InputOutput, FileStorage_copy_constructor_17412_heap)
|
||||||
|
{
|
||||||
|
std::string fname = tempfile("test.yml");
|
||||||
|
FileStorage fs_orig(fname, cv::FileStorage::WRITE);
|
||||||
|
fs_orig << "string" << "wat";
|
||||||
|
fs_orig.release();
|
||||||
|
|
||||||
|
// no crash anymore
|
||||||
|
cv::FileStorage fs;
|
||||||
|
|
||||||
|
// use heap to allow valgrind detections
|
||||||
|
{
|
||||||
|
cv::FileStorage* fs2 = new cv::FileStorage(fname, cv::FileStorage::READ);
|
||||||
|
fs = *fs2;
|
||||||
|
delete fs2;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string s;
|
||||||
|
fs["string"] >> s;
|
||||||
|
EXPECT_EQ(s, "wat");
|
||||||
|
EXPECT_EQ(0, remove(fname.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace
|
}} // namespace
|
||||||
|
Loading…
Reference in New Issue
Block a user