From f089a52865bd82a327fe9ef460cecdb812dcb56c Mon Sep 17 00:00:00 2001 From: shyouhei Date: Mon, 15 Jan 2018 02:35:16 +0000 Subject: [PATCH] __attibute__((__aligned__)) for RSTRING_PTR() For instance array.c:rb_ary_product() uses RSTRING_PTR() as an array of int. So to avoid misaligned memory access RSTRING_PTR() must at least be sizeof(int)-aligned. However the type of RSTRING_PTR() is char*, which of course can expect alignment as much as 1. This is a problem. The reality is, there is no misaligned memory access because the memory region behind RSTRING_PTR() is allocated using malloc(). Memory regions returned from malloc() are always aligned appropriately. So let's tell the compiler about this information. It seems GCC, clang, and MSVC have such feature. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61827 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- compile.c | 2 +- configure.ac | 26 +++++++++++++++++++++++++- include/ruby/defines.h | 4 ++++ include/ruby/ruby.h | 17 ++++++++--------- win32/Makefile.sub | 1 + 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/compile.c b/compile.c index f4ae64bacc..98004b65a0 100644 --- a/compile.c +++ b/compile.c @@ -8077,7 +8077,7 @@ struct ibf_dump { rb_iseq_t * iseq_alloc(void); struct ibf_load { - const char *buff; + const RUBY_ALIGNAS(sizeof(VALUE)) char *buff; const struct ibf_header *header; ID *id_list; /* [id0, ...] */ VALUE iseq_list; /* [iseq0, ...] */ diff --git a/configure.ac b/configure.ac index 81efb0bbc1..f7707b761d 100644 --- a/configure.ac +++ b/configure.ac @@ -1743,6 +1743,30 @@ EOH ])dnl ])dnl +AC_CACHE_CHECK([for alignas() syntax], rb_cv_have_alignas, [ +rb_cv_have_alignas=no +RUBY_WERROR_FLAG([ +for attr in \ + "_Alignas(x)" \ + "alignas(x)" \ + "@<:@@<:@alignas(x)@:>@@:>@" \ + "__declspec(aligned(x))" \ + "__attribute__((__aligned__(x)))" \ +; +do + # C11 _Alignas and GCC __attribute__((__aligned__)) behave + # slightly differently. What we want is GCC's. Check that + # here by something C11 does not allow (`struct ALIGNAS ...`) + AC_TRY_COMPILE( + [@%:@define ALIGNAS(x) $attr + struct ALIGNAS(128) conftest_tag { int foo; } foo; ], [], + [rb_cv_have_alignas="$attr"; break], []) +done +])]) +AS_IF([test "$rb_cv_have_alignas" != no], [ + AC_DEFINE_UNQUOTED([RUBY_ALIGNAS(x)], $rb_cv_have_alignas) +]) + dnl RUBY_DECL_ATTRIBUTE(attrib, macroname, cachevar, condition, type, code) AC_DEFUN([RUBY_DECL_ATTRIBUTE], [dnl m4_ifval([$2], dnl @@ -1773,6 +1797,7 @@ ${rbcv_cond+[@%:@define ]attrib[](attrib_params)[ x]} ${rbcv_cond+[@%:@endif]}) $6 @%:@define mesg ("") +@%:@define n (32768) attrib[](attrib_params)[;], [], [rbcv="$mac"; break]) done @@ -1801,7 +1826,6 @@ AC_DEFUN([RUBY_TYPE_ATTRIBUTE], [dnl @%:@define x struct conftest_attribute_check {int i;} ]) ]) - RUBY_FUNC_ATTRIBUTE(__const__, CONSTFUNC) RUBY_FUNC_ATTRIBUTE(__pure__, PUREFUNC) RUBY_FUNC_ATTRIBUTE(__noreturn__, NORETURN) diff --git a/include/ruby/defines.h b/include/ruby/defines.h index 2c72a7cb8a..da2ba24109 100644 --- a/include/ruby/defines.h +++ b/include/ruby/defines.h @@ -376,6 +376,10 @@ void rb_ia64_flushrs(void); # endif #endif +#ifndef RUBY_ALIGNAS +#define RUBY_ALIGNAS(x) y +#endif + RUBY_SYMBOL_EXPORT_END #if defined(__cplusplus) diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index 6d84a6b06e..fe0ecf4622 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -853,14 +853,10 @@ enum ruby_fl_type { RUBY_FL_SINGLETON = RUBY_FL_USER0 }; -struct RBasic { +struct RUBY_ALIGNAS(sizeof(VALUE)) RBasic { VALUE flags; const VALUE klass; -} -#ifdef __GNUC__ - __attribute__((aligned(sizeof(VALUE)))) -#endif -; +}; VALUE rb_obj_hide(VALUE obj); VALUE rb_obj_reveal(VALUE obj, VALUE klass); /* do not use this API to change klass information */ @@ -953,18 +949,21 @@ enum ruby_rstring_flags { RSTRING_ENUM_END }; + +typedef RUBY_ALIGNAS(sizeof(VALUE)) char ruby_aligned_char; + struct RString { struct RBasic basic; union { struct { long len; - char *ptr; + ruby_aligned_char *ptr; union { long capa; VALUE shared; } aux; } heap; - char ary[RSTRING_EMBED_LEN_MAX + 1]; + char RUBY_ALIGNAS(sizeof(VALUE)) ary[RSTRING_EMBED_LEN_MAX + 1]; } as; }; #define RSTRING_EMBED_LEN(str) \ @@ -976,7 +975,7 @@ struct RString { RSTRING(str)->as.heap.len) #define RSTRING_PTR(str) \ (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \ - RSTRING(str)->as.ary : \ + (ruby_aligned_char *)RSTRING(str)->as.ary : \ RSTRING(str)->as.heap.ptr) #define RSTRING_END(str) \ (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \ diff --git a/win32/Makefile.sub b/win32/Makefile.sub index 944573f1bb..a3ac277dd2 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -636,6 +636,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define PACKED_STRUCT_UNALIGNED(x) x !endif #define RUBY_EXTERN extern __declspec(dllimport) +#define RUBY_ALIGNAS(n) __declspec(align(n)) #define HAVE_DECL_SYS_NERR 1 #define HAVE_LIMITS_H 1 #define HAVE_FCNTL_H 1