Oberon space

General Category => Общий раздел => Тема начата: valexey_u от Сентябрь 14, 2016, 08:40:16 pm

Название: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 14, 2016, 08:40:16 pm
Имеем вот такой код на С++:

#include <vector>
#include <iostream>

using namespace std;

struct bor
{
    int mp[2];
    int cnt;
    bor(): mp({0,0}), cnt(0)
    {}
};
vector<bor> tr;
int go()
{
    tr.push_back(bor());
    cerr << "go " << tr.size() << ' ' << tr.size() - 1 << endl;
    return tr.size() - 1;
}

string s;
int add(int v, int i, int zn)
{
    cerr << "in " << v << ' ' << tr.size() <<' ' << i <<' ' << s.size() << endl;
    if (i == static_cast<int>(s.size()))
    {
        tr[v].cnt += zn;
        return tr[v].cnt;
    }
    int x = s[i] - '0';
    x = x % 2;
    if (tr[v].mp[x] == 0)
    {
       cerr << "go in " << endl;
       cerr << tr.size() <<' ' << tr[v].mp[x] << endl;
         tr[v].mp[x] = go();
       cerr << tr.size() <<' ' << tr[v].mp[x] << endl; 
         cerr << "go out " <<  endl;
    }
    return add(tr[v].mp[x], i + 1, zn);
}

int main()
{
    go();
    s = "01";
    add(0, 0, 1);
}

Найдите в коде ошибку, если она есть. Что делает программа вам знать не нужно, нужно чтобы программа успешно завершила работу.
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 14, 2016, 08:42:45 pm
Ну и дополнительный вопрос: могла ли возникнуть подобная ситуация в вашем любимом ЯП в аналогичном коде (если на вашем любтмом ЯП аналогичный код не пишут, ибо ЯП сильно другой, то это не считается).
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 15, 2016, 07:53:54 am
Программа скомпилялась, значит ошибок нет (алгоритм же не указан, значит любой алгоритм правилен).
Хотя есть сообщение о предупреждении:

10:28: warning: list-initializer for non-class type must not be parenthesized

Ну хз...
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 15, 2016, 11:05:51 am
Программа скомпилялась, значит ошибок нет (алгоритм же не указан, значит любой алгоритм правилен).
Это в цитатник! :-)
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 15, 2016, 11:06:40 am
Напомню, что программа как минимум не должна падать. Пользователь собирает программу gcc.
Название: Re: Найдите ошибку, если она есть.
Отправлено: kemiisto от Сентябрь 15, 2016, 12:04:55 pm
Что тут у нас? Geniepro открывает для себя новый вид ошибок: ошибки времени исполнения?  :D  Падает оно, да. Разбираться лень. ;D
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 15, 2016, 12:15:37 pm
Что тут у нас? Geniepro открывает для себя новый вид ошибок: ошибки времени исполнения?  :D  Падает оно, да. Разбираться лень. ;D
Он пришел из страны непуганных хаскелистов. :-)
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 15, 2016, 04:50:42 pm
Что тут у нас? Geniepro открывает для себя новый вид ошибок: ошибки времени исполнения?  :D  Падает оно, да. Разбираться лень. ;D
У меня не упало. Проверял онлайн-компилятором с сайта cpp.sh, возиться с установкой с++ компилеров лень, а борландовскому сибилдеру 2001 года я не очень доверяю проверку этой программы ))...
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 15, 2016, 04:58:07 pm
Кто-то ещё хочет попытаться? :-)
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 15, 2016, 05:02:57 pm
Поставил дома CodeBlock с GCC -- прога и правда падает )))
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 15, 2016, 05:06:23 pm
хз что там за ошибка, но одно могу сказать точно -- это тебе наказание за то, что говнокодишь всякую императивщину )))
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 15, 2016, 05:08:51 pm
хз что там за ошибка, но одно могу сказать точно -- это тебе наказание за то, что говнокодишь всякую императивщину )))

Это не мой код :-) Просто у знакомые столкнулись с вот этим. Помог багу отловить.
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 15, 2016, 05:21:09 pm
Ну как минимум вот в этой строке:

int x = s[i] - '0';
у тебя x становится отрицательной, когда i становится равной 2 и из строки s ты считываешь терминатор строки (число ноль).
Далее в строке:

Цитировать
if (tr[v].mp
  • == 0)
у тебя происходит обращение к элементу вектора tr с отрицательным индексом, это, видимо, и приводит к падению программы.

Не показывай такой говнокод своему работодателю -- он будет обязан уволить тебя )))
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 15, 2016, 05:22:45 pm
Что-за глюки у движка этого форума???
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 15, 2016, 05:24:03 pm
Ну как минимум вот в этой строке:
int x = s[i] - '0';у тебя x становится отрицательной, когда i становится равной 2 и из строки s ты считываешь терминатор строки (число ноль).
Далее в строке:
if (tr[v].mp[x] == 0)у тебя происходит обращение к элементу массива mp с отрицательным индексом, это, видимо, и приводит к падению программы.

