前言
最近fix一个崩溃问题,崩溃关键信息如标题如示,具体的原因调用:assign(const value_type* __s, size_type __n)时第二个参数传了负数,负数赋值到无符号long时就是一个很大的正数了!
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s, size_type __n)
{
_LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::assign received nullptr");
size_type __cap = capacity();
if (__cap >= __n)
{
value_type* __p = _VSTD::__to_raw_pointer(__get_pointer());
traits_type::move(__p, __s, __n);
traits_type::assign(__p[__n], value_type());
__set_size(__n);
__invalidate_iterators_past(__n);
}
else
{
size_type __sz = size();
__grow_by_and_replace(__cap, __n - __cap, __sz, 0, __sz, __n, __s);
}
return *this;
}
void
basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace
(size_type __old_cap, size_type __delta_cap, size_type __old_sz,
size_type __n_copy, size_type __n_del, size_type __n_add, const value_type* __p_new_stuff)
{
size_type __ms = max_size();
if (__delta_cap > __ms - __old_cap - 1)
this->__throw_length_error(); //这里抛异常,导致崩溃
pointer __old_p = __get_pointer();
size_type __cap = __old_cap < __ms / 2 - __alignment ?
__recommend(_VSTD::max(__old_cap + __delta_cap, 2 * __old_cap)) :
__ms - 1;
pointer __p = __alloc_traits::allocate(__alloc(), __cap+1);
__invalidate_all_iterators();
if (__n_copy != 0)
traits_type::copy(_VSTD::__to_raw_pointer(__p),
_VSTD::__to_raw_pointer(__old_p), __n_copy);
if (__n_add != 0)
traits_type::copy(_VSTD::__to_raw_pointer(__p) + __n_copy, __p_new_stuff, __n_add);
size_type __sec_cp_sz = __old_sz - __n_del - __n_copy;
if (__sec_cp_sz != 0)
traits_type::copy(_VSTD::__to_raw_pointer(__p) + __n_copy + __n_add,
_VSTD::__to_raw_pointer(__old_p) + __n_copy + __n_del, __sec_cp_sz);
if (__old_cap+1 != __min_cap)
__alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1);
__set_long_pointer(__p);
__set_long_cap(__cap+1);
__old_sz = __n_copy + __n_add + __sec_cp_sz;
__set_long_size(__old_sz);
traits_type::assign(__p[__old_sz], value_type());
}
业务场景
具体的业务场可以抽像成出下示例代码
int main() {
string test;
char a[10] {'\0', 'c', 'c', 'b'};
unsigned long maxSize = -1;
cout << "size = " << strlen(a) << endl;
cout << "maxSize = " << maxSize << ", string.max_size = " << test.max_size() << endl;
test.assign(a, strlen(a) - 1);
}
如上代码的运行结果(macOS上)
/Users/dw_luogongwu/CLionProjects/untitled1/cmake-build-debug/untitled1
size = 0
maxSize = 18446744073709551615, string.max_size = 18446744073709551599
libc++abi.dylib: terminating with uncaught exception of type std::length_error: basic_string
Process finished with exit code 6
关键点
- strlen方法需要特别注意和处理’\0’(字符串结束符)的情况
- assign方法第二个参数用特别reivew,确保不是一个负数或一个很大的数,最算没有到string.max_size = 18446744073709551599,但是应用也不允许分配那么大的内存的,同样也会崩溃