Gauche:Bugs:log15

Gauche:Bugs:log15

Gauche 0.9.2以前のバグ


rfc.uriのuri-mergeで結果の正しくない?結合パターンがある(52712ab)

(2011/08/02 05:54:22 PDT)

gosh> (uri-merge "http://aaa.bbb" "xxx.yyy")
"http://aaa.bbbxxx.yyy"

これは

"http://aaa.bbb/xxx.yyy"

となるのが正しいのではないでしょうか。

(use srfi-1 :only (find)) がエラーになる (0.9.2_pre2)

teppey(2011/08/01 08:03:54 PDT): srfi-1モジュールからコアに移ったいくつかの手続きをインポートオプションに指定するとエラーになります。これらの手続きをsrfi-1でもエクスポートするのはどうでしょうか。

diff --git a/libsrc/srfi-1.scm b/libsrc/srfi-1.scm
index f436d82..f0f958a 100644
--- a/libsrc/srfi-1.scm
+++ b/libsrc/srfi-1.scm
@@ -17,19 +17,19 @@
 
 (define-module srfi-1
   (export xcons cons* list-tabulate circular-list iota
-          not-pair?
+          not-pair? null-list?
           list=
           first second third fourth fifth sixth seventh eighth
           ninth tenth car+cdr take drop take-right drop-right
-          take! drop-right! split-at! last
+          take! drop-right! split-at split-at! last
           concatenate concatenate!
           append-reverse append-reverse!
           zip unzip1 unzip2 unzip3 unzip4 unzip5
-          count unfold pair-fold reduce unfold-right
+          count fold unfold pair-fold reduce fold-right unfold-right
           pair-fold-right reduce-right append-map append-map!
           map! pair-for-each filter-map map-in-order
           filter partition remove filter! partition! remove!
-          member find-tail list-index
+          member find find-tail any every list-index
           take-while drop-while take-while! span break span! break!
           delete delete-duplicates delete! delete-duplicates!
           assoc alist-cons alist-copy alist-delete alist-delete!
@@ -44,6 +44,12 @@
 
 (define-inline (not-pair? x) (not (pair? x)))
 
+(define-macro (from-core . xs)
+  `(begin
+     ,@(map (^x `(define ,x (global-variable-ref (find-module 'gauche) ',x)))
+            xs)))
+(from-core null-list? any every fold fold-right find split-at)
+
 
 ;;;
 ;;; List generators of SRFI-1
diff --git a/test/dict.scm b/test/dict.scm
index 08dd21d..285de7a 100644
--- a/test/dict.scm
+++ b/test/dict.scm
@@ -37,7 +37,6 @@
 (test-basics (make-bimap (make-hash-table 'eq?) (make-hash-table 'eqv?)))
 
 (use gauche.collection)