Не показывай такой говнокод своему работодателю -- он будет обязан уволить тебя )))

ЗЫ. Накапай работодатюлю своих знакомых -- пусть их уволят )))
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 15, 2016, 05:26:51 pm
ну так чо, правильный ответ или как? ))
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 15, 2016, 05:30:33 pm
Ну как минимум вот в этой строке:
int x = s[i] - '0';у тебя x становится отрицательной, когда i становится равной 2 и из строки s ты считываешь терминатор строки (число ноль).
Далее в строке:
if (tr[v].mp[x] == 0)у тебя происходит обращение к элементу массива mp с отрицательным индексом, это, видимо, и приводит к падению программы.

Не показывай такой говнокод своему работодателю -- он будет обязан уволить тебя )))

ЗЫ. Накапай работодатюлю своих знакомых -- пусть их уволят )))

Нет, дело не в этом. Не становится там индекс отрицательным.
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 15, 2016, 06:24:13 pm
Короче, непонятно, чего она падает на выходе из третьего захода в процедуру add, вроде предпосылок для этого нет...
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 15, 2016, 06:53:10 pm
Короче, непонятно, чего она падает на выходе из третьего захода в процедуру add, вроде предпосылок для этого нет...

Нишмагла :-)
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 15, 2016, 07:50:50 pm
Короче, непонятно, чего она падает на выходе из третьего захода в процедуру add, вроде предпосылок для этого нет...

Нишмагла :-)
А нинада отлаживать какую-то хрень, у которой даже ТЗ нету )))
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 15, 2016, 08:44:04 pm
Короче, непонятно, чего она падает на выходе из третьего захода в процедуру add, вроде предпосылок для этого нет...

Нишмагла :-)
А нинада отлаживать какую-то хрень, у которой даже ТЗ нету )))

ТЗ есть, но оно тут не важно. Не привожу его, чтобы просто не отвлекать на всякие глупости.
Название: Re: Найдите ошибку, если она есть.
Отправлено: Romiras от Сентябрь 24, 2016, 08:23:00 pm
У кого есть PVS-Studio? Прогоните на нём.
Название: Re: Найдите ошибку, если она есть.
Отправлено: kemiisto от Сентябрь 26, 2016, 11:10:34 am
У кого есть PVS-Studio? Прогоните на нём.
А то мы не догадались...  ;)  Ничего.
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 26, 2016, 03:34:31 pm
У кого есть PVS-Studio? Прогоните на нём.
А то мы не догадались...  ;)  Ничего.

:-)

У меня, заняло около часа разобраться что там и как, после того, как попросили помочь. Программа естественно не моя, и к ней я отношения не имею.
Название: Re: Найдите ошибку, если она есть.
Отправлено: Romiras от Сентябрь 26, 2016, 10:40:29 pm
Переведи на Оберон - сразу станет ясно где ошибка.  ;)
Название: Re: Найдите ошибку, если она есть.
Отправлено: ilovb от Сентябрь 27, 2016, 10:49:05 pm
Как же мерзко выглядят плюсы...

Не шарю, но может тут обрезается чего при большом size()?:
if (i == static_cast<int>(s.size()))ну и зацикливание происходит...

зы Будто в канализацию нырнул :D
Название: Re: Найдите ошибку, если она есть.
Отправлено: kkkk от Сентябрь 28, 2016, 09:54:53 am
Решил глянуть на этот код.
Собрал "g++-5 -std=gnu++11 -g", запустил. Программа нормально завершилась выдав:
go 1 0
in 0 1 0 2
go in
1 0
go 2 1
2 0
go out
in 0 2 1 2
go in
2 0
go 3 2
3 0
go out
in 0 3 2 2
Я что-то упустил из виду?
Собрал по-другому - "g++ -std=c++11 -g -fsanitize=address -fsanitize=undefined" . Запустил - теперь она грохнулась на использовании освобождённой памяти
go 1 0
in 0 1 0 2
go in
1 0
go 2 1
=================================================================
==5542==ERROR: AddressSanitizer: heap-use-after-free on address 0x60200000eff0 at pc 0x000000402abf bp 0x7fff0f67c930 sp 0x7fff0f67c920
WRITE of size 4 at 0x60200000eff0 thread T0
    #0 0x402abe in add(int, int, int) /home/konstantin/projects/github/bubble_test/cpp-strange-error/mistake.cpp:36
    #1 0x40301a in main /home/konstantin/projects/github/bubble_test/cpp-strange-error/mistake.cpp:47
    #2 0x7f3bee08082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #3 0x4018c8 in _start (/home/konstantin/projects/github/bubble_test/cpp-strange-error/a.out+0x4018c8)

