Jump to content
pyscripter

TThread always raises OS Errror

Recommended Posts

Guest

THe point is not i should use it like that or not, something has changed in the RTL and it should be invesitigated, for me i would know what had been changed.

 

I can confirm that threads created by CreateThead directly do have last error to 87,  (not always all threads )

So why and how Delphi RTL in older version was resetting the error code to 0 ?

Per your text and resources provided above this shouldn't happen, or there was call to an API resetted it to 0.

 

What does confuse me about that Wine test, is associating the 87 error with Windows 9x not NT.

 

 

 

Edited by Guest

Share this post


Link to post
Guest
35 minutes ago, Kas Ob. said:

I can confirm that threads created by CreateThead directly do have last error to 87,

Hold on that, this is more stranger than it looks, not all created threads are starting with last error =87

Delphi up to Seattle is 0, don't know about about any later versions, On Other side my FPC is giving me threads with 87 and also visual studio on 64bit.

Share this post


Link to post
19 minutes ago, Kas Ob. said:

Hold on that, this is more stranger than it looks

You are wasting both your own and our time but as usual here the discussion continues ad nauseam even though the question has been resolved in the very first answer to the original post.

 

I'm not sure how to explain it in a way that we haven't already tried. The value is meaningless, undocumented, random, forget about it ffs!
If you really want an answer to this question, I suggest you ask it on stackexchange. I'm sure it will get the answers it deserves... Add a link back to this discussion for bonus points.

Share this post


Link to post

If the perceived behavior over the last two decades was that a newly created thread always had a GetLastError of 0 and now it's all of sudden 87, there's absolutely nothing wrong with being curious.  Now, I don't think it was the perceived behavior of many as it's pretty very likely that most devs haven't really given this specific topic much thought - but, programmers are supposed to be curious and altered behavior (perceived or real) is an obvious red flag that we all have been forcibly trained over the years to instinctively question, regardless of the merits.  How many times have we gone a journey chasing a bug that "shouldn't ever happen" when it actually happens "every single time" once we figured out the "obvious"?  (only obvious of course after the fact)  Occasionally that journey takes a while and it's probably the case that every seasoned developer on the planet has taken that particular trip more than once - blunt force here isn't merited.

 

For fun, you could scan through Windows source code and see what's up behind the scenes and maybe even find out where 87 comes from, if you are curious. 

https://github.com/pustladi/Windows-2000
https://github.com/Zer0Mem0ry/ntoskrnl

 

 

  • Like 1

Share this post


Link to post
24 minutes ago, Darian Miller said:

there's absolutely nothing wrong with being curious

Agree. But your wise words are missing the point that the value of GetLastError is irrelevant in the context. Being curious about the value is pointless.

Those that are curious about it regardless could just examine the source, and when that turns up no clue, trace though CreateThread in a kernel debugger, but in the end it will amount to nothing because the value [drum roll] doesn't matter.

Share this post


Link to post
2 minutes ago, Anders Melander said:

Agree. But your wise words are missing the point that the value of GetLastError is irrelevant in the context. Being curious about the value is pointless.

Those that are curious about it regardless could just examine the source, and when that turns up no clue, trace though CreateThread in a kernel debugger, but in the end it will amount to nothing because the value [drum roll] doesn't matter.

No, it's absolutely not a pointless process just because of the topic.  If any value changes over time then being curious as to why is not only expected, but typically mandated.  This is the case even if your perception is wrong headed, as it's still your perception of reality.  The situation is even more difficult if its a very long held perception backed up by years of observation - even if that observation was faulty or insufficient.  Changing perception is not easy - and it's rarely changed by blunt force.

 

It's the developers' job to question facts that go against personal perception when analyzing problems. You don't need people hitting you over the head with their own (perceived or real) realities.  There is a process that needs to happen to alter a perception.  And it's a process that we all have gone through with different topics at different times in our careers.  I would assert it's a rather common occurrence that we should all be familiar with - and since that's the case why can't we just provide assistance on the journey and not try to end it quickly because we deem it to be an invalid destination?  Every trip is valid as long as there is something learned along the way. 

 

If you tried to be helpful and failed to penetrate someone's reality, then being quiet is sometimes the most help you can be so they can figure it out on their own.  As such, I'll certainly try to ignore any further comments in this thread.  Let's just please not turn this valuable resource into StackExchange.  I strongly object to that sort of behavior.  

 

  • Like 1

Share this post


Link to post

Just out of curiosity, I ran the same test program on the same Windows 10 virtual machine that has many versions of Delphi installed.

 

I built/ran the console project below multiple times on each Delphi version and they all resulted in a GetLastError of 0 when a new thread is spawned: 

Delphi 5, 7, 2005, 2009, 2010, XE, XE2, XE3, XE4, XE5, XE6, XE7, XE8, 10.0 Seattle, 10.1 Berlin.

 

Delphi 10.2.2 resulted in nearly equal results of 87 and 0 - it seems to switch nearly every time I build the project.

