Bug #7307

gcc -ansi vs. alloca (undefined reference to `alloca')

Added by Akinori MUSHA over 2 years ago. Updated over 2 years ago.

[ruby-core:49086]
Status:Closed
Priority:Normal
Assignee:-
ruby -v:ruby 2.0.0dev (2012-11-08) [x86_64-openbsd] Backport:

Description

Ruby 2.0.0からは CFLAGS に -ansi が(サポートがあれば)付くように
なりましたが、これにより、 gcc の builtin alloca に依存しており
libc に alloca(3) を持たない環境、具体的にはOpenBSD(およびおそら
くNetBSDの mips, powerpc, powerpc64, sparc, sparc64 等)で次のよう
なリンクエラーが発生します。

linking miniruby
addr2line.o(.text+0x9e7): In function follow_debuglink':
/home/knu/src/ruby-trunk-vanilla/addr2line.c:424: warning: strcpy() is almost always misused, please use strlcpy()
regerror.o(.text+0x499): In function
onig_vsnprintf_with_pattern':
/home/knu/src/ruby-trunk-vanilla/regerror.c:334: warning: strcat() is almost always misused, please use strlcat()
regerror.o(.text+0x55e):/home/knu/src/ruby-trunk-vanilla/regerror.c:197: warning: sprintf() is often misused, please use snprintf()
dmyencoding.o(.text+0x120e): In function set_encoding_const':
/home/knu/src/ruby-trunk-vanilla/encoding.c:1535: undefined reference to
alloca'
bignum.o(.text+0xbfea): In function rb_str_to_inum':
/home/knu/src/ruby-trunk-vanilla/bignum.c:791: undefined reference to
alloca'
object.o(.text+0x11c2): In function rb_str_to_dbl':
/home/knu/src/ruby-trunk-vanilla/object.c:2565: undefined reference to
alloca'
parse.o(.text+0x1e24): In function parser_yyerror':
/home/knu/src/ruby-trunk-vanilla/build.unknown.openbsd-amd64/parse.y:5221: undefined reference to
alloca'
parse.o(.text+0xb2c8): In function parser_tokadd_string':
/home/knu/src/ruby-trunk-vanilla/build.unknown.openbsd-amd64/parse.y:6072: undefined reference to
alloca'
parse.o(.text+0xb2fb):/home/knu/src/ruby-trunk-vanilla/build.unknown.openbsd-amd64/parse.y:6085: more undefined references to `alloca' follow
collect2: ld returned 1 exit status
*** Error code 1

Stop in /home/knu/src/ruby-trunk-vanilla/build.unknown.openbsd-amd64 (line 180 of Makefile).

なぜ(configure は成功するのに)こけるかの説明は以下の通りです。

  1. autoconf の AC_FUNC_ALLOCA は次のようなコードによるテストに展開 されるので、 gcc を使う限りは alloca は __builtin_alloca に置き換 わるので configure は成功する

#ifdef GNUC

define alloca _builtinalloca

#else

ifdef _MSC_VER

include

define alloca _alloca

else

ifdef HAVE_ALLOCA_H

include

else

ifdef _AIX

#pragma alloca

else

ifndef alloca /* predefined by HP cc +Olibcalls */

void *alloca (size_t);

endif

endif

endif

endif

#endif

  1. gcc は -ansi を付けると alloca を提供しなくなる
    (__builtin_alloca は常にある)

  2. ruby のソースツリーでは(マクロを通じて)広く alloca が使われて
    いるが、上記1のような alloca のケア(置換)を行っているのは gc.c
    や #include "eval_intern.h" しているもののみ

  3. しかし、基本的にすべてのファイルが -ansi 付きでビルドされるので、
    addr2line.o, regerror.o, encoding.o 等々に alloca への参照が埋まっ
    てしまい、 libc に alloca がない環境ではリンクエラーとなる

解決策は、 ruby/ruby.h の alloca 関連部を gc.c などにあるような
gcc 対応を含む完全なものにすることです。

下のパッチを適用し、以下の環境で make test が通りました。

  • OpenBSD/amd64 5.2-RELEASE (GCC 4.2.1) - libc has no alloca
  • FreeBSD/amd64 9.1-PRERELEASE (GCC 4.2.1)
  • FreeBSD/amd64 9.1-PRERELEASE (clang 3.1)
  • Mac OS X 10.8.2 (Apple clang 4.1)

問題なければコミットします。

alloca.diff Magnifier (3.67 KB) Akinori MUSHA, 11/08/2012 03:14 PM

Associated revisions

Revision 37571
Added by Akinori MUSHA over 2 years ago

Fix build when gcc is used and the platform's libc lacks alloca().

  • include/ruby/ruby.h (alloca), eval_intern.h (alloca), gc.c
    (alloca): Make alloca() globally available by moving the
    ultimate ifdef's to ruby/ruby.h. Gcc hides its builtin alloca()
    when compiling with -ansi, and linking thus fails on platforms
    that lack their own alloca() implementation in libc, which
    include OpenBSD and some ports of NetBSD. We use alloca()
    everywhere including from within third party C extentions, so
    alloca() must be made globally available. [Bug #7307]

  • addr2line.c (alloca): Replace the alloca() part with the
    ultimate ifdef's. [Bug #7307]

Revision 37571
Added by Akinori MUSHA over 2 years ago

Fix build when gcc is used and the platform's libc lacks alloca().

  • include/ruby/ruby.h (alloca), eval_intern.h (alloca), gc.c
    (alloca): Make alloca() globally available by moving the
    ultimate ifdef's to ruby/ruby.h. Gcc hides its builtin alloca()
    when compiling with -ansi, and linking thus fails on platforms
    that lack their own alloca() implementation in libc, which
    include OpenBSD and some ports of NetBSD. We use alloca()
    everywhere including from within third party C extentions, so
    alloca() must be made globally available. [Bug #7307]

  • addr2line.c (alloca): Replace the alloca() part with the
    ultimate ifdef's. [Bug #7307]

History

#1 Updated by Akinori MUSHA over 2 years ago

バリデーションに捕まったのにアップロードファイルを再添付忘れました。

#2 Updated by Akinori MUSHA over 2 years ago

  • Category changed from core to build

Sorry, I could have sworn that I chose ruby-dev as Preferred language but after a form error that I didn't fill in ruby -v the field got somehow reset to the default value (ruby-core) and I resubmitted the form without noticing it...

#3 Updated by Motohiro KOSAKI over 2 years ago

ちゃんと読めてませんが、 autoconf の AC_FUNC_ALLOCA のコードをそのままカット&ペーストで持ってきたという意味ならライセンス非互換なのでよくないのではないでしょうか。
gc.c のやつをruby.h に引っ越しただけという話ならすいません。

#そもそも -ansi を外してしまうという案を押したい。-ansi はピュアANSI Cという意味だけど、rubyはANSI外の様々なPOSIX関数を

使いまくってるので、どうにも本来の使い道でない感があります。たまたま動いているだけというか

#4 Updated by Akinori MUSHA over 2 years ago

その通り、 gc.c にあったものを ruby/ruby.h に移動しただけです。
当該部分の内容はコメントを含めほぼ autoconf の吐くものと同一ですが、 configure スクリプト冒頭にもある通り、
生成された configure スクリプトはGPLの例外で、利用(改変、コピー、配布)にあたって制限はないはずです。
cf. http://www.gnu.org/licenses/autoconf-exception.html

-ansi を外すというのはできればそうしたいですね。
潜在バグのあぶり出しや移植性の低いコードの混入を防ぐような効果を期待しているのでしょうか。

#5 Updated by Akinori MUSHA over 2 years ago

なお、現状ではビルドできないプラットフォームがあるので、 -ansi をどうするかというのとは別に、
早めに入れて救済を優先したいなと思っています。

#6 Updated by Shyouhei Urabe over 2 years ago

knu (Akinori MUSHA) wrote:

-ansi を外すというのはできればそうしたいですね。
潜在バグのあぶり出しや移植性の低いコードの混入を防ぐような効果を期待しているのでしょうか。

そうです。もとの動機に関しては下記をご参照ください。
http://qa.atmarkit.co.jp/q/2159

#7 Updated by Akinori MUSHA over 2 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r37571.
Akinori, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


Fix build when gcc is used and the platform's libc lacks alloca().

  • include/ruby/ruby.h (alloca), eval_intern.h (alloca), gc.c
    (alloca): Make alloca() globally available by moving the
    ultimate ifdef's to ruby/ruby.h. Gcc hides its builtin alloca()
    when compiling with -ansi, and linking thus fails on platforms
    that lack their own alloca() implementation in libc, which
    include OpenBSD and some ports of NetBSD. We use alloca()
    everywhere including from within third party C extentions, so
    alloca() must be made globally available. [Bug #7307]

  • addr2line.c (alloca): Replace the alloca() part with the
    ultimate ifdef's. [Bug #7307]

#8 Updated by Akinori MUSHA over 2 years ago

shyouhei (Shyouhei Urabe) wrote:

knu (Akinori MUSHA) wrote:

-ansi を外すというのはできればそうしたいですね。
潜在バグのあぶり出しや移植性の低いコードの混入を防ぐような効果を期待しているのでしょうか。

そうです。もとの動機に関しては下記をご参照ください。
http://qa.atmarkit.co.jp/q/2159

なるほど。せっかく今はコンパイルできているので、具体的に困るまではいいか。

なお、そういう用途では-pedanticも付けるのが定番だと思いますが、実効性のほどは分かりません。

Also available in: Atom PDF