0x60200000eff0 is located 0 bytes inside of 12-byte region [0x60200000eff0,0x60200000effc)
freed by thread T0 here:
    #0 0x7f3bef767b2a in operator delete(void*) (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x99b2a)
    #1 0x404a5b in __gnu_cxx::new_allocator<bor>::deallocate(bor*, unsigned long) /usr/include/c++/5/ext/new_allocator.h:110
    #2 0x4044bb in std::allocator_traits<std::allocator<bor> >::deallocate(std::allocator<bor>&, bor*, unsigned long) /usr/include/c++/5/bits/alloc_traits.h:517
    #3 0x403ce2 in std::_Vector_base<bor, std::allocator<bor> >::_M_deallocate(bor*, unsigned long) /usr/include/c++/5/bits/stl_vector.h:178
    #4 0x4041f2 in void std::vector<bor, std::allocator<bor> >::_M_emplace_back_aux<bor>(bor&&) /usr/include/c++/5/bits/vector.tcc:438
    #5 0x403b35 in void std::vector<bor, std::allocator<bor> >::emplace_back<bor>(bor&&) /usr/include/c++/5/bits/vector.tcc:101
    #6 0x403498 in std::vector<bor, std::allocator<bor> >::push_back(bor&&) /usr/include/c++/5/bits/stl_vector.h:932
    #7 0x401a62 in go() /home/konstantin/projects/github/bubble_test/cpp-strange-error/mistake.cpp:16
    #8 0x402a5e in add(int, int, int) /home/konstantin/projects/github/bubble_test/cpp-strange-error/mistake.cpp:36
    #9 0x40301a in main /home/konstantin/projects/github/bubble_test/cpp-strange-error/mistake.cpp:47
    #10 0x7f3bee08082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

previously allocated by thread T0 here:
    #0 0x7f3bef767532 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x99532)
    #1 0x404d73 in __gnu_cxx::new_allocator<bor>::allocate(unsigned long, void const*) /usr/include/c++/5/ext/new_allocator.h:104
    #2 0x404c03 in std::allocator_traits<std::allocator<bor> >::allocate(std::allocator<bor>&, unsigned long) /usr/include/c++/5/bits/alloc_traits.h:491
    #3 0x404920 in std::_Vector_base<bor, std::allocator<bor> >::_M_allocate(unsigned long) /usr/include/c++/5/bits/stl_vector.h:170
    #4 0x403e0a in void std::vector<bor, std::allocator<bor> >::_M_emplace_back_aux<bor>(bor&&) /usr/include/c++/5/bits/vector.tcc:412
    #5 0x403b35 in void std::vector<bor, std::allocator<bor> >::emplace_back<bor>(bor&&) /usr/include/c++/5/bits/vector.tcc:101
    #6 0x403498 in std::vector<bor, std::allocator<bor> >::push_back(bor&&) /usr/include/c++/5/bits/stl_vector.h:932
    #7 0x401a62 in go() /home/konstantin/projects/github/bubble_test/cpp-strange-error/mistake.cpp:16
    #8 0x402ff7 in main /home/konstantin/projects/github/bubble_test/cpp-strange-error/mistake.cpp:45
    #9 0x7f3bee08082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

SUMMARY: AddressSanitizer: heap-use-after-free /home/konstantin/projects/github/bubble_test/cpp-strange-error/mistake.cpp:36 add(int, int, int)
Shadow bytes around the buggy address:
  0x0c047fff9da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9dc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9dd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9de0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c047fff9df0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa[fd]fd
  0x0c047fff9e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==5542==ABORTING
Похоже, такое действительно не во всех языках возможно. Налицо избыточная сложность "универсального хорошо отлаженного" решения,  и поэтому трудно понять, что оно там внутри делает. По-моему, тут не с ошибкой надо разбираться, а навелосипедить более простое, хотя и более объёмное решение.

Название: Re: Найдите ошибку, если она есть.
Отправлено: kkkk от Сентябрь 28, 2016, 11:14:57 am
tr[v].mp[x] = go();
Очевидная проблема в этом месте, так как go() изменяет tr.
Если изменить на
int tmp = go();
tr[v].mp[x] = tmp;
То всё нормально. Да, проблема в плохом понимании работы универсальных решений. И в наличии состояния, конечно  :D
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 28, 2016, 11:16:25 am
Не шарю, но может тут обрезается чего при большом size()?:
if (i == static_cast<int>(s.size()))ну и зацикливание происходит...
Неа.

Как же мерзко выглядят плюсы...
...
зы Будто в канализацию нырнул :D
Тут сам код выглядит относительно мерзко, ибо писался очень быстро (час-два), на скорость. При этом сама задача не сказать чтобы совсем тривиальная.

