Laden...

Stacktrace unvollständig vom Fremdsystem

Erstellt von RED-BARON vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.472 Views
R
RED-BARON Themenstarter:in
74 Beiträge seit 2006
vor 5 Jahren
Stacktrace unvollständig vom Fremdsystem

Hallo,

2 Fehlermeldungen und meine Frage vorweg:
Ist es möglich, dass der Stacktrace aus System.Linq auf einem Produktionssystem nicht ausgegeben wird. Wenn ja - unter welchen Bedingungen ist dies denkbar ?

Meldung Fremdsystem ( StackTrace unvollständig ??? )

Progr.: ExecuteModifyCommand
Context:
Ausnahme: System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
bei ProjektName.ViewModel.ExecutePasteCommand(Object arg) in C:\ProjektName\ViewModels\ViewModel.cs:Zeile 3030.
bei Cinch.SimpleCommand`2.Execute(T2 parameter)

Meldung Eigensystem

Progr.: <ExecuteModifyCommand>b__1be
Context:
Ausnahme: System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
bei ProjektName.ViewModel.<>c__DisplayClass1ce.<ExecuteModifyCommand>b__1be(ViewModel p) in D:\ProjektName\ViewModels\ViewModel.cs:Zeile 3029.
bei System.Linq.Enumerable.<>c__DisplayClass6_01.&lt;CombinePredicates&gt;b__0(TSource x) bei System.Linq.Enumerable.WhereEnumerableIterator1.MoveNext()
bei ProjektName.ViewModel.ExecuteModifyCommand(Object arg) in D:\ProjektName\ViewModels\ViewModel.cs:Zeile 3030.
bei Cinch.SimpleCommand`2.Execute(T2 parameter) in D:\ProjektName\CinchV2\Commands\SimpleCommand.cs:Zeile 61.

der dazugehörige Quellcode:


2029:	var x = X.Where(p => p.Nr == row.Nr);
3030:	foreach (var item in x)  // NULL-Ref-Exception 
3031	{ ... }

**
Ich habe einiges ausprobiert und konnte eine NullReferenceException nur dadurch erzwingen, dass "row" zu null gesetzt wird. Was im Programmablauf
durchaus eine realistische Annahme ist - jedoch nicht berücksichtigt wurde !**

Im Quellcode von .NET habe ich nachgesehen
https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs


public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
            if (source == null) throw Error.ArgumentNull("source");
            if (predicate == null) throw Error.ArgumentNull("predicate");
            if (source is Iterator<TSource>) return ((Iterator<TSource>)source).Where(predicate);
            if (source is TSource[]) return new WhereArrayIterator<TSource>((TSource[])source, predicate);
            if (source is List<TSource>) return new WhereListIterator<TSource>((List<TSource>)source, predicate);
            return new WhereEnumerableIterator<TSource>(source, predicate);
        }

Es wird effektiv immer ein Objekt zurückgegeben, was nicht null sein kann.

Weiter habe ich mit Tests wie diesem versucht die Ausnahme zu erzwingen was nicht gelang. Was mich nicht verwundert, wenn innerhalb von foreach die Referenz auf die zu durchlaufende Enumeration gehalten wird.


        [TestMethod, ExpectedException(typeof(NullReferenceException))]
        public void EnumerableNullReferenceException()
        {
            var _List = new List<object>();
            _List.Add(null);
            _List.Add(null);

            var results = _List.Where(p => p == null);
            foreach (var item in results)
            {
                results = null;
            }
        }

Herzlichen Dank !!!
Ein einfaches "JA" auf meine Eingangs gestellte Frage - würde mir weiterhelfen.

1.040 Beiträge seit 2007
vor 5 Jahren

Du suchst den Fehler da, wo er nicht ist. 😉

Wenn row null ist, kannst du nicht auf Member der row zugreifen - machst du es doch, dann knallt es. Unanhängig von LinQ bzw. dem Where.

R
RED-BARON Themenstarter:in
74 Beiträge seit 2006
vor 5 Jahren

