Daniel Adler
2012-Feb-06 13:27 UTC
[Rd] Segfault on ".C" registration via R_CMethodDef according to 'Writing R Extensions'.
Dear R List,
I encountered a serious problem regarding the registration of ".C"
when following the documentation "Writing R Extensions"
that leads to a segmentation fault (tested on windows and mac os x).
The registration mechanism for ".C" routines via R_registerRoutines
and
the R_CMethodDef structure has been enhanced recently with the
addition of two fields, one for type specification and the other for
the style (in, out, inout or irrelevant).
According to the manual 'Writing R Extensions' of version 2.14.1
an example is given that specifies to use the fourth field (type information)
for definitions of C routines that use the ".C" calling convention:
R_CMethodDef cMethods[] = {
{"myC", (DL_FUNC) &myC, 4, {REALSXP, INTSXP, STRSXP,
LGLSXP}}, /* segfault! */
{NULL, NULL, 0}
};
If I follow this example I get compiler warnings or errors (whether I use C or
C++, respectively) and
a segmentation fault (in the case of C) when doing R CMD INSTALL, which seem to
happen during testing.
See build log at the end of this e-mail.
When removing the last field in the initializer list in order to register .C
routines in the old way the segfault goes away:
R_CMethodDef cMethods[] = {
{"myC", (DL_FUNC) &myC, 4}, /* works */
{NULL, NULL, 0}
};
There are still warnings/segfault or an error when initializing the undocumented
fifth entry (parameter passing style), e.g.
R_CMethodDef cMethods[] = {
{"myC", (DL_FUNC) &myC, 4, {REALSXP, INTSXP, STRSXP,
LGLSXP}, {R_ARG_IN, R_ARG_IN, R_ARG_IN, R_ARG_IN}, /* segfault! */
{NULL, NULL, 0}
};
Using a C source, the warnings are:
*** arch - i386
gcc -arch i386 -std=gnu99 -I/Library/Frameworks/R.framework/Resources/include
-I/Library/Frameworks/R.framework/Resources/include/i386 -I/usr/local/include
-fPIC -g -O2 -Wall -pedantic -c reg.c -o reg.o
reg.c:24: warning: braces around scalar initializer
reg.c:24: warning: (near initialization for ?cMethods[0].types?)
reg.c:24: warning: initialization makes pointer from integer without a cast
reg.c:24: warning: excess elements in scalar initializer
reg.c:24: warning: (near initialization for ?cMethods[0].types?)
reg.c:24: warning: excess elements in scalar initializer
reg.c:24: warning: (near initialization for ?cMethods[0].types?)
reg.c:24: warning: excess elements in scalar initializer
reg.c:24: warning: (near initialization for ?cMethods[0].types?)
Using C++, protecting the init/unload function prototypes and structure
declarations via 'extern "C" { }', I get the following error:
*** arch - i386
g++ -arch i386 -I/Library/Frameworks/R.framework/Resources/include
-I/Library/Frameworks/R.framework/Resources/include/i386 -I/usr/local/include
-fPIC -g -O2 -c reg.cpp -o reg.o
reg.cpp:30: error: braces around scalar initializer for type
???R_NativePrimitiveArgType*???
(line 24 is the point on the entry, while line 30 is the end of the overall
array initialization list in C++).
If I put the type and style (unsigned int and enum) arrays separately,
the build process works just fine. E.g.
R_NativePrimitiveArgType types[] = {REALSXP, INTSXP, STRSXP, LGLSXP};
R_NativeArgStyle styles[] = { R_ARG_IN, R_ARG_IN, R_ARG_IN, R_ARG_IN };
R_CMethodDef cMethods[] = {
{"myC", (DL_FUNC) &myC, 4, types, NULL}, /* works */
{"myC2", (DL_FUNC) &myC, 4, types, style}, /* works */
{NULL, NULL, 0}
};
(Though I haven't tested the runtime behaviour yet.. but at least no
segfault during R CMD INSTALL..)
I wonder what is wrong with the static initializer lists?!
I could imagine it has something to do with the standard compilance of the C/C++
compiler (due to the different behaviour warning or error during compilation).
Anyway, going with the manual right now, the ordinary user will get warnings and
errors - at least on the systems that I have tested (recent version of
Rtools/Windows 7
and Mac OS X 10.6 with gcc 4.2.1).
On Windows instead of a trace output, a window pops up during install to tell
about a process crash.
- Daniel
PS: If it helps, I could put up a test package online for further debugging.
--- build log: ----------------------------------------------------------------
** testing if installed package can be loaded
*** arch - i386
*** caught bus error ***
address 0xe, cause 'non-existent physical address'
Traceback:
1: dyn.load(file, DLLpath = DLLpath, ...)
2: library.dynam(lib, package, package.lib)
3: loadNamespace(package, c(which.lib.loc, lib.loc))
4: doTryCatch(return(expr), name, parentenv, handler)
5: tryCatchOne(expr, names, parentenv, handlers[[1L]])
6: tryCatchList(expr, classes, parentenv, handlers)
7: tryCatch(expr, error = function(e) { call <- conditionCall(e) if
(!is.null(call)) { if (identical(call[[1L]], quote(doTryCatch)))
call <- sys.call(-4L) dcall <- deparse(call)[1L] prefix
<- paste("Error in", dcall, ": ") LONG <- 75L
msg <- conditionMessage(e) sm <- strsplit(msg,
"\n")[[1L]] w <- 14L + nchar(dcall, type = "w") +
nchar(sm[1L], type = "w") if (is.na(w)) w <- 14L
+ nchar(dcall, type = "b") + nchar(sm[1L], type =
"b") if (w > LONG) prefix <- paste(prefix,
"\n ", sep = "") } else prefix <- "Error :
" msg <- paste(prefix, conditionMessage(e), "\n", sep =
"") .Internal(seterrmessage(msg[1L])) if (!silent &&
identical(getOption("show.error.messages"), TRUE)) {
cat(msg, file = stderr()) .Internal(printDeferredWarnings()) }
invisible(structure(msg, class = "try-error", condition = e))})
8: try({ ns <- loadNamespace(package, c(which.lib.loc, lib.loc))
dataPath <- file.path(which.lib.loc, package, "data") env <-
attachNamespace(ns, pos = pos, dataPath = dataPath, deps)})
9: library(pkg_name, lib.loc = lib, character.only = TRUE, logical.return =
TRUE)
10: withCallingHandlers(expr, packageStartupMessage = function(c)
invokeRestart("muffleMessage"))
11: suppressPackageStartupMessages(library(pkg_name, lib.loc = lib,
character.only = TRUE, logical.return = TRUE))
12: doTryCatch(return(expr), name, parentenv, handler)
13: tryCatchOne(expr, names, parentenv, handlers[[1L]])
14: tryCatchList(expr, classes, parentenv, handlers)
15: tryCatch(expr, error = function(e) { call <- conditionCall(e) if
(!is.null(call)) { if (identical(call[[1L]], quote(doTryCatch)))
call <- sys.call(-4L) dcall <- deparse(call)[1L] prefix
<- paste("Error in", dcall, ": ") LONG <- 75L
msg <- conditionMessage(e) sm <- strsplit(msg,
"\n")[[1L]] w <- 14L + nchar(dcall, type = "w") +
nchar(sm[1L], type = "w") if (is.na(w)) w <- 14L
+ nchar(dcall, type = "b") + nchar(sm[1L], type =
"b") if (w > LONG) prefix <- paste(prefix,
"\n ", sep = "") } else prefix <- "Error :
" msg <- paste(prefix, conditionMessage(e), "\n", sep =
"") .Internal(seterrmessage(msg[1L])) if (!silent &&
identical(getOption("show.error.messages"), TRUE)) {
cat(msg, file = stderr()) .Internal(printDeferredWarnings()) }
invisible(structure(msg, class = "try-error", condition = e))})
16: try(suppressPackageStartupMessages(library(pkg_name, lib.loc = lib,
character.only = TRUE, logical.return = TRUE)))
17: tools:::.test_load_package("mylib",
"/Users/dadler/Library/R/2.14/library")
aborting ...
sh: line 1: 75200 Bus error
'/Library/Frameworks/R.framework/Resources/bin/R' --arch=i386 --no-save
--slave <
/var/folders/Lr/Lrh7GWILEqCwHkyF1MdauE+++TI/-Tmp-//RtmpDqusSN/file1259d93ec2eb
*** arch - x86_64
Simon Urbanek
2012-Feb-06 14:47 UTC
[Rd] Segfault on ".C" registration via R_CMethodDef according to 'Writing R Extensions'.
Daniel,
the code you are using is probably not what you intended - since there is no
length information the compiler assumes you are filling the structure
sequentially and thus the expected value is that for R_NativePrimitiveArgType*
which has no length, so it can only be initialized with a scalar value, so you
are setting
R_NativePrimitiveArgType* types = REALSXP
which is wrong as you are casing an integer into a pointer. Also that's why
you get the warnings which are all valid:
ra.c:9: warning: braces around scalar initializer
-- because it is interpeted as {REALSXP} hence superfluous braces
ra.c:9: warning: initialization makes pointer from integer without a cast
-- because you're initializing R_NativePrimitiveArgType* with an integer
(REALSXP)
ra.c:9: warning: excess elements in scalar initializer
-- because INTSXP, ... must be ignored since "types" can only be
initialized with a scalar (pointer)
For what you intended, you're using variable-length array so you have to
specify its length:
{"myC", (DL_FUNC) &myC, 4, (R_NativePrimitiveArgType[4])
{REALSXP, INTSXP, STRSXP, LGLSXP}}
which will allocate extra static object (it has to because "types" is
a pointer, not a fixed array) - so the effect is the same as using a static
object.
Cheers,
Simon
On Feb 6, 2012, at 8:27 AM, Daniel Adler wrote:
> Dear R List,
>
> I encountered a serious problem regarding the registration of
".C" when following the documentation "Writing R Extensions"
> that leads to a segmentation fault (tested on windows and mac os x).
>
> The registration mechanism for ".C" routines via
R_registerRoutines and
> the R_CMethodDef structure has been enhanced recently with the
> addition of two fields, one for type specification and the other for
> the style (in, out, inout or irrelevant).
>
> According to the manual 'Writing R Extensions' of version 2.14.1
> an example is given that specifies to use the fourth field (type
information)
> for definitions of C routines that use the ".C" calling
convention:
>
> R_CMethodDef cMethods[] = {
> {"myC", (DL_FUNC) &myC, 4, {REALSXP, INTSXP, STRSXP,
LGLSXP}}, /* segfault! */
> {NULL, NULL, 0}
> };
>
> If I follow this example I get compiler warnings or errors (whether I use C
or C++, respectively) and
> a segmentation fault (in the case of C) when doing R CMD INSTALL, which
seem to happen during testing.
> See build log at the end of this e-mail.
>
> When removing the last field in the initializer list in order to register
.C routines in the old way the segfault goes away:
>
> R_CMethodDef cMethods[] = {
> {"myC", (DL_FUNC) &myC, 4}, /* works */
> {NULL, NULL, 0}
> };
>
> There are still warnings/segfault or an error when initializing the
undocumented fifth entry (parameter passing style), e.g.
>
> R_CMethodDef cMethods[] = {
> {"myC", (DL_FUNC) &myC, 4, {REALSXP, INTSXP, STRSXP,
LGLSXP}, {R_ARG_IN, R_ARG_IN, R_ARG_IN, R_ARG_IN}, /* segfault! */
> {NULL, NULL, 0}
> };
>
> Using a C source, the warnings are:
>
> *** arch - i386
> gcc -arch i386 -std=gnu99
-I/Library/Frameworks/R.framework/Resources/include
-I/Library/Frameworks/R.framework/Resources/include/i386 -I/usr/local/include
-fPIC -g -O2 -Wall -pedantic -c reg.c -o reg.o
> reg.c:24: warning: braces around scalar initializer
> reg.c:24: warning: (near initialization for ?cMethods[0].types?)
> reg.c:24: warning: initialization makes pointer from integer without a cast
> reg.c:24: warning: excess elements in scalar initializer
> reg.c:24: warning: (near initialization for ?cMethods[0].types?)
> reg.c:24: warning: excess elements in scalar initializer
> reg.c:24: warning: (near initialization for ?cMethods[0].types?)
> reg.c:24: warning: excess elements in scalar initializer
> reg.c:24: warning: (near initialization for ?cMethods[0].types?)
>
>
> Using C++, protecting the init/unload function prototypes and structure
declarations via 'extern "C" { }', I get the following error:
>
> *** arch - i386
> g++ -arch i386 -I/Library/Frameworks/R.framework/Resources/include
-I/Library/Frameworks/R.framework/Resources/include/i386 -I/usr/local/include
-fPIC -g -O2 -c reg.cpp -o reg.o
> reg.cpp:30: error: braces around scalar initializer for type
???R_NativePrimitiveArgType*???
>
> (line 24 is the point on the entry, while line 30 is the end of the overall
array initialization list in C++).
>
> If I put the type and style (unsigned int and enum) arrays separately,
> the build process works just fine. E.g.
>
> R_NativePrimitiveArgType types[] = {REALSXP, INTSXP, STRSXP, LGLSXP};
> R_NativeArgStyle styles[] = { R_ARG_IN, R_ARG_IN, R_ARG_IN, R_ARG_IN };
>
> R_CMethodDef cMethods[] = {
> {"myC", (DL_FUNC) &myC, 4, types, NULL}, /* works
*/
> {"myC2", (DL_FUNC) &myC, 4, types, style}, /* works
*/
> {NULL, NULL, 0}
> };
>
> (Though I haven't tested the runtime behaviour yet.. but at least no
segfault during R CMD INSTALL..)
>
> I wonder what is wrong with the static initializer lists?!
>
> I could imagine it has something to do with the standard compilance of the
C/C++
> compiler (due to the different behaviour warning or error during
compilation).
>
> Anyway, going with the manual right now, the ordinary user will get
warnings and
> errors - at least on the systems that I have tested (recent version of
Rtools/Windows 7
> and Mac OS X 10.6 with gcc 4.2.1).
> On Windows instead of a trace output, a window pops up during install to
tell
> about a process crash.
>
> - Daniel
>
> PS: If it helps, I could put up a test package online for further
debugging.
>
> --- build log:
----------------------------------------------------------------
>
> ** testing if installed package can be loaded
> *** arch - i386
>
> *** caught bus error ***
> address 0xe, cause 'non-existent physical address'
>
> Traceback:
> 1: dyn.load(file, DLLpath = DLLpath, ...)
> 2: library.dynam(lib, package, package.lib)
> 3: loadNamespace(package, c(which.lib.loc, lib.loc))
> 4: doTryCatch(return(expr), name, parentenv, handler)
> 5: tryCatchOne(expr, names, parentenv, handlers[[1L]])
> 6: tryCatchList(expr, classes, parentenv, handlers)
> 7: tryCatch(expr, error = function(e) { call <- conditionCall(e)
if (!is.null(call)) { if (identical(call[[1L]], quote(doTryCatch)))
call <- sys.call(-4L) dcall <- deparse(call)[1L] prefix
<- paste("Error in", dcall, ": ") LONG <- 75L
msg <- conditionMessage(e) sm <- strsplit(msg,
"\n")[[1L]] w <- 14L + nchar(dcall, type = "w") +
nchar(sm[1L], type = "w") if (is.na(w)) w <- 14L
+ nchar(dcall, type = "b") + nchar(sm[1L], type =
"b") if (w > LONG) prefix <- paste(prefix,
"\n ", sep = "") } else prefix <- "Error :
" msg <- paste(prefix, conditionMessage(e), "\n", sep =
"") .Internal(seterrmessage(msg[1L])) if (!silent &&
identical(getOption("show.error.messages"), TRUE)) {
cat(msg, file = stderr()) .Internal(printDeferredWarnings()) }
invisible(structure(msg, class = "try-error", condition = e))})
> 8: try({ ns <- loadNamespace(package, c(which.lib.loc, lib.loc))
dataPath <- file.path(which.lib.loc, package, "data") env <-
attachNamespace(ns, pos = pos, dataPath = dataPath, deps)})
> 9: library(pkg_name, lib.loc = lib, character.only = TRUE, logical.return =
TRUE)
> 10: withCallingHandlers(expr, packageStartupMessage = function(c)
invokeRestart("muffleMessage"))
> 11: suppressPackageStartupMessages(library(pkg_name, lib.loc = lib,
character.only = TRUE, logical.return = TRUE))
> 12: doTryCatch(return(expr), name, parentenv, handler)
> 13: tryCatchOne(expr, names, parentenv, handlers[[1L]])
> 14: tryCatchList(expr, classes, parentenv, handlers)
> 15: tryCatch(expr, error = function(e) { call <- conditionCall(e)
if (!is.null(call)) { if (identical(call[[1L]], quote(doTryCatch)))
call <- sys.call(-4L) dcall <- deparse(call)[1L] prefix
<- paste("Error in", dcall, ": ") LONG <- 75L
msg <- conditionMessage(e) sm <- strsplit(msg,
"\n")[[1L]] w <- 14L + nchar(dcall, type = "w") +
nchar(sm[1L], type = "w") if (is.na(w)) w <- 14L
+ nchar(dcall, type = "b") + nchar(sm[1L], type =
"b") if (w > LONG) prefix <- paste(prefix,
"\n ", sep = "") } else prefix <- "Error :
" msg <- paste(prefix, conditionMessage(e), "\n", sep =
"") .Internal(seterrmessage(msg[1L])) if (!silent &&
identical(getOption("show.error.messages"), TRUE)) {
cat(msg, file = stderr()) .Internal(printDeferredWarnings()) }
invisible(structure(msg, class = "try-error", condition = e))})
> 16: try(suppressPackageStartupMessages(library(pkg_name, lib.loc = lib,
character.only = TRUE, logical.return = TRUE)))
> 17: tools:::.test_load_package("mylib",
"/Users/dadler/Library/R/2.14/library")
> aborting ...
> sh: line 1: 75200 Bus error
'/Library/Frameworks/R.framework/Resources/bin/R' --arch=i386 --no-save
--slave <
/var/folders/Lr/Lrh7GWILEqCwHkyF1MdauE+++TI/-Tmp-//RtmpDqusSN/file1259d93ec2eb
> *** arch - x86_64
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>
>