А придирки к языку на уровне {} VS begin/end, == VS =, := VS = and so on - не принимаются :-)
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 28, 2016, 11:23:14 am
tr[v].mp[x] = go();
Очевидная проблема в этом месте, так как go() изменяет tr.
Если изменить на
int tmp = go();
tr[v].mp[x] = tmp;
То всё нормально. Да, проблема в плохом понимании работы универсальных решений. И в наличии состояния, конечно  :D

Бинго! :-)

Очевидно, что очевидная проблема не столь очевидна, коль было столь длинное и долгое обсуждение с массой неверных гипотез. :-)

Что такое плохое понимание универсальных решения, я не очень понял. Но да, мутабельность тут подгадила, именно поэтому тот же haskell на голову выше в плане безопасности чем любая императивщина. Но у этого есть цена, иногда неприемлемая.

Теперь осталось ответить на второй вопрос - на вашем любимом ЯП возможна ли подобная ошибка?
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 28, 2016, 11:30:06 am
tr[v].mp[x] = go();Очевидная проблема в этом месте, так как go() изменяет tr.
Если изменить на int tmp = go();
tr[v].mp[x] = tmp;
То всё нормально. Да, проблема в плохом понимании работы универсальных решений. И в наличии состояния, конечно  :D
Бинго! :-)
Не понимаю, как это могло привести к падению программы? Ну подумаешь, добавили к вектору новый элемент в конец вместе с изменением одного из имеющихся в нём элементов, на что это влияет?
Походу это просто какая-то ошибка в компиляторе.
Название: Re: Найдите ошибку, если она есть.
Отправлено: kkkk от Сентябрь 28, 2016, 11:34:17 am
Очевидно, что очевидная проблема не столь очевидна, коль было столь длинное и долгое обсуждение с массой неверных гипотез. :-)
Очевидной она стала после использования средств контроля целостности памяти. Стало понятно, что обращение идёт не к тому, что изначально предполагалось, и оставалось только выяснить почему.

Что такое плохое понимание универсальных решений, я не очень понял.
Объект-хранилище как универсальное решение мимикрирует под то, чем он не является - под массив, чем вводит в заблуждение. Будь там банальный массив, проблемы бы тоже не было, если бы, конечно, было бы выделено достаточно памяти для него.

Теперь осталось ответить на второй вопрос - на вашем любимом ЯП возможна ли подобная ошибка?
В Си такой ошибки бы не было, потому что для него использовали бы массив, а не vector.
Название: Re: Найдите ошибку, если она есть.
Отправлено: kkkk от Сентябрь 28, 2016, 11:38:55 am
Не понимаю, как это могло привести к падению программы?
1. сначала была выполнена  tr[v].mp[x] , которая ссылалась на массив, использованный в vector в текущем состоянии.
2. затем go() добавила новый элемент в tr, что потребовало выделения нового массива и освобожения старого
3.  наконец было выполнено присваивание tr[v].mp[x] = go() , которое произвело запись в освобождённую память
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 28, 2016, 11:45:45 am
Короче говно этот ваш с++, что и требовалось доказать.
Пользуйтесь иммутабельными данными!!! Хаскеллем, короче!!!!!!
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 28, 2016, 11:47:23 am
Не понимаю, как это могло привести к падению программы?
1. сначала была выполнена  tr[v].mp[x] , которая ссылалась на массив, использованный в vector в текущем состоянии.
2. затем go() добавила новый элемент в tr, что потребовало выделения нового массива и освобожения старого
3.  наконец было выполнено присваивание tr[v].mp[x] = go() , которое произвело запись в освобождённую память
А почему компилятор этого не отследил и не переназначил область памяти при присваивании на новую? о_О баг какой-то, концептуальный...
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 28, 2016, 11:51:34 am
Очевидно, что очевидная проблема не столь очевидна, коль было столь длинное и долгое обсуждение с массой неверных гипотез. :-)
Очевидной она стала после использования средств контроля целостности памяти. Стало понятно, что обращение идёт не к тому, что изначально предполагалось, и оставалось только выяснить почему.

Что такое плохое понимание универсальных решений, я не очень понял.
Объект-хранилище как универсальное решение мимикрирует под то, чем он не является - под массив, чем вводит в заблуждение. Будь там банальный массив, проблемы бы тоже не было, если бы, конечно, было бы выделено достаточно памяти для него.

Дык и тут ровно то же самое :-) Смотри, фокус покажу:
переписываем main вот так:
int main()
{
    tr.reserve(100500);
    go();
    s = "01";
    add(0, 0, 1);
}

И ничего уже никуда не падает, память не портится :-)

