関数へのポインターの出力

question:1185077855

あるオープンソースソフトウェアのソースコードを読んでいて、関数へのポインターを出力するコードのバグを見つけた。直そうと思ったんだけど、そういえば標準規格(ISO C)として関数へのポインターを出力する方法がないことに改めて気が付いたので、質問というか問題にしてみた。
自分でもちょっと書いてみたけど、まだ「たまご」の問題が完全ではない。まあ、たぶん今時そんなマシンは存在しないと思う(思いたい!)ので、放っておくかなぁ…。

Mozex 1.9.5 が動かない

WindowsFirefox 2.0.0.4 *1Mozex 1.9.5 が動かないので、調べてみた。
[View Page Source]を選択すると、うんともすんとも言わないだけなのだが、[Edit Textarea]を選択すると、例外が投げられるので、これを手がかりにして問題箇所を絞り込むと、mozexRunProgram() 関数の下記の場所の動作がおかしいようだ。

    scmd=cmd.match(/"(\"|.)*?"(?=\s|$)|(\\\s|\S)+/g);
    for (var i in scmd)
    {
        // If it is apos. delimited
        if (scmd[i].slice(0,1)=='"') // ←ここで例外が投げられる

この for 文がなぜか本来より多く回ってしまい、例外が投げられる。
そこで、下記のように for 文を書き換えてみた。

    scmd=cmd.match(/"(\"|.)*?"(?=\s|$)|(\\\s|\S)+/g);
    for (var i = 0; i < scmd.length; i++) // ←ここ
    {
        // If it is apos. delimited
        if (scmd[i].slice(0,1)=='"')

すると、本来の回数だけ回るようになり、mozexRunProgram() 関数が正常に動くようになった。
元々のコードでも問題ないはず*2だし、FreeBSDFirefox 2.0.0.1 *3では動くので、WindowsFirefox 2.0.0.4 のバグだろうか?

パッチ

--- mozex.js.ORG	2006-08-29 04:26:40.000000000 +0900
+++ mozex.js	2007-06-24 16:17:16.000000000 +0900
@@ -917,8 +917,8 @@
     //
     // Use debugging facility to see what is the result if you are not sure how
     // to use this
-    scmd=cmd.match(/"(\"|.)*?"(?=\s|$)|(\\\s|\S)+/g);
-    for (var i in scmd)
+    var scmd=cmd.match(/"(\"|.)*?"(?=\s|$)|(\\\s|\S)+/g);
+    for (var i = 0; i < scmd.length; i++)
     {
         // If it is apos. delimited
         if (scmd[i].slice(0,1)=='"')

*1:Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4

*2:JavaScript は、ほとんど知らないんだけど…

*3:Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.1.1) Gecko/20070129 Firefox/2.0.0.1

C/C++ の enum 相当の機能

question:1175229198

使い易いようにメソッドにしてみた。また、C/C++ 相当の機能と、C/C++ にも無い機能を追加してみた。*1

constant.rb
#!ruby

module Constant
  def self.enum_set(klass, names, init_val = 0)
    value = init_val.to_int
    names.each do |name|
      klass.const_set(name, value)
      value += 1
    end
  end

  def self.enum_set_ex(klass, exprs, init_val = 0)
    value = init_val.to_int
    exprs.each do |expr|
      case expr
      when /\A([^=]+)\s*=\s*(.+)\Z/
	value = klass.module_eval($2).to_int
	klass.const_set($1, value)
      else
	klass.const_set(expr, value)
      end
      value += 1
    end
  end

  def self.enum_set_bit(klass, names, init_val = 1)
    value = init_val.to_int
    names.each do |name|
      klass.const_set(name, value)
      value <<= 1
    end
  end
end

class Module
  def enum_const_set(names, init_val = 0)
    Constant.enum_set(self, names, init_val)
  end

  def enum_const_set_ex(exprs, init_val = 0)
    Constant.enum_set_ex(self, exprs, init_val)
  end

  def enum_const_set_bit(names, init_val = 1)
    Constant.enum_set_bit(self, names, init_val)
  end
end

次のような感じで使える。

enum_const_set
require 'constant'

class Foo
  enum_const_set %w[
    XX_A
    XX_B
    XX_C
  ]
end

p Foo::XX_A	# => 0
p Foo::XX_B	# => 1
p Foo::XX_C	# => 2
enum_const_set_ex
require 'constant'

class Foo
  enum_const_set_ex %w[
    XX_A
    XX_B
    XX_C=-2
    XX_D
    XX_E=XX_B
  ]
end

p Foo::XX_A	# => 0
p Foo::XX_B	# => 1
p Foo::XX_C	# => -2
p Foo::XX_D	# => -1
p Foo::XX_E	# => 1
enum_const_set_bit
require 'constant'

class Foo
  enum_const_set_bit %w[
    XX_A
    XX_B
    XX_C
  ]
end

p Foo::XX_A	# => 1 = 0b0001
p Foo::XX_B	# => 2 = 0b0010
p Foo::XX_C	# => 4 = 0b0100

*1:私自身も昔作ろうとしたけど、当時はできなかった。

STLでメモリーリーク?

question:1174986855

valgrind でメモリーリークが検出されるのは、どうやら std::allocator が原因のようだ。

テストプログラム
#include <memory>

int main()
{
  std::allocator<int> allocator;
  int *ip = allocator.allocate(1);
  allocator.deallocate(ip, 1);
}
テスト環境
% uname -v
FreeBSD 6.2-RELEASE #0: Fri Jan 12 10:40:27 UTC 2007     root@dessler.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC 
% g++ --version
g++ (GCC) 3.3.6
Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

% g++ -Wall -g -o allocator allocator.cpp 
テスト結果
% valgrind --leak-check=yes --show-reachable=yes ./allocator
==2756== Memcheck, a memory error detector for x86-linux.
==2756== Copyright (C) 2002-2004, and GNU GPL'd, by Julian Seward.
==2756== Using valgrind-2.1.0, a program supervision framework for x86-linux.
==2756== Copyright (C) 2000-2004, and GNU GPL'd, by Julian Seward.
==2756== Estimated CPU clock rate is 500 MHz
==2756== For more details, rerun with: -v
==2756== 
==2756== 
==2756== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==2756== malloc/free: in use at exit: 320 bytes in 1 blocks.
==2756== malloc/free: 1 allocs, 0 frees, 320 bytes allocated.
==2756== For counts of detected errors, rerun with: -v
==2756== searching for pointers to 1 not-freed blocks.
==2756== checked 2189936 bytes.
==2756== 
==2756== 320 bytes in 1 blocks are still reachable in loss record 1 of 1
==2756==    at 0x3C0382F3: operator new(unsigned) (in /usr/local/lib/valgrind/vgpreload_memcheck.so)
==2756==    by 0x3C0B7FC1: std::__default_alloc_template<true, 0>::_S_chunk_alloc(unsigned, int&) (stl_alloc.h:108)
==2756==    by 0x3C0B7EDB: std::__default_alloc_template<true, 0>::_S_refill(unsigned) (stl_alloc.h:550)
==2756==    by 0x3C0B7C48: std::__default_alloc_template<true, 0>::allocate(unsigned) (stl_alloc.h:357)
==2756== 
==2756== LEAK SUMMARY:
==2756==    definitely lost: 0 bytes in 0 blocks.
==2756==    possibly lost:   0 bytes in 0 blocks.
==2756==    still reachable: 320 bytes in 1 blocks.
==2756==         suppressed: 0 bytes in 0 blocks.

3.3 系列では、効率化の為か複雑(?)な処理をしているようだが(未読)、そこにバグがあるのか、効率化の為の仕様なのかはわからない。(気が向いたら読んでみるかも。)
ちなみに、3.4 系列では、単純に new/delete を呼ぶだけになっているので、メモリーリークは検出されなくなっている。

続く…かも?

はてなダイアリーへようこそ!

このページはあなた専用の日記(ブログ)です。*1

さっそく「日記を書く」をクリックして最初の記事を書いてみましょう。

はてなダイアリーの一番簡単な使い方を知りたい方は、以下の動画をご覧ください。

(再生ボタンをクリックすると、はてなダイアリーの使い方を音声と動画で見ることができます。)

はてなダイアリーのヘルプでは、このような動画を交えた使い方の説明や、文字の色の付け方、本やDVDを紹介する「はてな記法」の使い方を解説しています。

より詳しいはてなダイアリーの使い方を知りたい方は、以下のヘルプをご覧ください。


それでは、日々の出来事やテレビ番組の感想、普段考えていることなど、あなたならではの日記を書いて楽しんでください!

*1:この文章はサンプルです。実際に自分の記事を書くときには削除しても大丈夫です。