Danke ich nehme keine Pillen 😃

das würde einschließen, dass die PDB nicht zum EXE passt - das läßt sich leicht
provozieren und mit Glück erhalte ich einen Stacktrace ohne Angabe von Zeilen oder komplett Schrott.

Das Problem ist mir wohl bekannt und würde es zunächst einmal ausschließen.
Im Beitrag habe ich die Stacktraces etwas vereinfacht um für fremde Augen es lesbarer zu machen. Im realen Fall vergleiche ich schon die passenden Quellcodestände zur ausgelieferten Exe.

und auch da komme ich eben auf die Zeile

foreach (var item in x)

unmittelbar nach

var x = X.Where(p => p.Nr == row.Nr);

Im Normalfall sollte "row" nicht null sein - dieser Fall lässt sich aber häßlich reproduzieren - deswegen setze ich es im Code gleich selbst auf null !
Ergebnis: es knallt nicht in

var x = X.Where(p => p.Nr == row.Nr);

sondern wie im Fehler auch hier

foreach (var item in x)

Mir ist das auch logisch. Das was ich probiere und die Folge davon.

Aber was Du schreibst ist nicht ganz von der hand zu weisen, denn es gibt sehr wohl auch von anderen Produktionssystemen Fehlermeldungen die den Stacktrace bis System.Linq ausweisen - allerdings auch mal mit und mal ohne Zeilenangaben.

Fehlermeldung:
Ausnahme: System.ArgumentNullException: Value cannot be null.
Parameter name: source
at System.Linq.Enumerable.Select[TSource,TResult](IEnumerable1 source, Func2 selector)
at System.Linq.Enumerable.Min[TSource,TResult](IEnumerable1 source, Func2 selector)

5.657 Beiträge seit 2006
vor 5 Jahren

Hi RED-BARON,

der Fehler tritt an dieser Stelle auf:

p.Nr == row.Nr

Mit deiner Änderung verhinderst du nur, daß die Exception ausgelöst wird.

Ausgeführt wird der Code aber erst beim Durchlaufen der foreach-Schleife. Da ist der StackTrace auch sehr eindeutig. Deine eigentliche Frage kann ich daher nicht nachvollziehen.

Weeks of programming can save you hours of planning

1.040 Beiträge seit 2007
vor 5 Jahren

Abschließend sei noch gesagt, dass der von dir ausgedachte Testfall mit deinem Problem nichts gemein hat.

var results = _List.Where(p => p == null);

ist was komplett anderes als

var irgendeineKlasse = null;
var results = _List.Where(p => p == irgendeineKlasse.IrgendeinMember);

Im ersten Fall werden alle Elemente, die null sind, ermittelt. Gibt es keine Treffer, hast du eine leere Ergebnismenge. Das foreach macht dann einfach nix.
Im zweiten Fall soll auf einen Member einer Instanz zugegriffen werden, die null ist. Das knallt natürlich.

Probiere das mal im Unit-Test aus, dann siehst du auch den "Zeilenversatz" in dem der Fehler auftritt.

W
955 Beiträge seit 2010
vor 5 Jahren

Vllt solltest Du auch keine Klassen bauen die über 3000 LOC haben...

148 Beiträge seit 2013
vor 5 Jahren

Ganz kurz, um es deutllich zu machen:

var x = X.Where(p => p.Nr == row.Nr);

Wird zunächst erstmal nicht ausgeführt. Es ist zu diesem Zeitpunkt erstmal eine Expression. Erst wenn auf die Liste tasächlich zugegriffen wird, wird die Liste materialisiert.

Das würde z.B. durch ein .ToList() oder .ToArray() passieren, oder aber durch ein Durchlaufen der Liste wie in deinem Beispiel z.B.:

foreach (var item in x)  // NULL-Ref-Exception

Es macht also durchaus Sinn, dass der Fehler in dieser Zeile auftritt, da erst dort deine Expression von einer Zeile vorher ausgeführt wird. Da dort deine "row" null ist, bekommst du in der foreach Zeile einen Fehler.