Теперь осталось ответить на второй вопрос - на вашем любимом ЯП возможна ли подобная ошибка?
В Си такой ошибки бы не было, потому что для него использовали бы массив, а не vector.
Не массив, а указатель на массив. И смотрелось бы это так:
size_t len = 1;
bor* tr = malloc(len*sizeof(bor));

tr[v].mp[x] = go();
...
int go()
{
    bor* old = tr;
    len++;
    tr = malloc(len * sizeof(bor));
    memcpy(tr, old, (len-1)*sizeof(bor));
    free(old);
    bor b;
    init(&b);
    tr[len-1] = b;
    return len-1;
}
Название: Re: Найдите ошибку, если она есть.
Отправлено: kkkk от Сентябрь 28, 2016, 12:08:50 pm
Дык и тут ровно то же самое :-) Смотри, фокус покажу:
переписываем main вот так:
int main()
{
    tr.reserve(100500);
    go();
    s = "01";
    add(0, 0, 1);
}

И ничего уже никуда не падает, память не портится :-)
О таком фокусе я знаю, но в общем случае резерва не требуется, в то время как в Си - он обязателен.

Не массив, а указатель на массив. И смотрелось бы это так:
size_t len = 1;
bor* tr = malloc(len*sizeof(bor));

tr[v].mp[x] = go();
...
int go()
{
    bor* old = tr;
    len++;
    tr = malloc(len * sizeof(bor));
    memcpy(tr, old, (len-1)*sizeof(bor));
    free(old);
    bor b;
    init(&b);
    tr[len-1] = b;
    return len-1;
}
В том-то и дело, что для Си это
Название: Re: Найдите ошибку, если она есть.
Отправлено: ilovb от Сентябрь 28, 2016, 04:37:01 pm
2. затем go() добавила новый элемент в tr, что потребовало выделения нового массива и освобожения старого

Жесть. Это ошибка где-то на уровне генов в с++.

Ну в общем то ничего нового.
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 28, 2016, 08:56:57 pm
О таком фокусе я знаю, но в общем случае резерва не требуется, в то время как в Си - он обязателен.
Какие-то странные представления о Си.. Конечно же и в Си это не обязательно.

...
В том-то и дело, что для Си это
  • Трудоёмко, поэтому чаще будет задействовано более простое решение - выделения столько памяти, сколько должно хватить для всех допустимых случаев, возможно, по формуле
  • Даже если реализовано автоувеличение размера, оно явное и очевидное, что делает проблему более понятной и менее вероятной

Выделить сразу памяти столько сколько будет необходимо в общем случае либо невозможно, либо слишком ресурсоёмко для подобных классов задачек как минимум.

На тему явного и очевидного, то в Си в реальном коде, это смотрелось бы примерно так, на самом деле.
g_array_index(ts, bor, v).mp[x] = go();
...
int go() {
        bor b;
        init(&b);
        g_array_append_val(ts, b);
        return ts->len-1;
}
И ровно с той же семантикой.

Никто по сто раз писать один и тот же велосипед для банального динамического массива/вектора не будет ни в одном из языков. Все либо пишут свои либы, либо используют уже написанные.

Ну, то есть по сути ты говоришь, что это не С++ плохой как язык и им не надо пользоваться, а это использование готовых либ плохо и ими не следует пользоваться в любом языке, следует максимально на каждый чих писать велосипед. Причем сколько мест использования подобного кода, столько велосипедов в проекте и должно быть. Так сказать, по велосипеду отдельному на каждое место использования :-)
Название: Re: Найдите ошибку, если она есть.
Отправлено: valexey_u от Сентябрь 28, 2016, 08:59:49 pm
2. затем go() добавила новый элемент в tr, что потребовало выделения нового массива и освобожения старого

Жесть. Это ошибка где-то на уровне генов в с++.

Ну в общем то ничего нового.

То есть, переводя на обычный язык, получается вроде того, что "в чем тут проблема, как это лечить (на уровне языка, либы или же подходов) и из за чего это случается я не знаю, но в любом случае это лишнее подтверждение тому, что С++ -- говно" :-)

Покажите мне язык где подобная ошибка не может возникнуть в принципе!
Название: Re: Найдите ошибку, если она есть.
Отправлено: kkkk от Сентябрь 28, 2016, 10:54:08 pm
О таком фокусе я знаю, но в общем случае резерва не требуется, в то время как в Си - он обязателен.
Какие-то странные представления о Си. Конечно же и в Си это не обязательно.
У меня действительно странные представления о Си - основаны на логике и опыте ежедневного использования, к счастью и к сожалению. В Си в невыделенной памяти  ничего работать не будет и это очевидно. Даже если программист перепил чаю и забыл выделить память, после первого же неудачного запуска он это исправит. В С++ с вектором в большинстве случаев можно не волноваться, Tefal думает за вас. Но иногда это выливается в непонимание, как работает программа и приходится тратить немало времени, чтобы выяснить причину проблемы. Речь об этом.
 

