Hi,
Thank you for posting the code. According to what I see now, the code makes a lot of checks to make sure that null pointer exceptions and out-of-range references do not occur. That's really nice. However, there is one line of code that really stopped me.
This line of code is strange. I don't know how your i686-gcc compiler doesn't report a warning at this line. This line should cause a warning even without -Wall and -Wextra!
This line of code,.... Well I don't really know how to express my feelings towards it... but it is really strange
It is like seeing an atom of Lithium (Li, with only 3 electrons) in a world full of Uranium
Despite all of these awkward feelings towards this strange line, it really touched me. The line, if you look at it very closely, is like a small child in a green garden. It is really cute and I have seen all my beautiful childhood when I looked at the line. But wait! my childhood wasn't beautiful. I still can't forget that creepy, awful day when... Sorry did you check stdarg.h before you use it in your operating system? Is it written by your or someone else? Are you sure about its behaviour? Is it
deterministic?
TFM wrote: If there is no next argument, or if type is not compatible with the
type of the actual next argument (as promoted according to the default
argument promotions), random errors will occur.
Now let's see what type is passed to the innocent va_arg:
Code: Select all
/*** address of ***/
case 's': {
int c = (int) va_arg (args, char);
char str[64];
strcpy (str,(const char*)c);
DebugPuts (str);
i++; // go to next character
break;
}
First of all, without even looking at the context of va_arg here, your explicit cast from (char) to (int) with va_arg() is very dangerous. The manual itself says it very clearly:
random errors will occur if promotions are not compatible with the passed type. The word "promotions" here refer to the promotions that are done by gcc-compiled code when a function is called. Types that are passed to that function are promoted. For example, on my machine, (char) parameters are promoted to (int) before the function is called (simply by movsbl instruction). For that reason, gcc should throw a warning at this point, because your assumption about argument-passing promotions as done by gcc is wrong.
Furthermore, it throws the same warning at places with the same risky use of va_arg(). For example, at line 261, the passed type is (char) so you simply used va_arg() with (char)... However, the compiler should tell you the whole point:
gcc wrote:
<your file>: In function <your function>:
<your file>:<the line>:<unsurprisingly, the column>:
warning: ‘char’ is promoted to ‘int’ when passed through ‘...’
char c = (char) va_arg(args, char);
^
note: (so you should pass ‘int’ not ‘char’ to ‘va_arg’)
note: if this code is reached, the program will abort
Can you see it? The compiler tells us the truth. It doesn't lie like us (not because it is honest, but because it is dumb (or dump?)). A passed character will always be promoted to an integer, so you should use va_arg() with 'int', not 'char', according to the first note.
OK. I will pass 'char'... and I will ignore this silly warning... What on earth will happen? we always happily cast a (char) to (int) even when it is the Christmas day! Recent research on the origins of Java programmers suggests that their ancestors heavily used such awkward constructs and their programs worked well (to them). So what about gcc? Here comes the second note...
gcc wrote:
<your file>: In function <your function>:
<your file>:<the line>:<unsurprisingly, the column>:
warning: ‘char’ is promoted to ‘int’ when passed through ‘...’
char c = (char) va_arg(args, char);
^
note: (so you should pass ‘int’ not ‘char’ to ‘va_arg’)
note: if this code is reached, the program will abort
How innocent! Did you like it? I will make your program abort if this code is reached! You know what, If I compile and execute va_arg(args, char) on my x86_64 machine (using gcc), the program gives illegal instruction exception!
OK iocoder, that's easy... my compiler doesn't give me the same warning that appears to you, so it might be handling va_arg() differently, in a way that doesn't abort the program.
Me: OK dude, even if we assume that this
random behavior is
deterministic (how can this be?), I am sure the tape on Turing machine will get damaged if we run this program on it (and you can't replace the tape because it doesn't have boundaries).
Why? Let's look at the code again:
Code: Select all
int c = (int) va_arg (args, char);
....
strcpy (str,(const char*)c);
You assume that the passed type is char. In this case, you will ignore whatever that argument holds except the lowest significant byte. So, if for example, I pass this:
The va_arg (args, char) thing will evaluate to 0x78 with (char) type. You then convert this to integer, hoping that gods will return back the missed 0x123456 when the character is converted to an integer. You then convert the integer to char pointer and use it to retrieve the passed string!
I am not saying that this bug (I am not even sure if it is the actual bug that crashes your OS, because the behavior of va_arg is
random in this case, so it might even be working correctly. But it is still a bug, because it will behave differently (in an unwanted manner) if I compile your OS with my gcc) is why your OS crashes, but my argument here is that
such holes in a program are why it crashes. The compiler is an innocent child that is not intelligent enough to understand the reality of our awkward world.
My suggestion is to try to debug your code a component by component. We don't know exactly in which component the bug is hiding. The compiler itself might be buggy. However, the compiler is well tested. Is your program well tested?
You could also post the code of the other parts of your kernel that you suspect they have the bug. I love it when someone gives me code to fix and it is challenging to me. But,
you must learn how to find the bug by yourself. Our answers here are just guidelines that help you understand what is going on.
Best of luck!