Grüße

R
RED-BARON Themenstarter:in
74 Beiträge seit 2006
vor 5 Jahren

Vllt solltest Du auch keine Klassen bauen die über 3000 LOC haben...

nicht mein Code - Kollege hat den Fehler Anfang Februar als gefixt dokumentiert und gestern erst wieder - die einzige Änderung an der Datei war, dass mein Kommentar an der Zeile entfernt wurde !

Hi RED-BARON,

der Fehler tritt an dieser Stelle auf:

p.Nr == row.Nr  

Mit deiner Änderung verhinderst du nur, daß die Exception ausgelöst wird.

Ausgeführt wird der Code aber erst beim Durchlaufen der foreach-Schleife. Da ist der StackTrace auch sehr eindeutig. Deine eigentliche Frage kann ich daher nicht nachvollziehen.

Mit der Änderung wollte ich erzwingen und nichts verhindern - ich vermute an der Stelle knallt es - einzig der Stacktrace fehlt mir um es "sehen" zu können.

Pille hat freilich Recht:
(p => p == null); hat nichts mit dem realen Fall zu tun. Im Test wollte ich sehen was passiert wenn:

foreach (var item in results)
{
      results = null;
}

Habe mehrere testfälle erstellt. Und jetzt eine Konsolenanwendung die ich mal versuche am Produktionsrechner auszuführen und bei der "row" null ist. Wenn da System.Linq im Stacktrace vorkommt ... liegt der Fehler womöglich doch wo ganz anders.

Danke an alle die mitgehirnt haben 😃

@Geaz : 100% ( meine aktuelle Annahme ! ) .... der Beweis fehlt mir nur noch 😃 - da bin ich aber dran

148 Beiträge seit 2013
vor 5 Jahren

Kannst du relativ einfach testen. Mach einfach:

var x = X.Where(p => p.Nr == row.Nr).ToList();

Dann wird es direkt in der Zeile knallen wenn row == null ist.

1.040 Beiträge seit 2007
vor 5 Jahren

Wenn da System.Linq im Stacktrace vorkommt ... liegt der Fehler womöglich doch wo ganz anders.

Wenn da System.Linq im Stacktrace vorkommt (was es tun wird), liegt der Fehler trotzdem in der Expression bzw. daran, dass row null ist. Linq ist hier nur Mittel zum Zweck, um den Fehler auszulösen. Es knallt auch, wenn du z.B.

var test = row.Nr;

schreibst. Wenn du über Linq darauf zugreifst, ist es normal, dass du das auch im Stacktrace siehst.

Ansonsten kannst du den Fehler auch ganz einfach an deinem Rechner nachstellen inkl. Stacktrace und Co. - dafür brauchst du nicht an einen anderen Rechner. Geht sogar ganz einfach beim Debuggen.

Ein Aufwand, um eine fehlende Prüfung auf null hinzuzufügen.

R
RED-BARON Themenstarter:in
74 Beiträge seit 2006
vor 5 Jahren

da bin ich wieder, test.exe auf Produktionsrechner zeigt - kompletten - Stacktrace.

Wenn da System.Linq im Stacktrace vorkommt (was es tun wird), liegt der Fehler
trotzdem in der Expression

richtig. so isses ja auch ( gewollt gewesen ).

Warum die test.exe den kompletten erwarteten Stacktrace ausgibt - mit Enumerable.MoveNext ... aber die Anwendung.exe nicht - hm gute Frage.

Evtl. bei an die 4000LOC ... kommt vll. mal was durcheinander^^ und tatsächlich ist der Fehler in ganz anderer Zeile.

Es gibt kein vernünftigen Grund, warum System.Linq Symbole nur in einer kleinen
test.exe aufgelöst werden können sollen und in einer 10 MB.exe nicht.

Antwort Eingangsfrage: Nein. 😃

Zurück auf Start.

1.040 Beiträge seit 2007
vor 5 Jahren

Zurück auf Start.

Hast du den Bug jetzt einfach behoben?