Цитировать
Выделить сразу памяти столько сколько будет необходимо в общем случае либо невозможно, либо слишком ресурсоёмко для подобных классов задачек как минимум.
В общем случае - нет, а в частном зачастую есть асимптотические формулы, позволяющие найти достаточно хорошее приближение сверху, и именно такое выделение будет самым эффективным по скорости. И памяти нужно в 1.5-2 раза меньше, чем с саморасширяющимся вектором(при удачных для вектора раскладах - одинаковое). К тому же, не надо во время вычисления обрабатывать отказ от выделения очередной порции памяти - хватит или нет ясно в самом начале.

Цитировать
На тему явного и очевидного, то в Си в реальном коде, это смотрелось бы примерно так, на самом деле.
g_array_index(ts, bor, v).mp[x] = go();
...
int go() {
        bor b;
        init(&b);
        g_array_append_val(ts, b);
        return ts->len-1;
}
И ровно с той же семантикой.
Даже при повторении семантики один в один, проблема в Си видна гораздо лучше, потому что в нём нет возможности для самописных структур и функций мимикрировать под массивы, а потому вводить в заблуждение.

Цитировать
Никто по сто раз писать один и тот же велосипед для банального динамического массива/вектора не будет ни в одном из языков. Все либо пишут свои либы, либо используют уже написанные.
А я реализовал нечто подобное, только коллеги это отвергли.

Цитировать
Ну, то есть по сути ты говоришь, что это не С++ плохой как язык и им не надо пользоваться, а это использование готовых либ плохо и ими не следует пользоваться в любом языке, следует максимально на каждый чих писать велосипед.
Нет, я этого не говорю, да и что такое плохой язык, я тоже плохо понимаю.

Цитировать
Причем сколько мест использования подобного кода, столько велосипедов в проекте и должно быть. Так сказать, по велосипеду отдельному на каждое место использования :-)
А это зависит от задачи, решаемой библиотекой или велосипедом. Для банального кода лучше велосипед по месту без запрета на переиспользование неподалёку. Нередко оказывается экономичней помнить базовые принципы и уметь их быстро воплощать, чем помнить и разбираться в нюансах редкоиспользуемой библиотеки с постоянным сверением с документацией.  Для нетривиального кода, например, компрессора данных - однозначно нужно использовать готовое решение, если оно достаточно хорошо для твоей задачи.
Есть ещё вопрос лицензий. Я, как пролетарий, сталкиваюсь с тем, что часто не могу использовать свой старый код. Чтобы переиспользовать нужно получить непростое разрешение на выкладывание в Open Source. Дело благородное, но также сопряжено с дополнительными затратами на оформление кода, соответствующее уровню компании, как в ней это видят. И вот для такой банальщины, как вектор,  проще всего оказывается наколбасить по месту либо использовать ещё более простое решение, и часто это работает.
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 29, 2016, 05:10:39 am
2. затем go() добавила новый элемент в tr, что потребовало выделения нового массива и освобожения старого
Жесть. Это ошибка где-то на уровне генов в с++.

Ну в общем то ничего нового.
Вообще-то аналогичная проблема была бы возможна и в обероне, если бы кто-то удосужился в нём реализовать класс вектор. Впрочем, думаю, можно и обероновским массивом такое же провернуть.
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 29, 2016, 05:21:59 am
Покажите мне язык где подобная ошибка не может возникнуть в принципе!
Ну хаскель же! даже если там работать с мутабельным вектором, просто так сделать аналогtr[v].mp[x] = go();не вышло бы из-за дизайна языка, пришлось бы делать аналогint tmp = go();
tr[v].mp[x] = tmp;
Но выглядел бы такой код на хаскелле страшно, это точно )))
Название: Re: Найдите ошибку, если она есть.
Отправлено: kkkk от Сентябрь 29, 2016, 10:58:56 am
Вообще-то аналогичная проблема была бы возможна и в обероне, если бы кто-то удосужился в нём реализовать класс вектор. Впрочем, думаю, можно и обероновским массивом такое же провернуть.
Эта проблема невозможна в Обероне ни с вектором ни с массивом. Может я ошибаюсь, но тогда покажите как.
Название: Re: Найдите ошибку, если она есть.
Отправлено: ilovb от Сентябрь 29, 2016, 06:41:42 pm
Geniepro, вот ты все мутабельность упоминаешь (как и все функциональщики).
Можно подумать что причиной таких фейлов является одна только мутабельность.

