logo
Contato | Sobre...        
rebarba rebarba

Rodrigo Strauss :: Blog

follow us in feedly

Bug escabroso no Visual C++ 6.0

Como eu já disse antes, o Visual C++ 6.0 é muito velho e tem sérios problemas para compilar o Boost. E como ficar alocando e desalocando memória na mão é coisa de quem não sabe nada de C++ moderno, meu chefe/gerente criou uma classe de smart pointer com contador de referência para usarmos nos nossos projetos (sim, meu gerente programa e muito bem). Ele me passou a classe para colocar em alguns projetos, e depois de apagar todos os operadores de conversão automática (safety first!), eu encontrei um bug muito estranho no código que usava essa classe.

O que eu consegui isolar é que o bug acontece quando existe um operador de atribuição que é um template. O VC6 se perde completamente, e não gera o código que chama o operador, fazendo com que a atribuição não seja feita e que ele compile um código que é inválido. Eu resumi o código ao menor caso de teste possível, e mudei o nome da classe para CStupidPtr. Bom, vamos ao código:

//
// Rode isso no Visual C++ 6.0 e veja o que acontece
//

template<typename T>
class CStupidPtr
{
  T* m_pT;
public: 

  CStupidPtr()
  {
    m_pT = 0;
  }
  
  template< typename TSrc >
  CStupidPtr<T>& operator=(const CStupidPtr<TSrc>& p ) throw()
  {
    //
    // vamos colocar um break point forçado aqui para ver
    // se ele passa
    //
    __asm int 3;

    m_pT = p.m_pT;
    return( *this );
  }

public:

  T* operator->() const throw()
  {
    return m_pT;
  }
};

struct TEST
{
  int d;
};

int main()
{
  CStupidPtr<TEST> p;
    
  //
  // essa linha NÃO É GERADA PELO VC6, 
  // e não compila em uma versão mais nova do VC, pois é inválida
  // rode esse programa no debugger do VC6, passo a passo, e você verá
  // que essa linha é pulada pelo debugger.
  //
  p = new TEST();
  

  //
  // tã!
  //
  p->d = 10;

  return 0;
}

Esse código funcionaria se houvesse uma conversão possível de T* para CStupidPtr, o que parace acontecer quando esse código é compilado. Mas note que não existe nenhum operador ou construtor que faça a conversão. O que acontece é que não há conversão, não acontece nenhum erro durante a compilação (mesmo o código sendo inválido) e o VC6 não gera código para a linha de atribuição. E no final ganhamos um 0xC00000005 (access violation) de presente, já que o operador -> retorna NULL.

Olha que o acontece quando eu compilo esse código no Visual C++ 8:

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

vc6_bug.cpp
vc6_bug.cpp(49) : error C2679: binary '=' : no operator found which takes a 
                  right-hand operand of type 'TEST *' (or there is no acceptable conversion)
        vc6_bug.cpp(35): could be 'CStupidPtr &CStupidPtr::operator =(const CStupidPtr &)'
        with
        [
            T=TEST
        ]
        while trying to match the argument list '(CStupidPtr, TEST *)'
        with
        [
            T=TEST
        ]

Pois é, o VC6 já está bem velhinho...


Em 25/11/2005 03:42, por Rodrigo Strauss


  
 
 
Comentários
Wanderley Caloni Junior | website | e-mail | em 24/11/2005 | #
Lamentável! Pior que a própria existência de uma função que recebe uma referência const mascara o problema de conversão. Nessas horas até um internal compiler error seria bem-vindo. Tudo menos o silêncio. Parece que foi feito um try-catch em volta desse trecho e o catch ficou quietinho...

Interessante que se usarmos a notação direta o erro vem à tona (apesar de diferente do VC mais novo):

p.operator = ( new TEST() );

error C2784: 'class CStupidPtr<struct TEST> &__thiscall CStupidPtr<struct TEST>::operator =(const class CStupidPtr<T> &)' : could not deduce template argument for 'const class CStupidPtr<`template-param
Rodrigo Pinho Pereira de Souza | em 06/12/2005 | #
Estão discutindo na lista do boost, sobre parar o suporte para os compiladores que não suportam C++ 100%.

Em fim, eles querem reduzir o numero de Workarrounds(Gambiarras) dentro do boost.

Alguns argumentos que foi utilizado foram:
- Eu quero ver o boost compilando sem warnings ou erros
- Quero um código mais limpo


A Sugestões foram várias, até uma bem escabrosa:
- Se o desenvolvedor estiver usando um compilador não conformante, ele que faça o workarround. Teve um cara que usa Borland C que não gostou muito da ideia, mas .... acho que isto não vai ser aceito.

Porém, tenho certeza que eles não mais oferecerão suporte ao Visual C 6.0. Ou seja, qualquer erro que dê, quando vc compilar com VC 6.0, não poderá ser submetido como bug. Os test cases serão excluídos, e se vc quiser usar, vc que arrume o boost para se adequar ao boost.


Particularmente, eu até tentei usar o boost com o VC 6, mas é muito ruim vc compilar uma coisa simples, e ver mais de 100 warnings .... Como se sentir seguro que aquele código rodará sem falhas depois ????

Meu sonho, é que um dia a empresa em que trabalhamos decida usar o VC 7.1 ao menos, para que então, possa usar o boost.
Algo a dizer?
Nome:


Site:


E-mail:


Escreva o número vinte e seis:


 Não mostre meu e-mail no site, não serve pra nada mesmo...

Comentário





Os comentários devem ser sobre assuntos relativos ao post, eu provavelmente apagarei comentários totalmente offtopic. Se quiser me enviar uma mensagem, use o formulário de contato. E não esqueça: isso é um site pessoal e eu me reservo o direito de apagar qualquer comentário ofensivo ou inapropriado.
rebarba rebarba
  ::::