このページは福井県立大学の田中求之が2006年1月まで運用していた Mac のサーバ運用に関する会議室 「Web Scripter's Meeting」の記録です。情報が古くなっている可能性がありますのでご注意ください。

Tanaka's OSAXのsetClipTextがこけます

発言者:モリヤ
( Date Wednesday, November 05, 1997 23:23:15 )


 サーバーの話とはまったく関係ないのですが,解決策がわからないの
で教えてくださいませんでしょうか。
 最近書いた,以下のスクリプトを実行させると,頻繁にシステムエ
ラーが起きて,MacsBugに落ちてしまいます。スクリプトの内容はクリッ
プボード内のテキストデータのうち,行頭に">"のついていない行を,飯
森さんのWrapText OSAXを用いてワードラップするというものです。(稚
拙なコードで恐縮ですが‥‥)

on run
    set cur_data to (getClipText) as string
    set init_lines to (count paragraph of cur_data)
    repeat with i from 1 to init_lines
        set tg to paragraph (init_lines - (i - 1)) of cur_data
        if ((count character of tg) ュ 0) then
            if ((character 1 of tg) ュ ">") then
                set new_lines to (WrapText tg width 64 scriptCode 1 with onlyLongLines)
                set cur_data to (xReplace cur_data search tg replace new_lines)
            end if
        end if
    end repeat
    setClipText (cur_data as string)
end run

システムエラーが起こったときのMacsBugのエラーメッセージは,以下の
ようなものです。

Bus Error at 003EF5A8 setclipt+00084
while reading long word from 6E756C6C in Supervisor data space

 最後のsetClipTextの行を外すと,エラーが起きませんし,スクリプト
編集プログラムでcur_dataの内容を表示させても,特に変なところは見
当たりません。なにより,AppleScriptのエラーにならずに,バスエラー
が起こってしまっているのが謎です。
 また,WrapTextを用いていない別のスクリプトでは,setClipTextがこ
けるコトはありませんので,なにか,WrapTextと相性が悪いのではない
かとか想像しています。

 私のところの環境は,以下の通りです。
Power Macintosh 8500/120  RAM 80MB  HD 2GB
使用OS: MacOS 8(J) --(AppleScriptはこれに付属のものです)
使用OSAX: Tanaka's OSAX 1.1,WrapText.PPC 1.1
その他: MacsBug 5.6.4a3c1

 実はスクリプト上のミスなんでしょうが,わからなくて困っていま
す。いつも質問ばかりで恐縮ですが,よろしくお願いします。

田中求之 さんからのコメント
( Thursday, November 06, 1997 01:29:01 )

たぶん、Tanaka's osax が問題なんだと思います。ただ、開発に使える PowerMac 
を持ってませんし、OS 8 もインストールしていない状態なので、どこまで対処できる
かわかりませんが、調べてみます。