Откуда вообще возник этот миф будто изменение состояния это зло?
Это же чепуха голимая. И хаскелы всякие сокращают количество ошибок
совсем не потому, что в них "нет состояния" (http://ic.pics.livejournal.com/ledashchev/15997568/60059/60059_900.jpg)
А потому, что в них заложена более строгая модель вычислений.
Тут адепт бы долго нес херню про типы, монады и прочее трехомудье.
Тогда как все гораздо проще. В любом языке заложена некая модель вычислений.
К какой парадигме принадлежит эта модель, совершенно насрать.
Важно лишь то, насколько эта модель проста и согласована.
Хорошая модель не должна давать написать то, что может похоронить модель в рантайме.
Понятно, что есть динамика, от которой избавиться даже в теории нельзя.
Но речь о другом.
Если язык позволяет свободно обращаться к указателю, который может быть невалидным,
то это херовый язык с кривой моделью.
В правильной модели либо указатель должен быть всегда валидным,
либо язык не должен пропускать обращение к такому указателю без предварительной проверки
его валидности.
Ну все тупо же и очевидно. Если указатель может быть в двух состояниях (валид/инвалид),
то неопределенность должна быть как-то разрешена перед обращением к нему.
Если провести параллель с Обероном, то это охрана типа. Убери охрану
из языка и будешь свободно обращаться к отсутствующим полям записей.

Это свойство и нравится оберонщикам. Это и есть хорошая модель.

И все мы знаем, что даже в обероне в этой модели есть дырка.
Более того в большинстве языков есть NIL. И большинство
языков (включая оберон) позволяют обращаться к указателю без проверки на NIL.
И ведь очевидно, что это косяк в модели, который растащили по языкам все, кому не лень.
Даже Вирт.

Проблема в кривых моделях.

Состояния и мутабельность - это страшилки для дураков.
Название: Re: Найдите ошибку, если она есть.
Отправлено: ilovb от Сентябрь 29, 2016, 07:28:51 pm
Покажите мне язык где подобная ошибка не может возникнуть в принципе!

Тык эта... я на таком языке на хлеб зарабатываю.
Внутренний язык платформы 1С называется :D
Правда в нем другого говна ушат...

зы Ну а ты тут должен поржать и ответить типа: "да это ж не язык" или "сравнил жопу  пальцем" :D
Тем не менее твою просьбу я выполнил.
Название: Re: Найдите ошибку, если она есть.
Отправлено: kkkk от Сентябрь 29, 2016, 08:04:07 pm
Покажите мне язык где подобная ошибка не может возникнуть в принципе!
Я только сейчас обратил внимание на категоричность запроса - не может возникнуть в принципе. Возможно, Алексей захотел пошутить, потому что, в принципе, в любом полном по Тьюрингу языке, такая ошибка может возникнуть.

Рассмотрим доказательство. Как мы уже выяснили,  в С++ такая ошибка возможна, а значит, возможна везде, где можно создать  виртуальную машину и компилятор С++ для неё, который соберёт приведённую программу с ошибкой. Это возможно в любом полном по Тьюрингу языке. Доказано.

Так что все эти ваши обероны, хаскели и даже русские коболы уязвимы.
Название: Re: Найдите ошибку, если она есть.
Отправлено: ilovb от Сентябрь 29, 2016, 08:14:39 pm
Ну нет. Если речь о данной конкретной ошибке, то в 1С такой точно не может быть.
Другое дело, что к валексеевскому "подобная ошибка" приплести можно что угодно.
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 30, 2016, 06:44:26 am
Geniepro, вот ты все мутабельность упоминаешь (как и все функциональщики).
Ну вообще-то не все функциональщики против мутабельности. Хаскеллеры утверждают, что наиболее полноценное ФП возможно в условиях полной изоляции мутабельности в определённые "гетто", из которых мутабельность не может выйти. В хаскелле это монада IO.
Но есть всякие лисперы, например. Они тоже функциональщики, но мутабельность у них доступна почти как у паскалистов или сишников.

Можно подумать что причиной таких фейлов является одна только мутабельность.

Откуда вообще возник этот миф будто изменение состояния это зло?
В данной теме проблема возникла из-за неконтролируемой мутабельности. В хаскелле конкретно эта проблема не возникла бы, потому что в хаскелле жёсткий контроль над мутабельностью.
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 30, 2016, 06:47:27 am
Рассмотрим доказательство. Как мы уже выяснили,  в С++ такая ошибка возможна, а значит, возможна везде, где можно создать  виртуальную машину и компилятор С++ для неё, который соберёт приведённую программу с ошибкой. Это возможно в любом полном по Тьюрингу языке. Доказано.
Это останется проблемой с++, а вовсе не того языка, на котором будет написана виртуальная машина для с++.
Странное доказательство.
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 30, 2016, 06:57:26 am
Покажите мне язык где подобная ошибка не может возникнуть в принципе!
Я только сейчас обратил внимание на категоричность запроса - не может возникнуть в принципе. Возможно, Алексей захотел пошутить, потому что, в принципе, в любом полном по Тьюрингу языке, такая ошибка может возникнуть.

Рассмотрим доказательство. Как мы уже выяснили,  в С++ такая ошибка возможна, а значит, возможна везде, где можно создать  виртуальную машину и компилятор С++ для неё, который соберёт приведённую программу с ошибкой. Это возможно в любом полном по Тьюрингу языке. Доказано.

Так что все эти ваши обероны, хаскели и даже русские коболы уязвимы.
Твой тезис имел бы смысл, сформулируй ты его иначе: эта ошибка возможна в любом языке, для которого можно написать транслятор из с++, полностью сохранающий семантику исходной программы.

Ну так для хаскелла, выходит, такого транслятора нельзя создать, потому что семантика не сохраняется.
Более того, подозреваю, что разные компиляторы с++ могут по разному компилировать эту программу, по разному понимая семантику этой программы. Где-то будет получаться эта ошибка, где-то не будет...
Название: Re: Найдите ошибку, если она есть.
Отправлено: vlad от Сентябрь 30, 2016, 07:24:11 am
Перевыделение памяти при изменении std::vector и невалидные ссылки на элементы после этого - еще не самое "интересное" свойство. Вектор еще может в каких-то ситуациях (зависит от реализации) переприсваивать свои элементы (operator =). Вот я помню помучился с отловом такой баги... Оно проявлялось только на одной платформе (реализация STL) и зависило от последовательности изменений вектора.
Название: Re: Найдите ошибку, если она есть.
Отправлено: kkkk от Сентябрь 30, 2016, 10:59:30 am
Твой тезис имел бы смысл, сформулируй ты его иначе: эта ошибка возможна в любом языке, для которого можно написать транслятор из с++, полностью сохранающий семантику исходной программы.

Ну так для хаскелла, выходит, такого транслятора нельзя создать, потому что семантика не сохраняется.
Более того, подозреваю, что разные компиляторы с++ могут по разному компилировать эту программу, по разному понимая семантику этой программы. Где-то будет получаться эта ошибка, где-то не будет...
Вы уверждаете, что транслятор С++, написанный на Хаскелле вместе с программой на С++, всунутой в строку в исходнике на Хаскелле, не является программой, написанной на Хаскелле? Если нет, то что не так? Обратите внимание, что речь не о практической достижимости, а о принципиальной возможности. Конечно, такой принципиальной возможности можно достичь гораздо более простым путём, чем создание транслятора C++, но версия с транслятором веселей и наглядней.
Название: Re: Найдите ошибку, если она есть.
Отправлено: Geniepro от Сентябрь 30, 2016, 01:16:33 pm
Вы уверждаете, что транслятор С++, написанный на Хаскелле вместе с программой на С++, всунутой в строку в исходнике на Хаскелле, не является программой, написанной на Хаскелле? Если нет, то что не так? Обратите внимание, что речь не о практической достижимости, а о принципиальной возможности. Конечно, такой принципиальной возможности можно достичь гораздо более простым путём, чем создание транслятора C++, но версия с транслятором веселей и наглядней.
Ок, хорошо, если так рассуждать, то, по аналогии с написанной на хаскелле виртуальной машиной с++, в случае выполнения с++-ной программы на реальном голом железе проблема этой программы не в с++, а в электрической принципиальной схеме процессора. Так что ли, получается?
По-моему, такие рассуждения лишены смысла.
Название: Re: Найдите ошибку, если она есть.
Отправлено: kkkk от Сентябрь 30, 2016, 01:39:49 pm
Верно, поскольку компьтер - это функциональный эквивалент машины Тьюринга с ограничением на память, которой, впрочем, достаточно, чтобы этим пренбречь. Раз проблема возможна в полном по Тьюрингу языке, то проблема есть и в аналоге Тьюринг-машины, то есть компьютере. Эти размышления имеют теоретический смысл, а о большем я и не говорил.

Обратите внимание, изначально я тоже напирал на практическую сторону, объяснив, что в Си такой ошибки не возникнет, но Алексей настаивал, что возникнет. Он дополнил Си до семантики С++, достаточной для этой задачи, предложив использовать вектор, написанный на Си. Обычно сишники так не поступают, они стараются использовать более простые средства, но принципиальная-то возможность есть, благо и копать недалеко. Позже мне пришло в голову, что  с такой точки зрения все языки уязвимы, так как любой полный по Тьюрингу язык можно дополнить до семантики С++. В общем случае, конечно, копать придётся глубоко и никто в здравом уме не станет этого делать, но мы, прикинувшись математиками, делаем вид, что нам всё равно.