Delphi 10.3.3 results in 87 every time that I've built/ran the project. (>20 builds)

 

To narrow it down further, I have Delphi 10.2.0 installed on another VM with the same OS but different patch levels and it comes up with 0 every time.  I copied the .exe to the first VM and it always comes up with 0.  It does appear that in Delphi 10.2.1 (or 10.2.2) and later there is a change in this (useless) behavior.

 

So - even though it doesn't really matter as we should all agree by now that you should never call GetLastError unless you have a very specific context to do so otherwise the return value is less than useful, it is a tiny bit curious why this is happening only in Delphi 10.2.2 and later on the same OS with the same console project.  This is especially true since the code in System provided with Delphi 10.2 and 10.2.2 is seemingly identical when it comes to BeginThread.  And the code in System.Classes for ThreadProc seems identical but I didn't spend a lot time trying to figure out the differences.

 

Now it could absolutely be the case that the return value of 87, or 209232, or some other random number could easily occur on a Delphi 5 project and that I simply didn't execute it enough times to see a different result at the start of new thread.  However, I did build and execute the same code multiple times per version and there were 16 different versions of Delphi tested which all resulted in 0 every single time.  Perhaps it has to do with the size of the executable which seems to be ever-growing in subsequent releases of Delphi, who knows.  (and yes, who really cares)

 

It's of little value to anyone.  But if you are 'that one guy' with code stretching back 20+years to Delphi 5 which was somehow based on the incorrect assumption that a new thread started with a GetLastError of 0, that assumption started breaking a few years ago around Delphi 10.2.2 for some reason.  And since I wasted a little time myself chasing an invalid GetLastError recently based on someone else's code, it tripped my curiosity.

program TestGetLastError;
{$APPTYPE CONSOLE}
uses
  SysUtils, Classes, Windows;

type
  TMyThread = class(TThread)
    procedure Execute(); override;
  end;

procedure TMyThread.Execute();
begin
  WriteLn('GetLastError: ' + IntToStr(GetLastError));
end;

var
  x:TMyThread;
begin
  x := TmyThread.Create(False);
  Sleep(100);
  WriteLn('Hit enter to exit');
  ReadLn;
end. 

 

Now that my curiosity has been sufficiently satisfied, I can be done with this.  If someone else wants to go deeper, have at it.

 

cheers

 

  • Like 1

Share this post


Link to post
7 hours ago, Kas Ob. said:

So why and how Delphi RTL in older version was resetting the error code to 0 ?

It wasn't resetting the last-error at all.  That was, and always has been, the sole job of the OS to handle.  Whatever value was assigned to the last-error going into the RTL's ThreadProc(), that is the value that was still set when going into TThread.Execute().  And since the issue is reproducible in FPC and Visual Studio then it has nothing to do with Delphi's RTL at all.  Something has clearly changed internal to the OS itself, and you are not going to figure out what that is unless you trace into the OS's internal source code for yourself.

Quote

What does confuse me about that Wine test, is associating the 87 error with Windows 9x not NT.

That is because CreateThread() in Win9x does not allow the lpThreadId parameter to be NULL.  If it is, CreateThread() fails with ERROR_INVALID_PARAMETER (87).  That behavior was changed in NT4 onward to allow the lpThreadId parameter to be NULL, as the thread's ID is not typically needed by most users.  That restriction used to be documented:

Quote

lpThreadId

    Pointer to a 32-bit variable that receives the thread identifier.

    Windows NT: If this parameter is NULL, the thread identifier is not returned.

    Windows 95 and Windows 98: This parameter may not be NULL.

The restriction is no longer documented since Win9x is no longer supported:

Quote

lpThreadId

    A pointer to a variable that receives the thread identifier. If this parameter is NULL, the thread identifier is not returned.

 

Edited by Remy Lebeau

Share this post


Link to post

I wish I had that amount of spare time. I would enjoy more walks in the sun. *sigh*

  • Like 2

Share this post


Link to post
9 hours ago, Sherlock said:

I wish I had that amount of spare time. I would enjoy more walks in the sun. *sigh*

 

If that's aimed my way, I'll gladly take it.  I had more days than I can count starting at 8am and leaving work the next afternoon without sleep due to some crisis.  CTO for 22 years at a highly active software company where we were always under-staffed, over-promised, and working on a shoe string budget (privately held, one man owner for much of that time until I became a minority owner.)  I don't miss it, much.  (My wife certainly doesn't.)  The cool thing - we had 11 Delphi developers at one point and I was trying to hire another when the VC people showed up and bought us out.   But even with that many developers I left the place with 5,000 open tickets on the tech side of the house, after spending a solid year concentrating on getting it down from a much higher number.  (My custom built trouble-ticket system had 500,000+ tickets in its mid-2004 to late 2018 history.)

 

But my history suggests - take the walks.  There's always a crisis.  And if you want some useless code tested for fun, send it my way.  I may just do it.  :classic_smile:

 

  • Like 3

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×