Holy cow, I wrote a book!
A customer had a debug trace log and needed some help interpreting it. The trace log was generated by an operating system component, but the details aren't important to the story.
I've attached the log file. I think the following may be part of the problem. [07/17/2005:18:31:19] Creating process D:\Foo\bar\blaz.exe [07/17/2005:18:31:19] CreateProcess failed with error 2 Any ideas? Thanks, Bob Smith Senior Test Engineer Tailspin Toys
I've attached the log file. I think the following may be part of the problem.
[07/17/2005:18:31:19] Creating process D:\Foo\bar\blaz.exe [07/17/2005:18:31:19] CreateProcess failed with error 2
Any ideas?
Thanks, Bob Smith Senior Test Engineer Tailspin Toys
What struck me is that Bob is proud of the fact that he's a Senior Test Engineer, perhaps because it makes him think that we will take him more seriously because he has some awesome title.
But apparently a Senior Test Engineer doesn't know what error 2 is. There are some error codes that you end up committing to memory because you run into them over and over. Error 32 is ERROR_SHARING_VIOLATION, error 3 is ERROR_PATH_NOT_FOUND, and in this case, error 2 is ERROR_FILE_NOT_FOUND.
ERROR_SHARING_VIOLATION
ERROR_PATH_NOT_FOUND
ERROR_FILE_NOT_FOUND
And even if Bob didn't have error 2 memorized, he should have known to look it up.
Error 2 is ERROR_FILE_NOT_FOUND. Does the file D:\Foo\bar\blaz.exe exist?
D:\Foo\bar\blaz.exe
No, it doesn't. -Bob
No, it doesn't.
-Bob
Bob seems to have shut off his brain and decided to treat troubleshooting not as a collaborative effort but rather as a game of Twenty Questions in which the person with the problem volunteers as little information as possible in order to make things more challenging. I had to give Bob a nudge.
Can you think of a reason why the system would be looking at D:\Foo\bar\blaz.exe? Where did you expect it to be looking for blaz.exe?
blaz.exe
This managed to wake Bob out of his stupor, and the investigation continued. (And no, I don't remember what the final resolution was. I didn't realize I would have to remember the fine details of this support incident three years later.)
A colleague of mine showed me some code from a back-end program on a web server. Fortunately, the company that wrote this is out of business. Or at least I hope they're out of business!
size = 16384; while (size && IsBadReadPtr(buffer, size)) { size--; }
Back in the old days, programmers were assumed to be smart and hardworking. Windows didn't provide functions for things that programs could already do on their own. Windows worried about providing functionality for thing that programs couldn't do. That was the traditional separation of responsibilities in operating systems of that era. If you wanted somebody to help you with stuff you could in principle do yourself, you could use a runtime library or a programming framework.
You know how to open files, read them, and write to them; therefore, you could write your own file copy function. You know how to walk a linked list; the operating system didn't provide a linked list management library. There are apparently some people who think that it's the job of an operating system to alleviate the need for implementing them yourself; actually that's the job of a programming framework or tools library. Windows doesn't come with a finite element analysis library either.
You can muse all you want about how things would have been better if Windows had had an installer library built-in from the start or even blame Windows for having been released without one, but then again, the core unix operating system doesn't have an application installer library either. The unix kernel has functions for manipulating the file system and requesting memory from the operating system. Standards for installing applications didn't arrive until decades later. And even though such standards exist today (as they do in Windows), there's no law of physics preventing a vendor from writing their own installation program that doesn't adhere to those standards and which can do anything they want to the system during install. After all, at the end of the day, installing an application's files is just calling creat and write with the right arguments.
creat
write
Commenter Archangel remarks, "At least if the ACL route had been taken, the installers would have had to be fixed - and fixed they would have been, when the vendors realised they didn't run on XP."
These arguments remind me of the infamous "Step 3: Profit" business plan of the Underpants Gnomes.
It's that step 2 that's the killer. Because the unwritten step 2 is "All applications stop working until the vendors fix them."
Who's going to fix the the bill-printing system that a twelve-year-old kid wrote over a decade ago, but which you still use to run your business. (I'm not making this up.) What about that shareware program you downloaded three years ago? And it's not just software where the authors are no longer available. The authors may simply not have the resources to go back and update every single program that they released over the past twenty years. There are organizations with thousands of install scripts which are used to deploy their line-of-business applications. Even if they could fix ten scripts a day, it'd take them three years before they could even start thinking about upgrading to the next version of Windows. (And what about those 16-bit applications? Will they have to be rewritten as 32-bit applications? How long will that take? Is there even anybody still around who understands 16-bit Windows enough to be able to undertake the port?)
There seemed to be a great deal of disbelief that anybody would hard-code the path to Notepad.
Here's one example and here's another.
There's a large class of problems that go like this:
I'm running Program X, and when I tell it to view the error log, I get this error message: CreateProcess of "C:\Windows\Notepad.exe errorlog.txt" failed: error 2: The system cannot find the file specified. What is wrong and how do I fix it?
CreateProcess of "C:\Windows\Notepad.exe errorlog.txt" failed: error 2: The system cannot find the file specified.
Obviously, the file C:\Windows\Notepad.exe is missing. But how can that be? Well, Windows Server 2008 bit the bullet and removed one of the copies of Notepad. Once you learn this, troubleshooting the above problem becomes a simple exercise in psychic debugging.
C:\Windows\Notepad.exe
My psychic powers tell me that you're running Windows Server 2008. The Notepad program no longer exists in the Windows directory; it's now in the system directory. Find the setting for your program that lets you change the program used for viewing error logs and tell it to use C:\Windows\System32\Notepad.exe.
C:\Windows\System32\Notepad.exe
Of course, this tip works only if the program permits you to change the program used for viewing error logs. If they hard-code the path, then you'll have to find some other workaround. (For example, you might try using the CorrectFilePaths shim.)
I received a brochure in the mail for a local church which says that it's "full of people just like you."
Everybody in the brochure is white.
"You'll fit right in!" it concludes.
Bonus chatter: My friends guessed that perhaps the church members are all computer programmers who work at Microsoft and speak Swedish badly.
My young niece received the game Candy Land and wants to play it several times a day. Naturally, I am frequently drafted as an opponent.
I discovered that my niece cheats rampantly. Sometimes, she will advance three green squares instead of two. Or if a yellow card will take her to a licorice square (lose a turn), she will ignore it and go to the yellow square after that. But the best cheating takes place when she draws a pink location card which sends her backward.
My niece is always careful to draw the card and turn it so only she can see what it is. If the card is an unfavorable one, she will hide it under her knee and tell me, "Hey, go play with the baby for a little bit." I naturally oblige, and when I return after a few seconds, her location card has magically changed into a two-green card or something else comparatively harmless.
I found this change in personality surprising. In earlier encounters, she was happy to share in the winning. In fact, sometimes, while resetting a game after winning, she would say, "Okay, you win this next one." And she would let me win!
Anyway, after one of the games of Candy Land which she won (actually, she wins every game), I declined to play another because she was cheating. She pled with me, "Okay, this time, no cheating." I agreed to play another game.
In the game that followed, she cheated five times, even more than in the previous game.
She wanted to play again. "I'm serious, I'm not cheating now."
In the "I'm serious, no cheating" game, there was, I will concede, technically no cheating during game play.
Instead, she stacked the deck.
Perhaps I need to study up on how to cheat at Candy Land. I could mark the cards or go for one of the more advanced methods.
Bonus chatter
Commenter Yuhong Bao suggests, "How about not granting debug privileges on the user? This will make bypassing the protection impossible."
This is such a great idea that Windows has worked that way for years.
Normal non-administrative users do not have debug privilege. They can only debug processes that they already have PROCESS_ALL_ACCESS to. In other words, non-administrative users can only pwn processes that they already pwn. No protection is being bypassed since you had full access in the first place.
PROCESS_ALL_ACCESS
The SeDebugPrivilege allows you to debug any process, even those to which you do not have full access. This is clearly dangerous, which is why it's not granted to non-administrative users by default.
Yuhong Bao also suggests, "How about separating the dangerous activities from the non-dangerous activities, or better, only allowing approved programs to do the dangerous activities?" (Where dangerous activities are defined as things that modify the program behavior.) I'm assuming this is discussing limiting the capabilities of SeDebugPrivilege, since in the absence of SeDebugPrivilege, the scope of your abilities is limited to things you already had the ability to do anyway; debugging didn't add anything new.
But even if you limited SeDebugPrivilege to nondestructive actions, you can still lose the farm. This imaginary SeLimitedDebugPrivilege would still let you read a target process's memory, which means you can do things like steal passwords and snoop on the activities of other users.
The last suggestion is to "only allow approved programs to do the dangerous activities." Again, I'm assuming this is discussing limiting the capabilities of SeDebugPrivilege, because without SeDebugPrivilege there is no new danger. But even in that limited context, what is an "approved program"? Approved by whom?
Must the program be digitally signed by Microsoft? I suspect people who write debuggers which compete with, say, Microsoft Visual Studio, would be upset if they had to submit their debugger to Microsoft for approval. And what are the requirements for receiving this approval? Does the debugger have to pass some battery of tests like WHQL? There are already plenty of readers of this Web site who reject WHQL as useless. Would this "debugger certification" also be useless?
Or maybe approval consists of merely being digitally signed at all? There are plenty of readers of this Web site who object to the high cost of obtaining a digital certificate (US$399; I don't think the $99 discounted version works for code signing.) And there are also plenty of readers who consider code signing to be payola and designed to maximize profit rather than effectiveness.
Or do you mean that the program needs to be listed in some new registry key called something like Approved Debuggers? Then what's to stop a rogue program from just auto-approving itself by writing to the Approved Debuggers registry key on its own?
Approved Debuggers
But then again, all this is a pointless discussion once you realize that SeDebugPrivilege is granted by default only to administrators. And since administrators already pwn the machine, there's no protection that SeDebugPrivilege bypasses: You already bypassed it when you became an administrator.
Some follow-up remarks to my old posting on rotating a two-dimensional array:
Some people noticed that the article I linked to purporting to rotate the array actually transposes it. I was wondering how many people would pick up on that.
I was surprised that people confused rotating an array (or matrix) with creating a rotation matrix. They are unrelated operations; the only thing they have in common are the letters r-o-t-a-t-i. A matrix is a representation of a linear transformation, and a rotation matrix is a linear transformation which rotates vectors. In other words, applying the rotation matrix to a vector produces a new vector which is a rotated version of the original vector. The linear transformation is a function of one parameter: It takes a vector and produces a new vector. A rotation matrix is a matrix which rotates other things. Whereas rotating an array is something you do to the array. The array is the thing being rotated, not the thing doing the rotating. It didn't even occur to me that people would confuse the two. It's the difference a phone dial and dialing a phone.
Showing that you cannot rotate an array via matrix multiplication is straightforward. Suppose there were a matrix R which rotated an array (laid out in the form of a matrix) clockwise. The result of rotating the identity matrix would be a a matrix with 1's along the diagonal from upper right to lower left, let's call that matrix J. Then we have RI = J, and therefore R = J. Now apply R to both sides: RRI = RJ = I and therefore R² = I. But clearly rotating clockwise twice is not the identity for n ≥ 2. (Rotating clockwise twice is turning upside-down.)
A more mechanical way to see this is to take the equation R = J and show that J does not perform the desired operation; just try it on the matrix with 1 in the upper left entry and 0's everywhere else.
And since it's one of those geeky math pastimes to see how many differents proofs you can come up with for a single result, the third way to show that rotation cannot be effected by matrix multiplication is to observe that the transformation is not linear. (That's the magical algebra-theoretical way of showing it, which is either so obvious you can tell just by looking at it or so obscure it defies comprehension.) [The transformation viewed as a transformation on matrices rather than a transformation on column vectors is indeed linear, but the matrix for that would be an n² × n² matrix, and the operation wouldn't be matrix multiplication, so that doesn't help us here.]
Bonus chatter: Mind you, you can do better than O(n²) if you change the rules of the problem. For example, if you allow pretending to move the elements, say by overloading the [] operator, then you can perform the rotation in O(1) time by just writing a wrapper:
[]
struct IArray { virtual int& Element(int x, int y) = 0; virtual ~IArray() = 0; }; class RotatedArray : public IArray { public: RotatedArray(IArray *p) : m_p(p) { } ~RotatedArray() { delete m_p; } int& Element(int x, int y) { return m_p->Element(y, x); } private: IArray *m_p; }; void RotateInPlace(IArray *& p, int N) { p = new RotatedArray(p); }
This pseudo-rotates the elements by changing the accessor. Cute but doesn't actually address the original problem, which said that you were passed an array, not an interface that simulates an array.
Seventh grade students (ages 12 to 13, roughly) were asked to write an essay on what success is and how you know when you've achieved it. The assignment was given under standardized test conditions: 90 minutes with nothing but pencil and paper, with an additional hour available upon request. (In practice, few students ask for the extra hour.)
Remember, these are only the funny sentences/excerpts. Do not assume that all students write like this.
On the nature of success
Recognizing success
Steps which do not lead to success
The fleeting nature of success
The recipe for success
Personal stories of success
Future success
Examples of other successful people
Out of about 300 students, the number who cited Bill Gates as a successful person: 17.
Jonathan Wilson asks why the clipboard APIs still require GlobalAlloc and friends. Why is there not a SetClipboardDataEx or something that does what SetClipboardData does but without needing to call GlobalAlloc?
SetClipboardDataEx
SetClipboardData
GlobalAlloc
Okay, here's your function:
HANDLE SetClipboardDataEx(UINT uFormat, void *pvData, DWORD cbData) { if (uFormat == CF_BITMAP || uFormat == CF_DSPBITMAP || uFormat == CF_PALETTE || uFormat == CF_METAFILEPICT || uFormat == CF_DSPMETAFILEPICT || uFormat == CF_ENHMETAFILE || uFormat == CF_DSPENHMETAFILE || uFormat == CF_OWNERDISPLAY) { return NULL; // these are not HGLOBAL format } HANDLE hRc = NULL; HGLOBAL hglob = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, cbData); if (hglob) { void *pvGlob = GlobalLock(hglob); if (pvGlob) { CopyMemory(pvGlob, pvData, cbData); GlobalUnlock(hglob); hRc = SetClipboardData(uFormat, hglob); } if (!hRc) { GlobalFree(hglob); } } return hRc; }
Whoop-dee-doo.
Historically, Windows doesn't go out of its way to include functions like this because you can easily write them yourself, or you can at least find a framework library that did it for you. Windows focused on doing the things that only Windows could do, providing you the building blocks with which you can create your own programs.
Besides, the classic clipboard is so old-school. The OLE clipboard provides a much richer interface, where you can generate data dynamically (for example as a stream) and expose it in formats other than just a chunk of bytes. Since SetClipboardData is old-school, if the window manager folks had written a function like SetClipboardDataEx, people would instead have asked the not unreasonable question, "Why did you bother to write a function that provides no essential new functionality to an old interface that was supplanted over a decade ago?"