From |kry|ov @end|ng |rom d|@root@org  Fri Apr  5 14:49:25 2024
From: |kry|ov @end|ng |rom d|@root@org (Ivan Krylov)
Date: Fri, 5 Apr 2024 15:49:25 +0300
Subject: [Rd] 
 Bug in out-of-bounds assignment of list object to expression()
 vector
In-Reply-To: <CAH54GbXMhcy+JFV7dfBLV0J7+YVoTBB8zdnQqEhrOogZPnM-yQ@mail.gmail.com>
References: <CAH54GbXMhcy+JFV7dfBLV0J7+YVoTBB8zdnQqEhrOogZPnM-yQ@mail.gmail.com>
Message-ID: <20240405154925.4df66c28@arachnoid>

On Fri, 5 Apr 2024 08:15:20 -0400
June Choe <jchoe001 at gmail.com> wrote:

> When assigning a list to an out of bounds index (ex: the next, n+1
> index), it errors the same but now changes the values of the vector
> to NULL:
> 
> ```
> x <- expression(a,b,c)
> x[[4]] <- list() # Error
> x
> #> expression(NULL, NULL, NULL)  
> ```
> 
> Curiously, this behavior disappears if a prior attempt is made at
> assigning to the same index, using a different incompatible object
> that does not share this bug (like a function)

Here's how the problem happens:

1. The call lands in src/main/subassign.c, do_subassign2_dflt().

2. do_subassign2_dflt() calls SubassignTypeFix() to prepare the operand
for the assignment.

3. Since the assignment is "stretching", SubassignTypeFix() calls
EnlargeVector() to provide the space for the assignment.

The bug relies on `x` not being IS_GROWABLE(), which may explain 
why a plain x[[4]] <- list() sometimes doesn't fail.

The future assignment result `x` is now expression(a, b, c, NULL), and
the old `x` set to expression(NULL, NULL, NULL) by SET_VECTOR_ELT(newx,
i, VECTOR_ELT(x, i)); CLEAR_VECTOR_ELT(x, i); during EnlargeVector().

4. But then the assignment fails, raising the error back in
do_subassign2_dflt(), because the assignment kind is invalid: there is
no way to put data.frames into an expression vector. The new resized
`x` is lost, and the old overwritten `x` stays there.

Not sure what the right way to fix this is. It's desirable to avoid
shallow_duplicate(x) for the overwriting assignments, but then the
sub-assignment must either succeed or leave the operand untouched.
Is there a way to perform the type check before overwriting the operand?

-- 
Best regards,
Ivan



[Rd] Bug in out-of-bounds assignment of list object to expression() vector
Ivan Krylov