Mark Phippard <markp...@gmail.com> writes:

> On Tue, Dec 20, 2011 at 2:42 PM, Philip Martin
> <philip.mar...@wandisco.com> wrote:
>> Mark Phippard <markp...@gmail.com> writes:
>>
>>> We have had a few users report a weird error that looks like they are
>>> getting an ArrayIndexOutOfBoundsException except that it appears that
>>> it is coming out of the native code.  This happens during an update
>>> operation.  I am going to paste some of the native code in here, in
>>> case anyone sees anything in the array handling that looks wrong.  The
>>> use of ++i instead of i++ looks odd to me, but I am not a C++
>>> programmer and the general code patterns.
>>
>> ++i and i++ are equivalent in this case, and likely to be identical
>> after optimisation.
>>
>>>
>>>     const apr_array_header_t *array = targets.array(subPool);
>>>     SVN_JNI_ERR(targets.error_occured(), NULL);
>>>     SVN_JNI_ERR(svn_client_update4(&revs, array,
>>>                                    revision.revision(),
>>>                                    depth,
>>>                                    depthIsSticky,
>>>                                    ignoreExternals,
>>>                                    allowUnverObstructions,
>>>                                    TRUE /* adds_as_modification */,
>>>                                    makeParents,
>>>                                    ctx, subPool.getPool()),
>>>                 NULL);
>>>
>>>     JNIEnv *env = JNIUtil::getEnv();
>>>     jlongArray jrevs = env->NewLongArray(revs->nelts);
>>>     if (JNIUtil::isJavaExceptionThrown())
>>>         return NULL;
>>>     jlong *jrevArray = env->GetLongArrayElements(jrevs, NULL);
>>>     if (JNIUtil::isJavaExceptionThrown())
>>>         return NULL;
>>>     for (int i = 0; i < revs->nelts; ++i)
>>>     {
>>>         jlong rev = APR_ARRAY_IDX(revs, i, svn_revnum_t);
>>>         jrevArray[i] = rev;
>>>     }
>>>     env->ReleaseLongArrayElements(jrevs, jrevArray, 0);
>>
>> Do we need to consider ReleaseLongArrayElements raising an exception?
>>
>> Everything else looks OK.
>>
>>>     return jrevs;
>
>
> The Subclipse code always calls this API with an array of exactly one
> path.  I only see two arrays in this code.  The list of paths to
> update, and the return value for revisions.

I suppose you could add a check to the bindings code to test whether
revs->nelts == array->nelts == 1.

> Is there ever a scenario where passing a single path to the API should
> return an array of 68ish revisions?  Our code only ever looks at the
> first revision returned since our API wrapper only accepts a single
> path.

I'm a bit confused, I thought you stated that looking at element 68
caused a ArrayIndexOutOfBoundsException?  Now you say you only ever look
at element 0?

The size of the jrevs array is set by the call the NewLongArray.  If
revs->nelts was 68 at that point then the Java array would have 68
elements.  The element values might be junk, but they would exist so I
don't see how that would lead to ArrayIndexOutOfBoundsException.

I suppose some other thread could clear the parent of the subpool
between the call to NewLongArray and the for loop.  That would allow the
memory used by revs->nelts, which is allocated from the subpool, to be
reused.  Then the value of revs->nelts might be "wrong" during the for
loop and that might corrupt the heap.

Or I suppose it could be unrelated heap corruption that happens to touch
the memory used by the Java array.

-- 
uberSVN: Apache Subversion Made Easy
http://www.uberSVN.com

Reply via email to