Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

When IterableWrapper iterates up to the middle of list, System.AccessViolationException occurs.#2280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
lostmsu merged 1 commit intopythonnet:masterfromJakeJP:master
Nov 7, 2023

Conversation

JakeJP
Copy link
Contributor

System.AccessViolationException occurs when iteration quits in the middle of list before reaching the end.

Environment

  • Pythonnet version: 3.0.3
  • Python version: 3.12.0
  • Operating System: Windows 11
  • .NET Runtime: .NET Framework 4.8

Reproduce the problem

I'm trying to pass a list from python to .NET method via List Codec.

mylist= ["a","b","c"]dotnet.method(mylist )

Conversion(decode) is successful and mylist is wrapped byListWrapper.
.NET code receives the list like this.

voidmethod(IList<string>mylist){mylist.First( s=>s=="b");// <- here the crash with System.AccessViolationException}

Using Enumerator ofmylist, if enumerated to the end of the list, nothing bad happens.
However if iteration didn't go to the end of the list, AccessViolationException is thrown.
This case happens in the following code:

mylist.First( s=>s=="b");// iteration stops at the 2nd item

similarly

foreach(variteminmylist){if(item=="b")break;// iteration stops at the 2nd item}mylist.Contains("b");// iteration stops at the 2nd itemmylist.Any( s=>s=="b");// iteration stops at the 2nd item

The following code doesn't throw exception becuase it always iterates to the end of the list.

mylist.ToList();mylist.ToArray();

Exception occurs because PyIter(ator) object is Dispose(d) outside of GIL protection only when iteration ends before reaching the end ( before MoveNext() returns null ).
In such a case, code process just slips out of GIL enclosure as the nature of C# scope and yield return and break.

solution for now

original code is like this:

publicIEnumerator<T>GetEnumerator(){PyIteriterObject;using(Py.GIL()){iterObject=PyIter.GetIter(pyObject);}usingvar_=iterObject;while(true){usingvarGIL=Py.GIL();if(!iterObject.MoveNext()){iterObject.Dispose();break;}yieldreturniterObject.Current.As<T>()!;}}

using var _ = iterObject; above the while loop is the problematic line.
Before iteration reaches the end, the executing process is somewhere out of theusing scope.
When c# caller process stops iteration(Enumeration) for some reason, c# suddely calls
using var _ = iterObject; 's closing process which is iterObject.Dispose().
But here iterObject is not inside of GIL() protection. This is why exception occurs.
Solution is to make sure iterObject.Dispose() is always inside of GIL protection and
always executed whatever the caller process abandons the enumeration in the middle.

My suggestion is to use try catch pattern. Without catching any exception it may look odd. But this is one solution to make sure the execution of Dispose and GIL scope surrounding always.

publicIEnumerator<T>GetEnumerator(){PyIteriterObject;using(Py.GIL()){iterObject=PyIter.GetIter(pyObject);}try{while(true){usingvar_=Py.GIL();if(!iterObject.MoveNext()){break;}yieldreturniterObject.Current.As<T>()!;}}finally{usingvar_=Py.GIL();iterObject.Dispose();}}

@filmor
Copy link
Member

Great catch, thank you very much!

Copy link
Member

@lostmsulostmsu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Please, revert whitespace changes (wrong line breaks?)

@JakeJP
Copy link
ContributorAuthor

I amended the last commit with 'right' line breaks. Did it work propertly? Sorry I'm not used to this 'push request' workflow.

lostmsu reacted with thumbs up emoji

@lostmsulostmsu merged commiteef67db intopythonnet:masterNov 7, 2023
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@lostmsulostmsulostmsu approved these changes

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

3 participants
@JakeJP@filmor@lostmsu

[8]ページ先頭

©2009-2025 Movatter.jp