Bus Error を出すような操作はしてないつもりなんだけどな?? (^_^;;


田中求之 さんからのコメント
( Thursday, November 06, 1997 01:30:02 )

あ、念のため 1.2b7 に取り換えてみて試してもらえますか?


Hideaki Iimori さんからのコメント
( Thursday, November 06, 1997 07:54:21 )

 MacsBugで追ってみましたが、xReplaceが 0番地以降を壊して

います。

 Tanaka's osax 1.2b2の setClipTextは壊した 0番地のゴミを 

pointerとして使い memoryの存在しない空間を見てコケます。

Ver1.2b7の setClipTextは大丈夫なようです。


 xReplaceの(というか Tanaka's osax全体に言えることです

が)AEGetParamDesc()で最後の result AEDesc addressに誤っ

て 0を渡していて 0番地以降 8 byteを壊しています。


 MacsBugで

  ebbe on

としてから osaxを実行してみてください。0番地への不正アク

セスが検知されるはずです。


 また AEDescは、

  AEDesc  result = {'null',0};

  err = AEGetParamDesc(...,&result);

     :

     :

  if (result.dataHandle)  AEDisposeDesc(&result);

の様に null descriptorに初期化し、何があっても最後に必ず 

disposeするのが正しい使い方です。AEDescの扱いでバグってい

て徐々に memoryを食いつぶしてコケるソフトが沢山あります。


田中求之 さんからのコメント
( Thursday, November 06, 1997 10:38:55 )

飯森さん、わざわざデバッグしていただいてありがとうございます。

setClipText の方は、私でもミスに気が付いたのですが、

> xReplaceの(というか Tanaka's osax全体に言えることです
>が)AEGetParamDesc()で最後の result AEDesc addressに誤っ
>て 0を渡していて 0番地以降 8 byteを壊しています。

の部分については、まったく気が付いてませんでした。なんでこうなるんだろ?
という原因を追ってみます。

デスクリプタについては、「何があっても Dispose 」というはちゃんとやって
ますので、Dispose のミスはないと思いたいのですが、初期化は CompileIt!
まかせ( HyperTalk は宣言なしに変数が使える言語ですんで)の部分があり
ますので、どこまで対処できるか、ちょっと不安だったりもします。

MacsBug の使い方ももう一度確認しておこう (^_^;;


モリヤ さんからのコメント
( Friday, November 07, 1997 17:16:31 )

 田中さん,飯森さん,コメントどうもありがとうございます。返事が
遅くなってしまってすみません。
 とりあえず,Tanaka's OSAXを1.2b7に変えたところ,動くようになり
ました。最新版を試しもせずに質問してしまって申しわけありませんで
した。
 飯森さんと田中さんのやり取りは,ちんぷんかんぷんでしたが(シス
テムにMacsBugを入れているとは言っても,入れているだけの身なの
で),おいおい理解できるよう勉強したいと思います。とりあえず,
WrapText OSAXは,今回の問題には直接には関係ないということなんだと
理解しました。にも関らず,飯森さんには,問題考察にご参加くださっ
て,どうもありがとうございました。あらぬ嫌疑をおかけしてしまって
すみませんでした。

 有用なプログラムを世に出してくださっているおふた方の努力に感謝
いたします。どうもありがとうございます。また,これからもよろしく
お願いします。

田中求之 さんからのコメント
( Tuesday, November 11, 1997 01:59:55 )

モリヤさん、とりあえず動いてよかったです。

で、飯森さんに指摘された問題点を究明しようとしているのですが、

> MacsBugで
>  ebbe on
>としてから osaxを実行してみてください。

ebbe on って、MacsBug のコマンドですか? 何か dcmd を追加する必要が
あるのでしょうか? 私の MacsBug では ebbe だと、EBBE 番地のメモリー
の内容を表示するだけなのですが??


モリヤ さんからのコメント
( Tuesday, November 11, 1997 18:05:50 )

私のところでは,dcmdの追加とかは行なっていませんが,MacsBugに入って
   ebbe on
とタイプすると,
   EBBE is now ON
と表示されて,それ以降の実行ではトラップが働いて
   User break at 04E32356
   The EBBE dcmd has detected that location $0000 has been overwritten
とか表示されるようになりますけれど‥‥。

田中求之 さんからのコメント
( Tuesday, November 11, 1997 19:04:14 )

>  ebbe on
>とタイプすると,
>   EBBE is now ON
>と表示されて,それ以降の実行ではトラップが働いて
>   User break at 04E32356
>   The EBBE dcmd has detected that location $0000 has been overwritten
>とか表示されるようになりますけれど‥‥。

モリヤさん、情報ありがとうございます。どうやら私の MacsBug の Preference に
dcmd が入っていないようですね。Developer-CD から探してきて入れます。

それと、モリヤさんの表示例のように、しっかり $0000 を書き換えているわけですね (^_^;;
解決できるのではないかと思うコードの書き方を思い付いてますので、EBBE dcmd を
インストールしてテストしてます。

Hideaki Iimori さんからのコメント
( Wednesday, November 12, 1997 02:09:19 )

》ebbe on って、MacsBug のコマンドですか? 何か dcmd を追加
》する必要があるのでしょうか? 私の MacsBug では ebbe だ
》と、EBBE 番地のメモリーの内容を表示するだけなのですが??

EBBE [ON | OFF]  (EvenBetterBusError dcmd)                 v1.0b2
   EBBE detects inadvertent use of NIL handles (or pointers) and
   jumps to $0000 as a place to execute code.
   by Jim Luther. Based on Greg Marriott's EvenBetterBusError INIT.

 最新の MacsBugには含まれています。
 <http://devworld.apple.com/MacOS8/index.html>
から落せます。

 EBBEは 0番地の内容を誤って pointerとして使った場合は即座に 
Bus Errorを発生させますので Machine Instructionを特定できま
す。不正書込み検知は 1/60秒 Timer監視ですので精度は落ちます
が、不正書込みを起こしている動作の見当は付きます。

》pascal function SjisToEuc:I theAEEvent:R, theReply:R, handerRefCon:L  
》
》put AEGetParamDesc(theAEEvent@,keyDirectObject,typeChar,theParamDesc@) 
》into err

 この部分が Cで書けば
  AEDesc  *theParamDesc = 0;    // たまたま 0に初期化されている
  err = AEGetParamDesc(...,theParamDesc);
に相当する Codeとなっています。

Hideaki Iimori さんからのコメント
( Wednesday, November 12, 1997 02:12:19 )

》ebbe on って、MacsBug のコマンドですか? 何か dcmd を追加
》する必要があるのでしょうか? 私の MacsBug では ebbe だ
》と、EBBE 番地のメモリーの内容を表示するだけなのですが??

EBBE [ON | OFF]  (EvenBetterBusError dcmd)                 v1.0b2
   EBBE detects inadvertent use of NIL handles (or pointers) and
   jumps to $0000 as a place to execute code.
   by Jim Luther. Based on Greg Marriott's EvenBetterBusError INIT.

 最新の MacsBugには含まれています。
 <http://devworld.apple.com/MacOS8/index.html>
から落せます。

 EBBEは 0番地の内容を誤って pointerとして使った場合は即座に 
Bus Errorを発生させますので Machine Instructionを特定できま
す。不正書込み検知は 1/60秒 Timer監視ですので精度は落ちます
が、不正書込みを起こしている動作の見当は付きます。

》pascal function SjisToEuc:I theAEEvent:R, theReply:R, handerRefCon:L  
》
》put AEGetParamDesc(theAEEvent@,keyDirectObject,typeChar,theParamDesc@) 
》into err

 この部分が Cで書けば
  AEDesc  *theParamDesc = 0;    // たまたま 0に初期化されている
  err = AEGetParamDesc(...,theParamDesc);
に相当する Codeとなっています。

田中求之 さんからのコメント
( Wednesday, November 12, 1997 10:56:13 )

飯森さん、わざわざ丁寧にありがとうございます。

> この部分が Cで書けば
>  AEDesc  *theParamDesc = 0;    // たまたま 0に初期化されている
>  err = AEGetParamDesc(...,theParamDesc);
>に相当する Codeとなっています。

ここですよね、問題は。


>EvenBetterBusError dcmd

あ、こいつだったのか! ってことで分かりました。デバッグしてみます。

田中求之 さんからのコメント
( Thursday, November 13, 1997 00:04:02 )

>デバッグしてみます。

あ〜〜、落ちる落ちる (@_@)


田中求之 さんからのコメント
( Thursday, November 13, 1997 22:38:27 )

とりあえず、

put NewPtr(8) into theParamDesc
put AEGetParamDesc(theAEEvent@,keyDirectObject,typeChar,theParamDesc@) into err

というように、NewPtr() でちゃんと Pointer を確保してから AEGetParamDesc() を
呼ぶようにしました。これで EBBE にひっかかることはなくなりました。やれやれ。

今となってみれば、当たり前というか、こうすべきなのはわかりますが、やっぱこういう
時に、宣言(初期化)無しで変数を使う HyperTalk っていうのは、落とし穴もある
ことを痛感させられます。

で、確認なのですが(ほとんど飯森さんへの私信ですが (^_^;; )

使用後は

put AEDisposeDesc(theParamDesc@) into err

によってtheParamDesc デスクリプタによって指示されているデータのメモリーが
破棄されるわけですから、これとは別に

DisposPtr theParamDesc

によって、デスクリプタのメモリーも破棄する、ということでいいんですよね?
(このようにソースを書きましたが)

Hideaki Iimori さんからのコメント
( Friday, November 14, 1997 07:51:56 )

》put NewPtr(8) into theParamDesc

 NewPtrClear()で確保するか、初期化して Descriptorを 0 clearして
おいた方が AEDisposeDesc時に安全です。
 本当は NewPtr()の成否も判断すべきですが、8 byteも確保できなけ
ればどこか他の所で落ちるでしょう。

》使用後は
》
》put AEDisposeDesc(theParamDesc@) into err
》
》によってtheParamDesc デスクリプタによって指示されているデータ
》のメモリーが破棄されるわけですから、これとは別に
》
》DisposPtr theParamDesc
》
》によって、デスクリプタのメモリーも破棄する、ということでいいん
》ですよね?(このようにソースを書きましたが)

 OKです。

 Compile It!の書式が良く解らないのですが、数 10 byte程度の小さ
な memoryに一々 New...() / Dispose...()を使うのは面倒ですし遅く
なりますので、Local変数で作業領域を取る書き方があればそちらを使
う方が良いでしょう。

田中求之 さんからのコメント
( Friday, November 14, 1997 11:48:06 )

>NewPtrClear()で確保するか、初期化して Descriptorを 0 clearして
>おいた方が AEDisposeDesc時に安全です。

なるほど、確かにそうですね。NewPtrClear() を使うようにします。

色々とありがとうございました。おかげさまで、AEDescriptor の扱い方が
クリアーになって、かねての懸案だった、リストの中にリストを入れる方法や、
AECoerceDesc で型変換を行わせる、といったことが、やっとできるように
なりました。

いずれも、すべての Desc が初期化の段階で 0 番地に確保されていたことが
原因で、失敗していたのでした (^_^;;

ふ、ふ、ふ、これでまた新しいものが作れるぜ…