среда, 19 июня 2013 г.

Баг компилятора MS Visual Studio 2012


Недавно наткнулся в MS Visual Studio 2012 на неприятный баг... Обозначенная в данной теме ошибка компилятора MS Visual Studio 2012 не является смертельной и её можно обойти (ниже способ будет указан), однако она опасна, т.к. наличие оной может неожиданно привести либо к неправильной работе программы (если в глобальном пространстве имён компилятором будет обнаружена другая функция с такой же сигнатурой, пусть даже не вами объявленная), либо, в противном случае, выдаст ошибку времени редактирования связей.

В интернете обнаружил такую заявку, с той же самой проблемой, которая, как оказалось, была найдена ещё в марте 2012-го и указана Майкрософту. Ответ на баг был таким:

>We have confirmed that this is a bug in our compiler and it has been fixed.

т.е. по-русски это так:

> Мы подтвердили, что это является ошибкой нашего компилятора и зафиксировали это.

Смотрим на статус заявки: Closed as Deferred, т.е. Закрыта как Отсроченная. Т.о. получается, что о проблеме знают, но её решение отложено в долгий ящик.

А теперь, подробней о самой проблеме...

Вариант первый:
/*
MS Visual Studio 2012 compiler bug...
*/
#include <cstdio>

namespace Myspace{
    struct Foo{
        static void Test(){
            void Hi(); // declaration
            Hi(); // calling
        }
    };

    static void Test(){
        void Hi(); // declaration
        Hi(); // calling
    }
}

namespace Myspace{
    void Hi(){
        printf("Myspace::Hi()\n");
    }
}

void Hi(){
    printf("::Hi()\n");
}

int main(void){
    Myspace::Foo::Test(); // Myspace::Hi() expected.
    Myspace::Test(); // Myspace::Hi() expected.
    getchar();
}

/*
Expected output result:
       Myspace::Hi()
       Myspace::Hi()
      
Actual output result:
       ::Hi()
       ::Hi()

*/

Как видим, по факту происходит вызов не той функции, которую мы ожидали. Если объявления пометить как extern, то результат отчасти изменится...

Вариант второй:
/*
MS Visual Studio 2012 compiler bug...
*/
#include <cstdio>

namespace Myspace{
    struct Foo{
        static void Test(){
            extern void Hi(); // declaration
            Hi(); // calling
        }
    };

    static void Test(){
        extern void Hi(); // declaration
        Hi(); // calling
    }
}

namespace Myspace{
    void Hi(){
        printf("Myspace::Hi()\n");
    }
}

void Hi(){
    printf("::Hi()\n");
}

int main(void){
    Myspace::Foo::Test(); // Myspace::Hi() expected.
    Myspace::Test(); // Myspace::Hi() expected.
    getchar();
}

/*
Expected output result:
       Myspace::Hi()
       Myspace::Hi()
      
Actual output result:
       ::Hi()
       Myspace::Hi()

*/

Однако, как видим, в первом случае по прежнему происходит вызов функции из глобального пространства имён.

Для того, чтобы код правильно компилировался в MS Visual Studio 2012, объявление функции придётся разместить в её пространстве имён.

/*
MS Visual Studio 2012 compiler bug...
*/
#include <cstdio>

namespace Myspace{ 
       void Hi(); // declaration
    struct Foo{           
        static void Test(){           
            Hi(); // calling
        }
    };

    static void Test(){       
        Hi(); // calling
    }
}

namespace Myspace{
    void Hi(){
        printf("Myspace::Hi()\n");
    }
}

void Hi(){
    printf("::Hi()\n");
}

int main(void){
    Myspace::Foo::Test(); // Myspace::Hi() expected.
    Myspace::Test(); // Myspace::Hi() expected.
    getchar();
}

/*
Expected output result:
       Myspace::Hi()
       Myspace::Hi()
      
Actual output result:
       Myspace::Hi()
       Myspace::Hi()

*/

Ещё раз обращаю внимание на то, что указанный баг специфичен для MS Visual Studio 2012 (хотя может и не только для указанной версии).





Комментариев нет: