Баг или не баг. G++ 4.7.2
От: lnkuser  
Дата: 20.07.13 07:07
Оценка: -2 :))) :)))
Добрый день!

Столкнулся с аномалией. В нижеприведенном коде пытаюсь получить МАС из arp таблицы. Для воспроизведения надо поставить в строке 50


cout << resolve_mac("192.168.1.1") << endl;


адрес устройства, видимого в вашей локальной сети и чтобы он был виден в вашей arp таблице (arp -n).

компилирую без ошибок и варнингов
$ g++ bug.cpp --std=c++0x -Wall -Wextra

пустой вывод, видимо возвращается NULL
$ ./a.out

$

Раскомментируем простой cout в строке 36

cout << "> " << ip << endl;


и код работает как надо, тоесть функция возвращает МАС как и задумывалось.

$ ./a.out
> 192.168.1.1
00:01:02:03:04:05


Я создал багрепорт http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57937, там мне ответили что дело в возвращении адреса локальной переменной.
Но! Я не могу понять, как влияет простой cout на возвращение или не возвращение адреса локальной переменной ? При чем тут вообще cout?



#include <iostream>
#include <arpa/inet.h>
#include <string.h>

using namespace std;

#define PROCFS_ARP "/proc/net/arp"


const char * resolve_mac(const char *ip_to_resolve)
{
    uint32_t ipaddr = inet_addr(ip_to_resolve);
    if (ipaddr == INADDR_NONE)
        return NULL;

    char ip[100];
    char hwa[100];
    char mask[100];
    char line[100];
    char dev[100];
    int flags, num, type;

    FILE *fp;

    fp = fopen(PROCFS_ARP, "r");
    if (fp == NULL)
        return NULL;

    memset(&hwa, 0, sizeof(hwa));

    if (fgets(line, sizeof(line), fp) != (char *)NULL) {
        for (; fgets(line, sizeof(line), fp); ) {
            num = sscanf(line, "%s 0x%x 0x%x %100s %100s %100s\n", ip, &type, &flags, hwa, mask, dev);
            if (num < 4)
                break;
            //cout << "> " << ip << endl;
            if (inet_addr(ip) == ipaddr) {
                const char *m = hwa;
                return m;
            }
        }
    }

    return NULL;
}


int main()
{
    cout << resolve_mac("192.168.1.1") << endl;
    return 0;
}





Ubuntu 12.10 с последними обновлениями.

$ g++ -v
gcc version 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1)


$ uname -a
Linux notebook 3.5.0-36-generic #57-Ubuntu SMP Wed Jun 19 15:10:49 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
Re: Баг или не баг. G++ 4.7.2
От: omgOnoz  
Дата: 20.07.13 07:39
Оценка:
Может влиять, я помню как пришлось использовать кривое апи, которое тоже возвращало локальную переменную .
Так вод любой код после вызова апи мог убить возвращаемое значение!
Re: Баг или не баг. G++ 4.7.2
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 20.07.13 07:40
Оценка:
Здравствуйте, lnkuser, Вы писали:

L>Я создал багрепорт http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57937, там мне ответили что дело в возвращении адреса локальной переменной.

L>Но! Я не могу понять, как влияет простой cout на возвращение или не возвращение адреса локальной переменной ? При чем тут вообще cout?

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

То, как вы написали — это классическое "неопределённое поведение" (UB — undefined behavior) и не разрешается к использованию.

Для такой простой функции можете объявить буфер, в котором отдаётся значение, как static. Он будет затираться при последующих вызовах, но если это вас устраивает, то нет проблем.
Для более рекомендованных сейчас стилей делается strdup() внутреннего буфера (с free() у вызывающего) или выделение буфера вызывающим.
The God is real, unless declared integer.
Re: Баг или не баг. G++ 4.7.2
От: UA Украина  
Дата: 20.07.13 07:44
Оценка:
Здравствуйте, lnkuser, Вы писали:

cout может и не влияет, а operator << может повлиять
Re[2]: Баг или не баг. G++ 4.7.2
От: Ops Россия  
Дата: 20.07.13 07:47
Оценка:
Здравствуйте, netch80, Вы писали:

N>Для такой простой функции можете объявить буфер, в котором отдаётся значение, как static. Он будет затираться при последующих вызовах, но если это вас устраивает, то нет проблем.

N>Для более рекомендованных сейчас стилей делается strdup() внутреннего буфера (с free() у вызывающего) или выделение буфера вызывающим.
Это ж плюсы (хоть и большая часть кода C-style), можно std::string использовать.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re: Баг или не баг. G++ 4.7.2
От: ArtDenis Россия  
Дата: 20.07.13 07:57
Оценка:
Здравствуйте, lnkuser, Вы писали:

L>Я создал багрепорт http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57937, там мне ответили что дело в возвращении адреса локальной переменной.

L>Но! Я не могу понять, как влияет простой cout на возвращение или не возвращение адреса локальной переменной ? При чем тут вообще cout?

При неопределённом поведении, которое происходит из-за возврата локальной переменной, на результат выполнения может повлиять что угодно. На то оно и неопределённое поведение.
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re: Баг или не баг. G++ 4.7.2
От: Константин Россия  
Дата: 20.07.13 08:09
Оценка: +4 :))
Здравствуйте, lnkuser, Вы писали:

L>Я создал багрепорт http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57937, там мне ответили что дело в возвращении адреса локальной переменной.

L>Но! Я не могу понять, как влияет простой cout на возвращение или не возвращение адреса локальной переменной ? При чем тут вообще cout?

Я не могу понять, как можно иметь достаточно энергии, чтобы создать багрепорт на gcc, прим этом совершенно не понимая базовых принципов языка?
Re[2]: Баг или не баг. G++ 4.7.2
От: omgOnoz  
Дата: 20.07.13 09:18
Оценка:
Счастливый он человек
Re: Баг или не баг. G++ 4.7.2
От: Шахтер Интернет  
Дата: 20.07.13 10:52
Оценка: 8 (1) +1
Здравствуйте, lnkuser, Вы писали:

Нельзя возвращать адрес локальной переменной из функции, поскольку как только функция закончит свою работу, life-time переменной закончится и этот указатель будет
указывать на несуществующий объект.
В подобных случаях можно использовать класс вместо функции.


class ResolveMAC
 {
   char buf[100];

  public:

   explicit ResolveMAC(const char *ip_to_resolve); // для хранения возвращаемой строки используем buf

   operator const char * () const { return buf; }
 };

cout << ResolveMAC("192.168.1.1") << endl ;
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: Баг или не баг. G++ 4.7.2
От: rg45 СССР  
Дата: 21.07.13 05:06
Оценка: 4 (1) +1 :)
Здравствуйте, Константин, Вы писали:


К>Я не могу понять, как можно иметь достаточно энергии, чтобы создать багрепорт на gcc, прим этом совершенно не понимая базовых принципов языка?


В жизни так обычно и бывает — у одних понимание, у других — энергия.
--
Справедливость выше закона. А человечность выше справедливости.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.