-(use srfi-1)
 
 (let1 bm (make-bimap (make-hash-table 'eq?) (make-hash-table 'eqv?))
   (bimap-put! bm 'a 1)

format の ~* で最後の引き数を飛ばせない(9379ba5)

leque(2011/07/16 20:41:13 PDT):

gosh> (format "~*" 1)
*** ERROR: '~*' format directive refers outside of argument list in "~*"

SLIB や CL の動作を見るとエラーになってほしくない気がします。

gosh> (use slib)
gosh> (require 'format)
gosh> (format "~*" 1)
""
% sbcl
...
*  (format nil "~*" 1)

""

こんな感じでしょうか。

diff --git a/src/write.c b/src/write.c
index 8e443cc..0f1b25b 100644
--- a/src/write.c
+++ b/src/write.c
@@ -875,7 +875,7 @@ static void format_proc(ScmPort *out, ScmString *fmt, ScmObj args, int sharedp)
                     } else {
                         backtracked = TRUE;
                     }
-                    if (argindex < 0 || argindex >= arglen) {
+                    if (argindex < 0 || argindex > arglen) {
                         Scm_Error("'~*' format directive refers outside of argument list in %S", fmt);
                     }
                     argcnt = argindex;

named letでコンパイルエラー(9ac2d87)

teppey(2011/07/01 20:04:54 PDT): 以下のコードがコンパイルエラーになります(-fno-inline-localsか-fno-lambda-lifting-passオプションを与えると発生しません)。

$ cat /tmp/x.scm
(let loop ()
  (values (lambda () #f))
  (loop))
$ ./gosh -ftest /tmp/x.scm
gosh: "error": Compile Error: vector-ref index out of range: 6
"/tmp/x.scm":1:(let loop () (values (lambda () #f)) ... 

compile.scmのpass4/scanでトップレベルのlambda nodeにマークが付けられますが、$lambda-flagがdissolvedだった場合このノードは

  1. pass4/liftに渡されないのでマークされたまま($lambda-lifted-varが#t)
  2. pass4/substの$LAMBDAの節で($gref #t)が返される

となるように思いました。場当たり的ですが、パッチです。

diff --git a/src/compile.scm b/src/compile.scm
index a9bf482..ed3b0b3 100644
--- a/src/compile.scm
+++ b/src/compile.scm
@@ -4031,7 +4031,8 @@
                ;; We just mark it by setting lifted-var to #t so that
                ;; pass4/lift phase can treat it specially.
                (if t?
-                 ($lambda-lifted-var-set! iform #t) ;mark this is toplevel
+                 (unless (eq? ($lambda-flag iform) 'dissolved)
+                   ($lambda-lifted-var-set! iform #t)) ;mark this is toplevel
                  (begin
                    ($lambda-free-lvars-set! iform inner-fs)
                    (let loop ([inner-fs inner-fs] [fs fs])

port-buffering が :modest :none で read-block が停止する場合

ryoakg(2011/06/27 01:43:00 PDT): 例えば

(receive (in out) (sys-pipe)
  ;; :modest かどうか一応確認
  (display #`"buffering in : ,(port-buffering in)\n" (standard-error-port))
  (display #`"buffering out: ,(port-buffering out)\n" (standard-error-port))

  (display "a" out)
  (flush out)

  ;; (set! (port-buffering in) :none) ; こっちでも同じ

  ;; a が読める
  (let1 d (read-block 64 in)
    (format (standard-error-port) "~s~%" d))

  ;; ココで止まる
  (let1 d (read-block 64 in)
    (format (standard-error-port) "~s~%" d))
  )

とすると、2回目の read-block で止まります。読む側に何もない状態だと起る様です。(read-block! も同様でした。socket も同様の様です。元々 socket でやっていましたが、それをココに書くのは面倒なので pipe にしています)

read-block の説明 http://practical-scheme.net/gauche/man/gauche-refj_58.html#index-read_002dblock を見ると、特にその様な事は書いていないので必ずすぐ return する様に思えますが、read-block! の http://practical-scheme.net/gauche/man/gauche-refj_101.html#index-read_002dblock_0021 では「vecを埋める前に戻ることがあります」と、「そういう場合もある」という表現になっています。英語だと「read-block! may return before ...」でした。

C言語で同じ様な事(だと私が勝手に思っている事)

#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(void) {
  int pipefd[2];
  char i,o;
  int s;

  if (pipe(pipefd) == -1) {
    perror("pipe");
    return 1;
  }

  fcntl(pipefd[0], F_SETFL, O_NONBLOCK | fcntl(pipefd[0], F_GETFL, 0));

  i = 'a';
  write(pipefd[1], &i, 1);

  s = read(pipefd[0], &o, 1);
  printf("s:%d, o:%c\n", s, o);

  s = read(pipefd[0], &o, 1);   /* fcntl やらないとココで止まる */
  if (s <= 0) {
    int err = errno;
    puts(strerror(err));
    printf("EWOULDBLOCK?:%d, EAGAIN?:%d\n", err == EWOULDBLOCK, err == EAGAIN);
  }
  printf("s:%d, o:%c\n", s, o);

  return 0;
}

をすると、読む側に何も届いていなくてもとりあえず read は戻ります。

これと考えを揃えるなら

現状停止したくなければ、byte-ready? などを使えば良い様子でしたが、複数スレッドがある期間同じ port を読む様なプログラムがうまく動く事を望む場合は、うまくいかない場合が出る気もしました。

construct-json に空リストを渡すとエラーになる

leque(2011/06/26 21:19:18 PDT): 空のオブジェクトを読み込んで書き出そうとした場合にエラーになります。

> (parse-json-string "{}")
()
> (construct-json (parse-json-string "{}"))
*** JSON-CONSTRUCT-ERROR: construct-json expects a list or a vector, but got ()
> (construct-json (parse-json-string "{\"a\": {}}"))
*** JSON-CONSTRUCT-ERROR: construct-json expects list or vector, but got: ()
Stack Trace:
_______________________________________
  0  (print-value (cdr attr))
        At line 176 of "/usr/local/share/gauche-0.9/0.9.1/lib/rfc/json.scm"
  1  (fold (lambda (attr comma) (unless (and (pair? attr) (string? (car ...
        At line 167 of "/usr/local/share/gauche-0.9/0.9.1/lib/rfc/json.scm"
diff --git a/lib/rfc/json.scm b/lib/rfc/json.scm
index 7909a18..f05434e 100644
--- a/lib/rfc/json.scm
+++ b/lib/rfc/json.scm
@@ -155,7 +155,7 @@
   (cond [(eq? obj 'false) (display "false")]
         [(eq? obj 'null)  (display "null")]
         [(eq? obj 'true)  (display "true")]
-        [(pair? obj)      (print-object obj)]
+        [(list? obj)      (print-object obj)]
         [(vector? obj)    (print-array obj)]
         [(number? obj)    (print-number obj)]
         [(string? obj)    (print-string obj)]
@@ -206,7 +206,7 @@
 (define (construct-json x :optional (oport (current-output-port)))
   (with-output-to-port oport
     (^()
-      (cond [(pair? x)   (print-object x)]
+      (cond [(list? x)   (print-object x)]
             [(vector? x) (print-array x)]
             [else (error <json-construct-error> :object x
                          "construct-json expects a list or a vector, ¥

リファレンスの sys-getaddrinfo の説明

ryoakg(2011/06/26 01:49:33 PDT): 英語は自信ないですが以下じゃないかと思います

 http://practical-scheme.net/gauche/man/gauche-refj_87.html#index-sys_002dgetaddrinfo
 誤: ... <sys-addrinfo> のインスタンスを返します。
 正: ... <sys-addrinfo> のインスタンスのリストを返します。

http://practical-scheme.net/gauche/man/gauche-refe_87.html#index-sys_002dgetaddrinfo

 誤: Returns <sys-addrinfo> instance ...
 正: Returns a list of <sys-addrinfo> instance ...

assert-curr-charのエラーメッセージ(89202df)

teppey(2011/06/16 07:45:50 PDT): 読み込んだ文字がエラーメッセージに含まれていませんでした。

diff --git a/lib/text/parse.scm b/lib/text/parse.scm
index ee1a08e..f611276 100644
--- a/lib/text/parse.scm
+++ b/lib/text/parse.scm
@@ -169,8 +169,8 @@
   (define pred (char-list-predicate char-list))
   (rlet1 c (read-char port)
     (unless (pred char-list c)
-      (errorf "~awrong character c ~a. ~s expected."
-              (ppp port) string char-list))))
+      (errorf "~awrong character ~s ~a. ~s expected."
+              (ppp port) c string char-list))))
 
 (define-compiler-macro assert-curr-char (er-transformer prefold-macro-1))

メタクラスを指定したクラスをchange-classするとSEGV(43634d4)

teppey(2011/05/29 17:56:03 PDT): メタクラスがどういうものかよく分かっていないのですが、以下のスクリプトがsegmentation faultになりました。

$ uname -srm
Linux 2.6.32-5-amd64 x86_64
$ ./gosh -V
Gauche scheme shell, version 0.9.1 [utf-8,pthreads], x86_64-unknown-linux-gnu
$ cat /tmp/x.scm
(define-class <c-meta> (<class>) ())
(define-class <c> () () :metaclass <c-meta>)
(define c (make <c>))
(change-class <c> <c-meta>)
(write c)
$ ./gosh -ftest /tmp/x.scm
zsh: segmentation fault  ./gosh -ftest /tmp/x.scm

gdbのバックトレースです。

$ gdb --quiet --args ./gosh -ftest /tmp/x.scm
Reading symbols from /home/teppey/src/Gauche-trunk/src/gosh...done.
(gdb) run
Starting program: /home/teppey/src/Gauche-trunk/src/gosh -ftest /tmp/x.scm
[Thread debugging using libthread_db enabled]

Program received signal SIGSEGV, Segmentation fault.
Scm_SubtypeP (sub=0x71ac00, type=0x7ffff7c5a860) at class.c:850
850         while (*p) {
(gdb) bt
#0  Scm_SubtypeP (sub=0x71ac00, type=0x7ffff7c5a860) at class.c:850
#1  0x00007ffff795bba3 in Scm_ComputeApplicableMethods (gf=<value optimized out>, 
    argv=<value optimized out>, argc=2, applyargs=0) at class.c:2076
#2  0x00007ffff793cfcf in run_loop () at ./vmcall.c:250
#3  0x00007ffff7951e85 in user_eval_inner (program=<value optimized out>, 
    codevec=<value optimized out>) at vm.c:1288
#4  0x00007ffff7952c3e in apply_rec (vm=<value optimized out>, 
    proc=<value optimized out>, nargs=<value optimized out>) at vm.c:1384
#5  0x00007ffff7974172 in write_ss_rec (obj=0x7ff3c0, port=0x720e40, 
    ctx=0x7fffffffe0b0) at write.c:554
#6  0x00007ffff7974ae6 in Scm_Write (obj=<value optimized out>, 
    p=<value optimized out>, mode=<value optimized out>) at write.c:153
#7  0x00007ffff79a60d8 in stdlib_write (SCM_FP=<value optimized out>, 
    SCM_ARGCNT=<value optimized out>, data_=<value optimized out>)
    at stdlib.stub:595
#8  0x00007ffff794a6cb in run_loop () at ./vmcall.c:186
#9  0x00007ffff7951e85 in user_eval_inner (program=<value optimized out>, 
    codevec=<value optimized out>) at vm.c:1288
#10 0x00007ffff7952c3e in apply_rec (vm=<value optimized out>, 
    proc=<value optimized out>, nargs=<value optimized out>) at vm.c:1384
#11 0x00007ffff795362f in safe_eval_wrap (kind=2, arg0=0x7ffff7c61d60, 
    args=0x7edf00, cstr=0x0, env=<value optimized out>, result=0x7fffffffe430)
    at vm.c:1531
#12 0x00007ffff799892a in Scm_Load (cpath=<value optimized out>, flags=0, 
    packet=0x7fffffffe760) at load.c:481
#13 0x0000000000402ac3 in main (argc=3, argv=<value optimized out>) at main.c:508
(gdb) 

create-directory-treeのspecに文字列・シンボルを指定するとエラー

teppey (2011/04/04 08:34:44 PDT): GaucheRefj:create-directory-treeによると、spec引数には文字列やシンボルを指定できますが、エラーになります。

gosh> (use file.util)
#<undef>
gosh> (create-directory-tree "/tmp" "foo")
*** ERROR: wrong number of arguments for #<closure ensure-file> (required 2, got 1)

do-fileへの引数が足りないようでした。

diff --git a/libsrc/file/util.scm b/libsrc/file/util.scm
index 516433e..10e0188 100644
--- a/libsrc/file/util.scm
+++ b/libsrc/file/util.scm
@@ -313,7 +313,7 @@
                    [else sys-chown]))
     (define (walk dir node do-file do-dir)
       (match node
-        [[? name?] (do-file (mkpath dir node))]
+        [[? name?] (do-file (mkpath dir node) #f)]
         [([? name? n] . args)
          (receive (opts content) (collect-options args)
            (if (list? content)

vmの命令と対応する関数をdefineで上書きしても、vmの命令としてコンパイルされる

ryoakg2011/01/14 06:38:52 PST

(define-module mod
  (export foo)
  (define (+ a b) 4)
  (define (foo a b)
    (+ a b))
  )
(import mod)
(disasm foo)

を、ファイルに書いて実行すると

% gosh d.scm
CLOSURE #<closure foo>
main_code (name=foo, code=0x83edbe0, size=3, const=0, stack=0):
args: #f
     0 LREF1                    ; a
     1 LREF-VAL0-NUMADD2(0,0)   ; (+ a b)
     2 RET 

となって、自分で定義した + でなくて vm の命令の方にコンパイルされてしまいます。(実のところ試したのは、+ と * だけで、ハッキリと vmの... とハッキリ言えないのですが、多分そうじゃないかなぁと思います)

また

(define (+ a b) 4)
(define (foo a b)
  (+ a b))
(disasm foo)

(define-module mod
  (export foo)
  )
(select-module mod)
(define (* a b) 4)
(define (foo a b)
  (* a b))

(select-module user)
(import mod)
(disasm foo)

の様に、define-module の外に書いた場合は、問題ない様子でした。

HTTPレスポンスヘッダにContent-Lengthが無い場合、バイナリデータを受け取れない(0.9.1)

2011/01/11 22:35:52 PST

rfc.httpモジュールのhttp-getでバイナリファイルを取りよせたときに レスポンスヘッダにContent-Length行が含まれていなかった場合、 sinkオプションを使ってもレスポンスボディの内容を得ることができません。

receive-body関数内でport->stringを呼んでいるのが原因のようで、 ソースのコメントを読むと過渡的にこのような処理になっているのかもしれないですが 報告しておきます。

マニュアル typo Adler32

ryoakg2011/01/07 05:35:09 PST http://practical-scheme.net/gauche/man/gauche-refj_153.html http://practical-scheme.net/gauche/man/gauche-refe_153.html

Function: alder32 string :optional checksum

alder32 になっている

parameterizeを抜ける際にconvert procedureが呼ばれてしまう

Shiro (2011/01/06 04:28:10 PST): Joo ChurlSooによりレポートされたもの。

gosh> (define a (make-parameter 1))
a
gosh> (define b (make-parameter 2 number->string))
b
gosh> (list (a) (b))
(1 "2")
gosh> (parameterize ((a 10) (b 20)) (list (a) (b))
)
*** ERROR: number required: "2"
Stack Trace:
_______________________________________
  0  after

gosh> (list (a) (b))
(1 "20")

現在のGaucheのparameterizeの実装はdynamic-windのbefore/after thunkで パラメータの値を書き換える、つまりこんな感じで展開されてるんだが:

(let ([a_prev #f]
      [b_prev #f])
  (dynamic-wind
    (lambda () (set! a_prev (a 10)) (set! b_prev (b 20)))
    (lambda () (list (a) (b)))
    (lambda () (a a_prev) (b b_prev))))

after thunkの(b b_prev)のところでconverterが起動されちゃうのがまずい。 parameterizeの動作は動的環境の変更だから、抜けるところで完全に元に戻らないと ならないはず。

binary.pack の unpack で #<eof> が入ったり入らなかったりする

ryoakg2011/01/06 02:29:05 PST: 以下実行例です

(use srfi-1)
(use binary.pack)
(map (.$ (cute unpack "V*" :from-string <>)
         (cute string <> #\x00 #\x00 #\x00)
         integer->char)
     (iota 16 0 16))
=> ((0) (16) (32) (48) (64) (80) (96) (112) (32962 #<eof>) (37058 #<eof>) (41154 #<eof>) (45250 #<eof>) (32963 #<eof>) (37059 #<eof>) (41155 #<eof>) (45251 #<eof>))

途中から #<eof> が入ります。結果が不安定なので多分バグだと思うのですが

元々は

(use gauche.uvector)
(use gauche.experimental.app)
($ unpack "V*" :from-string $ u8vector->string $
   list->u8vector '(#x01 #x01 #x01 #x01 ; 不完全文字列
                    #x01 #x01 #x01 #x01
                    #xd0 #x00 #x00 #x00
                    #x01 #x01 #x01 #x01
                    #x01 #x01 #x01 #x01))
=> (16843009 16843009)

の様にもう少し長い string を unpack させようとしていたのですが、これだとなぜか "V" 2つ分しか unpack してくれなく、もうすこし自分で調べると、#<eof> が途中で入る場合にこの現象が起っている様に見えました。 "V!*" にしても同じでした。

% gosh -V
Gauche scheme shell, version 0.9.1 [utf-8,pthreads], i686-pc-linux-gnu

です。

Windows7上でMinGW版gauche-install.exeが実行できない

koguro(2010/12/31 20:59:44 PST): Windows7上で、MinGWのshellからgauche-install.exeを実行すると以下のエラーが発生します。

$ /c/Program\ Files/Gauche/bin/gauche-install.exe
sh: /c/Program Files/Gauche/bin/gauche-install.exe: Bad file number

http://msdn.microsoft.com/ja-jp/windows/dd883236 で書かれているように、ファイル名にinstallという名前が付いていることから実行時に権限昇格が必要となるようで、正しく動作させるには以下のgauche-install.exe.manifestをgauche-install.exeと同じフォルダに置く必要があります。(MinGWのpatch.exeやinstall.exeも同じようなmanifestファイルを持っています)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <v3:trustInfo xmlns:v3="urn:schemas-microsoft-com:asm.v3">
    <v3:security>
      <v3:requestedPrivileges>
        <v3:requestedExecutionLevel level="asInvoker" />
      </v3:requestedPrivileges>
    </v3:security>
  </v3:trustInfo>
</assembly>

なお、上記URLにも書いてありますが、一度実行すると内部でキャッシュされてしまうみたいで、私の環境ではエラー発生後manifestファイルを置いてもエラーは解消されませんでした。ただ、他のフォルダにgauche-install.exeとgauche-install.exe.manifestをコピーしてみたところ、正常に実行できました。

gauche.partcontのマニュアルの日本語訳が中途半端 (0.9.1)

Shiro(2010/12/13 09:31:30 PST): パラグラフの途中まで訳したところで うっかりコミットしてそのまま忘れていたようです。完全なパラグラフは次のとおりです。

註: 部分継続はふたつのオペレータ、@code{reset}と@code{shift}を使います。 これらは元の論文で導入された名前ですが、既に用語として定着した感があります。 ライブラリ関数名としては一般的に過ぎる名前なので、よりわかりやすい名前を つけようかとも考えたのですが、部分継続を話題にする際にはこれらの用語が 使われるのが普通なので、最終的にこの名前をキープすることにしました。 プログラム中で他の識別子とぶつかったり紛らわしい場合は、モジュールのimport 時に@code{:prefix}インポート指示子(@ref{Using modules}参照)を 次のように使うと良いでしょう。

More ...