e-mail    Debatní kniha    Mapa stránek    Hlavní  
 perličky 
 

Chyba v Turbo Vision pro C++

F. Kašpárek, M. Minárik

Programový systém Turbo Vision je velmi dobře promyšlený a umožňuje vytvářet poměrně rychle aplikace s kvalitní a komfortní obsluhou. Bohužel se do něho vloudily chyby.
Ti, kteří se seznamovali s Turbo Vision, si jistě zkoušeli přeložit přiložené demonstrační programy. Mnozí si všimli, že v programu TVDEMO je chyba v Helpu. Pokud zkoušeli vytvořit Help pro svou aplikaci, zjistili, že prostě nefunguje. Klávesou se sice nápovědné okno otevře, ale při jeho zavírání se program zhroutí. Následující příspěvek popisuje důvod této chyby a jeho řešení. Upozorňujeme předem, že se týká kódů Turbo Vision, překládaných překladačem BC 3.1. U starších překladačů se chyba možná vůbec neprojevuje, nebo se může projevit jinak. Turbo Vision v Pascalu tuto chybu již z principu jazyka nemá.

Chyba je způsobena voláním nevhodného operátoru new. Turbo Vision totiž, jak se uvádí již v manuálu, předefinovává globální operátor new s prototypem:

  void * new( size_t sz );
Základní knihovna CL.LIB však neobsahuje pouze toto "malé" new, ale také "velké" new s prototypem:
  void * new( unsigned long sz );

A právě zde je zakopaný pes. Při konstrukci Helpu se při sestavování křížových referencí volá konstruktor třídy TCrossRef, který vytváří pole těchto referencí (zdrojový text HELPBASE.CPP, např. řádky 132, 324):

  ushort i;
  ...
  p = new TCrossRef[i];

Protože jde o alokaci pole prvků s konstruktory, překladač vygeneruje volání jisté knihovní funkce, která vyhradí paměť a inicializuje prvky pole. V modelu large tato funkce alokuje paměť pomocí operátoru velké new. Jenže velké new není v knihovně TV.LIB (která se linkuje dříve než CL.LIB) předefinováno, a proto se použije standardní velké new z knihovny CL.LIB. Bohužel operátor delete, který je v Turbo Vision také předefinován -- je jenom jeden -- a tak se objekt, který byl alokován standardním velkým new, dealokuje předefinovaným (ale hlavně modifikovaným) operátorem delete. Tento modifikovaný delete obsahuje vnitřní test, který způsobuje hlášení Assertion failed: ... i zhroucení systému. Detailně je generování a způsob volání operátorů new a delete popsán v knize Rudolfa Pecinovského: Borland C++ -- Co v manuálu nenajdete, která právě vychází ve vydavatelství UNIS.

Napravit tuto chybu lze dvojím způsobem:

  • Oprava zdrojových textů Turbo Vision
  • Do souboru NEW.CPP je nutné přidat další předefinování operátoru new, tentokrát velkého new. Definice těla bude stejná jako u malého new, pouze parametr bude:

  unsigned long (místo size_t).
Dále bude třeba do hlavičkového souboru BUFFERS.H do deklarace třídy class TBufListEntry přidat řádek:
  friend void * operator new( unsigned long );
Potom se musí přeložit celá zdrojová knihovna Turbo Vision.
(Pozn. -- Tato varianta vyžaduje větší znalosti jazyka C++, proto je pouze pro zkušenější. Při té příležitosti by bylo rozumné opravit ještě další chyby a přehlédnutí autorů knihovny Turbo Vision (nejen v operátoru new), ale to by vydalo na samostatný článek a ne na malou perličku.)

Přidání jednoho souboru do TV.LIB
Vytvořit následující soubor:
/*-------------------------------------------------*/ /* filename - new2.cpp */ /*-------------------------------------------------*/ /*-------------------------------------------------*/ /* */ /* Turbo Vision - Version 1.0 */ /* */ /* */ /* Copyright (c) 1993 */ /* by František Kašpárek, Miroslav Minárik */ /* All Rights Reserved. */ /* */ /*-------------------------------------------------*/ // Oprava chyby v TURBO VISION 1.0 // Tento modul přeložit a připojit ke knihovně TV.LIB #if !defined( __ALLOC_H ) #include <Alloc.h> #endif // __ALLOC_H inline void * /*****/ shadow /*****/ ( size_t sz ) { return ::operator new(sz); } void * /*****/ operator new /*****/ ( unsigned long sz ) { return shadow( (size_t)sz ); } /*-------------------------------------------------*/

Tento soubor přeložit řádkovým překladačem:
  BCC -c -P -O1 -ml NEW2.CPP
a přidat ho do knihovny TV.LIB:
  TLINK /0 TV.LIB +NEW2.OBJ

Tím je oprava skončena, dále se již bude linkovat správný operátor new. Tato varianta má sice omezení (nelze alokovat pole objektů větší než 64 KB), ale toto omezení nebude v drtivé většině aplikací na závadu, např. u Helpu to znamená "pouhých" 13 tisíc křížových referencí! Navíc tuto úpravu mohou provést i ti, kteří nevlastní kompletní zdrojový výpis Turbo Vision.

Pozn. -- Na chybu jsme sice narazili při tvorbě Helpu, ale může se projevit i jinde, kdykoli se alokuje pole prvků s konstruktory:

  int i;
  ...
  new Txxx[i];
Všem přejeme krásné Helpy.




Pascal - hlavní
Překladače
Vlastní články
Převzaté články
Věci na stáhnutí
Odkazy k tématu
BP7 buglist
Chyba Run-time 200

BASIC