Skip to content

Commit 29f3a73

Browse files
author
maechler
committed
move check to internal installAttrib() preventing e.g. also attr<- to mutate primitives via attributes
git-svn-id: https://svn.r-project.org/R/trunk@88060 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent 8c2592c commit 29f3a73

File tree

4 files changed

+28
-12
lines changed

4 files changed

+28
-12
lines changed

src/library/base/man/attr.Rd

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
% File src/library/base/man/attr.Rd
22
% Part of the R package, https://www.R-project.org
3-
% Copyright 1995-2017 R Core Team
3+
% Copyright 1995-2025 R Core Team
44
% Distributed under GPL 2 or later
55

66
\name{attr}
@@ -25,7 +25,9 @@ attr(x, which) <- value
2525
\details{
2626
These functions provide access to a single attribute of an object.
2727
The replacement form causes the named attribute to take the value
28-
specified (or create a new attribute with the value given).
28+
specified (or create a new attribute with the value given), unless
29+
the object is \code{\link{NULL}}, a \code{\link{symbol}} (aka \sQuote{\code{name}})
30+
or a \code{\link{primitive}} function.
2931

3032
The extraction function first looks for an exact match to \code{which}
3133
amongst the attributes of \code{x}, then (unless \code{exact = TRUE})
@@ -67,5 +69,8 @@ attr(x, which) <- value
6769
# create a 2 by 5 matrix
6870
x <- 1:10
6971
attr(x,"dim") <- c(2, 5)
72+
73+
S <- sum
74+
try( attr(S, "foo") <- NA ) # no longer possible to mutate primitive functions
7075
}
7176
\keyword{attribute}

src/library/base/man/attributes.Rd

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
% File src/library/base/man/attributes.Rd
22
% Part of the R package, https://www.R-project.org
3-
% Copyright 1995-2018 R Core Team
3+
% Copyright 1995-2025 R Core Team
44
% Distributed under GPL 2 or later
55

66
\name{attributes}
@@ -20,13 +20,15 @@ attributes(x) <- value
2020
mostattributes(x) <- value
2121
}
2222
\arguments{
23-
\item{x}{any \R object.}
23+
\item{x}{any \R object; for the replacement functions, not a
24+
\code{\link{symbol}} (aka \sQuote{\code{name}}) nor a \code{\link{primitive}} function.}
2425
\item{value}{an appropriate named \code{\link{list}} of attributes, or
2526
\code{NULL}.}
2627
}
2728
\details{
28-
Unlike \code{\link{attr}} it is not an error to set attributes on a
29-
\code{NULL} object: it will first be coerced to an empty list.
29+
Unlike \code{\link{attr}} it is currently not an error to set attributes
30+
on a \code{NULL} object: it will first be coerced to an empty
31+
\code{\link{list}}.
3032
3133
Note that some attributes (namely \code{\link{class}},
3234
\code{\link{comment}}, \code{\link{dim}}, \code{\link{dimnames}},

src/main/attrib.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,18 @@ static SEXP installAttrib(SEXP vec, SEXP name, SEXP val)
353353
{
354354
SEXP t = R_NilValue; /* -Wall */
355355

356-
if(TYPEOF(vec) == CHARSXP)
356+
switch(TYPEOF(vec)) {
357+
case CHARSXP:
357358
error("cannot set attribute on a CHARSXP");
358-
if (TYPEOF(vec) == SYMSXP)
359-
error(_("cannot set attribute on a symbol"));
359+
break;
360+
case SYMSXP:
361+
case BUILTINSXP:
362+
case SPECIALSXP:
363+
error(_("cannot set attribute on a '%s'"), R_typeToChar(vec));
364+
default:
365+
break;
366+
}
367+
360368
/* this does no allocation */
361369
for (SEXP s = ATTRIB(vec); s != R_NilValue; s = CDR(s)) {
362370
if (TAG(s) == name) {
@@ -1348,8 +1356,6 @@ attribute_hidden SEXP do_attributesgets(SEXP call, SEXP op, SEXP args, SEXP env)
13481356
/* Do checks before duplication */
13491357
if (!isNewList(attrs))
13501358
error(_("attributes must be a list or NULL"));
1351-
if (isPrimitive(object))
1352-
error(_("Cannot modify attributes on primitive functions"));
13531359
int i, nattrs = length(attrs);
13541360
if (nattrs > 0) {
13551361
names = getAttrib(attrs, R_NamesSymbol);

tests/reg-tests-1e.R

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1916,7 +1916,10 @@ stopifnot(is.primitive(sum))
19161916
msum <- sum
19171917
assertErrV(void <- structure(sum, foo = TRUE))
19181918
assertErrV(attributes(msum) <- list(foo = NA))
1919-
## both examples, the first a special case of the 2nd, did not error, but *modified* the base::sum primitive
1919+
## a few days later: Disable working via attr(*, "<name>") <- value as well:
1920+
assertErrV( attr(msum, "foo") <- NA )
1921+
stopifnot(identical(sum, msum), is.null(attributes(msum)))
1922+
## all 3 examples, the first a special case of the 2nd, did not error, but *modified* the base::sum primitive
19201923

19211924

19221925

0 commit comments

Comments
 (0)