2012-02-08 3 views
1

Рассмотрим следующий довольно простой C++ код:Valgrind не показывает ошибки с копией массива?

#include <algorithm> 
#include <iostream> 
using namespace std; 

int main() 
{ 
    int a[7] = {1, 2, 3, 4, 5, 6, 7}; 
    int b[7]; 
    copy(a, a+7, b); 
    for (int i=0; i<8; ++i) 
    cout << b[i] << endl; 
} 

Теперь вот что я получаю, когда я загрузить этот код в БГД:

(gdb) b 1 
Breakpoint 1 at 0x100000a64: file stdcopy.cpp, line 1. 
(gdb) r 
Starting program: /Users/Babai/pastebin/a.out 
Reading symbols for shared libraries ++......................... done 

Breakpoint 1, main() at stdcopy.cpp:7 
7  int a[7] = {1, 2, 3, 4, 5, 6, 7}; 
(gdb) n 
9  copy(a, a+7, b); 
(gdb) s 
std::copy<int*, int*> (__first=0x7fff5fbffb8c, __last=0x7fff5fbffba8, __result=0x7fff5fbffb70) at stl_algobase.h:398 
398  const bool __in = __is_normal_iterator<_InputIterator>::__value; 
(gdb) bt 
#0 std::copy<int*, int*> (__first=0x7fff5fbffb8c, __last=0x7fff5fbffba8, __result=0x7fff5fbffb70) at stl_algobase.h:398 
#1 0x0000000100000acd in main() at stdcopy.cpp:9 
(gdb) up 
#1 main() at stdcopy.cpp:10 
10 for (int i=0; i<8; ++i) 
(gdb) p &a 
$1 = (int (*)[7]) 0x7fff5fbffb8c 
(gdb) p a + 7 
$2 = (int *) 0x7fff5fbffba8 

Я не вижу каких-либо ошибок VALGRIND в этом коде, и я Интересно, почему. Массив a имеет 7 элементов и доступен до +6 в порядке, но почему valgrind не показывает + 7 как допустимую ошибку?

+0

... «как допустимая ошибка»? – 0xC0000022L

+0

Должен ли он сообщить об этом? Я не слишком знаком с valgrind, но вам может быть позволено писать в эту память. –

+3

Почему вы показываете нам выход GDB? Почему вы говорите о valgrind, но не показываете выход valgrind? Это шутка? –

ответ

1

Проходя мимо конца массива, получается Неопределенное поведение, что означает, что все может произойти. Тем не менее, ваш указатель на массив, разрешено идти мимо массива, если указатель не разыменовывается.

Это разрешено для проверки конца массива и используется в контейнерах с итераторами. Функция end() для итератора контейнера указывает на один конец. Однако это никогда не будет разыменовано, иначе вы находитесь в зоне неопределенного поведения.

+0

Вот что мне нужно было знать. Не могли бы вы указать мне соответствующий раздел стандарта, который упоминает об этом. – Fanatic23

+0

Я думаю, что он говорит о 'for (int i = 0; i <8; ++ i)', что приводит к тому, что указатель на элемент, находящийся за концом, разыменовывается (я не сделал нисходящего) –

+0

@SethCarnegie посмотрите, что OP говорит выше вашего комментария. Я знаю, что 8 проходит один конец, чтобы разыменоваться, однако он говорит о + 7 в своем вопросе. –

2

Средство memcheck в Valgrind не сообщает об ошибках памяти на основе стека (если вы не набрали верхнюю часть вашего адресного пространства стека). Он сообщает кучу ошибок памяти. Распределяйте массив в куче, и Valgrind должен сообщить недействительный читает

#include <algorithm> 
#include <iostream> 
#include <cstring> 

int main() 
{ 
    int* a = new int[7]; 
    int* b = new int[7]; 
    std::memset(a, 0, sizeof(int) * 7); 
    std::memset(b, 0, sizeof(int) * 7); 

    std::copy(a, a+7, b); 

    for (int i=0; i<8; ++i) 
    std::cout << b[i] << std::endl; 

    delete[] a; 
    delete[] b; 
} 


От Valgrind manual (не из copy, но из for петли, которая проходит мимо конца.):

Memcheck - детектор ошибок памяти. Он может обнаруживать следующие проблемы , которые являются общими для программ на C и C++.

Доступ к памяти не требуется, например. overrunning и underrunning heap блоки, перекрывающие верхнюю часть стека, и доступ к памяти после он был освобожден. Использование неопределенных значений, т. Е. Значений, которые не были инициализированы или получены из других неопределенных значений.

Неправильного освобождение динамической памяти, такие как двойные освобождением блоки кучи, или несогласованное использование таНоса/новое/новый [] против свободного/удалить/удалить []

Перекрытия в исходные текстах и ​​Dst указателей в тетсру и связанных функций.

Утечки памяти.

0

Выражение a+7 не является ошибкой - это конечный индикатор для копии и никогда не доступен. Копия выполняется до, но не включая a+7.

Однако cout << b[i] << endl; выполняется, когда i == 7 - это еще одна история - это ошибка (хотя я не уверен, что valgrind предназначен для того, чтобы поймать такую ​​ошибку в массиве, не выделенном кучкой).

0

Думаю, я понял.Что в основном происходит, так это то, что нет доступа * (a + 7) в любом месте. Звонок на std :: copy в конечном итоге сводится к memmove и пара с тем, что Seth размещен в разделе 5.7.5. Я думаю, что мы здесь хороши:

(gdb) down 
#0 std::__copy_aux<int*, int*> (__first=0x7fff5fbffb8c, __last=0x7fff5fbffba8, __result=0x7fff5fbffb70) at stl_algobase.h:313 
313     && __are_same<_ValueTypeI, _ValueTypeO>::__value); 
(gdb) n 
315  return std::__copy<__simple, _Category>::copy(__first, __last, __result); 
(gdb) s 
std::__copy<true, std::random_access_iterator_tag>::copy<int> (__first=0x7fff5fbffb8c, __last=0x7fff5fbffba8, __result=0x7fff5fbffb70) at stl_algobase.h:298 
298  std::memmove(__result, __first, sizeof(_Tp) * (__last - __first)); 
(gdb) list 
293  { 
294  template<typename _Tp> 
295   static _Tp* 
296   copy(const _Tp* __first, const _Tp* __last, _Tp* __result) 
297   { 
298  std::memmove(__result, __first, sizeof(_Tp) * (__last - __first)); 
299  return __result + (__last - __first); 
300  } 
301  }; 
302 
Смежные вопросы