Error detected in Fresh\freshlib\sqlite\sqlite.asm, line# 30: unbalanced stack
Error detected in Fresh\freshlib\sqlite\sqlite.asm, line# 30: unbalanced stack
KyberMax Error detected in Fresh\freshlib\sqlite\sglite.asm, line# 30: unbalanced stack
I totally forgot about it and used a modified procedure, for example in the project AsmBB. But now it is fixed in the branch FreshLibDev.
johnfound I totally forgot about it and used a modified procedure... it is fixed in the branch FreshLibDev.
OK, got it. I just downloaded your Fresh IDE package to look at the sources (it is absolutely impossible to use it without a warm tube dark theme). I just opened some files and saw this error.
I must say that the cause of the error is your slightly dangerous style with multiple exits from the procedures, because the flat assembler does not automate the work with the stack as HL compilers or MASM. IMHO, even with MASM, is better not to do this (because it can become a bad habit).
KyberMax I must say that the cause of the error is your slightly dangerous style with multiple exits from the procedures, because the flat assembler does not automate the work with the stack as HL compilers or MASM. IMHO, even with MASM, is better not to do this (because it can become a bad habit).
Well, yes, it is dangerous somehow. But once fixed, there is no problem anymore.
Also, similar problems are actually pretty obvious and easy for fixing...
johnfound Well, yes, it is dangerous somehow. But once fixed, there is no problem anymore. Also, similar problems are actually pretty obvious and easy for fixing...
Well, I agree that it is obvious that these errors are obvious, but experience seems to hint to us that they are possible and therefore IMHO is better to completely eliminate them, slightly correcting the style than catching them all over the code (usually there are enough problems without this type mistakes, is not it?).
KyberMax johnfound Well, yes, it is dangerous somehow. But once fixed, there is no problem anymore. Also, similar problems are actually pretty obvious and easy for fixing...
Well, I agree that it is obvious that these errors are obvious, but experience seems to hint to us that they are possible and therefore IMHO is better to completely eliminate them, slightly correcting the style than catching them all over the code (usually there are enough problems without this type mistakes, is not it?).
If you are talking about the multiple returns from the procedures, it IMHO actually increases the code readability. The alternative is a multiple jumps and branches that can easily turn the code into a spaghetti pot... But it is always some kind of trade-off between readability, speed, size and bug-proof.
Another possible way is to automate the way registers are stored/restored by the procedure macros. But, personally for me, this way in fact elevates the level of the language - something I am trying to avoid. Turning this way, you will end with a wanna-be-high-level macro library, limiting the user the same way, high level languages do. If I wanted this, I would program in C/C++.
And if you ask where is the borderline between lo/high level - it is personal. For me, the current set of the freshlib code generation macros is the maximal level I think is reasonable. (The data definition macros are totally different story.)
johnfound If you are talking about the multiple returns from the procedures, it IMHO actually increases the code readability. The alternative is a multiple jumps and branches that can easily turn the code into a spaghetti pot... But it is always some kind of trade-off between readability, speed, size and bug-proof.
Well, I'm talking about multiple returns, of course, because the cause of the error was precisely inattention during one of the manual stack restorations before returning. I agree about readability, but is it worth sacrificing security for them? However, you decide, of course.
By the way, there is a way to avoid multiple jumping to the exit or error (MASM):
Example PROC
PUSH error
INVOKE Proc1
JNC cont1
RETN ; Error
cont1:
INVOKE Proc2
JNC cont2
RETN ; Error
cont2:
.....
ok:
POP EAX ; Popping error address
JMP exit
error:
.....
exit:
.....
RET ; Only one return from procedure
Example ENDP
johnfound Another possible way is to automate the way registers are stored/restored by the procedure macros. But, personally for me, this way in fact elevates the level of the language - something I am trying to avoid. Turning this way, you will end with a wanna-be-high-level macro library, limiting the user the same way, high level languages do. If I wanted this, I would program in C/C++.
I also hate to tolerate the excess of macros - the tube warm of the Assembler is lost.
KyberMax I agree about readability, but is it worth sacrificing security for them?
Hm, I don't think one can sacrifice security for readability at all. Actually, in long term, the readable code is always more secure.
The discussed bug is not actually good example, because this procedure was never used in real code. I am using it for opening SQLite database in AsmBB, but I simply copied the code in the project from another project. Because simply forgot that the same procedure was included in FreshLib.
First of all, it would be necessary to clarify that security here is a characteristic of the programming style, i.e. this style helps to avoid coding errors or helps to make them happen. Another characteristic of the style is the readability of the code.
johnfound Actually, in long term, the readable code is always more secure.
Not always, and this case is a good example. Indeed, multiple returns from procedures have good readability, but in combination with manual stack work, this style:
Firstly, promotes to making errors (each time the number and/or the order of the registers stored in the stack change, it is necessary to make edits in several places in the code).
Secondly, can hide an error due to the occasional execution of some returns (as in the case under consideration).
johnfound The discussed bug is not actually good example
It is obvious that this error is a issue of the programming style in which your source are created. Sad but true.
Today I downloaded and looked at the fasm source. Well, my impression of it is that fasm programmers are orphans, because no one thinks about their safe programming style.
And only MASM programmers are elite because dear and beloved Micro$oft has long thought about their safe programming style and did enough for that. He solved the problem of register saving elegantly by embedding it in the PROC directive:
Example PROC Uses ESI EDI EBX ; The Uses option enables saving these registers to the prolog
.....
.....
RET ; This directive forms the epilogue and the restore registers from the stack
Example ENDP
It may be possible for fasm programmers to at least try to achieve the unattainable ideal of divine MASM by modifying already existing macros designed to form a prologue and an epilogue. The begin macro can take saved registers as arguments and include it in the prolog. Accordingly, the return macro should include their restore in the epilogue.
Something like that:
proc Example
begin esi edi ebx
.....
.....
return
.....
.....
return
.....
return
endp
instead of this:
proc Example
begin
push esi edi ebx
.....
.....
.wrong_register_order:
pop ebx esi edi ; FAIL. Most likely even EPIC
return
.....
.....
.wrong_register:
pop ebx edi eax ; FAIL. Most likely also EPIC
return
.....
.....
.extra_register:
pop ebx edi esi eax ; EPIC FAIL
return
.....
.....
.ifnrequent_ret_with_missing_register:
; shit will happen when a lot copies will be spread
pop ebx edi ; EPIC FAIL
return
endp
The great humanist old cook hutch in his kangaroo pen took a programmer with such style by the legs and killed him against the wall.
KyberMax And only MASM programmers are elite because dear and beloved Micro$oft has long thought about their safe programming style and did enough for that. He solved the problem of register saving elegantly by embedding it in the PROC directive:
This is not a matter of "poverty". It is a realized trade-off because of the better control! As I already said, if you really want the compiler to control your code for "safety", use high level languages.
There was many experiments with FASM macro system in the past. Including development of almost "high-level" languages with full control of the stack, calls, etc. All of them failed, because the safety gain is not enough to justify the lost of control.
In fact, as I already said, more control means more safety in long-term aspect, even if it causes more bugs in short-term period. And this is good IMHO.
johnfound This is not a matter of "poverty". It is a realized trade-off because of the better control!
What are you talking about? In the above quotation there is no word taken by you in quotes.
If you are talking about MASM, then the "trade-off" is simple: it only frees the programmer from the routine and dangerous fuss with the stack. In the fasm, this is also partially implemented as a macro begin return push pop. The problem is that it is partially.
johnfound ...the safety gain is not enough to justify the lost of control.
Great, and now answer the simple question: what is the use of manually restoring registers before each return? Why do you need this "control" in this particular case?
johnfound In fact, as I already said, more control means more safety in long-term aspect, even if it causes more bugs in short-term period. And this is good IMHO.
It's all just a theory, but in practice you created a monstrously ridiculous and dangerous style, where you dazzled in a heap multiple returns, safe only when automating stack work, and manual work with this stack. Although this work is easily automated. As a result, you got an ideal machine gun for shooting your own leg.
KyberMax Great, and now answer the simple question: what is the use of manually restoring registers before each return? Why do you need this "control" in this particular case?
I can decide to pop not all registers from the stack, because of some reason. Or pop them in different order, if I want to return their values exchanged. Or to push/pop different group of registers, depending on the program flow.
Here is an example:
proc ItIsBetter, .Arg1, .Arg2, .Arg3, .Arg4
begin
push eax
mov eax, [.Arg1]
cmp eax, 42
jne .exit1
push ecx
mov ecx, [.Arg4]
jecxz .exit2
push esi edi
mov esi, [.Arg2]
mov edi, [.Arg3]
rep movsd
pop edi esi
.exit2:
pop ecx
.exit1:
pop eax
return
endp
KyberMax It's all just a theory, but in practice you created a monstrously ridiculous and dangerous style, where you dazzled in a heap multiple returns, safe only when automating stack work, and manual work with this stack. Although this work is easily automated. As a result, you got an ideal machine gun for shooting your own leg.
But strange none of my legs is shot. My projects written in this style are not too buggy (and the revealed bugs are diagnosed and fixed easily) and the programs work in a field better than similar programs written in HLL. It's a magic! Isn't it?
johnfound I can decide to pop not all registers from the stack, because of some reason. Or pop them in different order, if I want to return their values exchanged. Or to push/pop different group of registers, depending on the program flow.
Here is an example
It is clear that you can do anything, it is not clear just for what. In a huge number of cases, this freedom is absolutely unnecessary. But you always pay a high price for this unnecessary freedom.
The example you give is a rare exception, where you are apparently trying to reduce the execution time. It is possible that I, too, in this case would not follow the standard style, however I would do it a little differently: I would pass the parameters through the register-pointer to the structure, not through the stack, and would not load the data into the registers for analysis.
Something like this:
PBIN TYPEDEF Ptr
;
COND_MOV_MEM STRUC
cond Dword ?
pDst PBIN ?
pSrc PBIN ?
lMem Dword ?
COND_MOV_MEM ENDS
;
.CODE
ItIsTheBest PROC
; Input: EBX = pointer to struct
; MASM not create stack frame if no args & local vars
; Proc.just for local labels
ASSUME EBX: Ptr COND_MOV_MEM
CMP [EBX].cond, 42
JNE exit
CMP [EBX].lMem, 0
JE exit
PUSH ECX
PUSH EDI
PUSH ESI
MOV ECX, [EBX].lMem
MOV EDI, [EBX].pDst
MOV ESI, [EBX].pSrc
REP MOVSD
POP ESI
POP EDI
POP ECX
ASSUME EBX: Nothing
exit:
RET
ItIsTheBest ENDP
johnfound But strange none of my legs is shot.
Well, here you can just look at the first post of this topic.
johnfound My projects written in this style are not too buggy...
I did not say that your code is buggy, I just said that your style is dangerous, i.e. requiring greater attention to a large number of dangerous little things, which increases the likelihood of errors, reduces the speed of code creation and increases the complexity of maintenance.
johnfound ...(and the revealed bugs are diagnosed and fixed easily) and the programs work in a field better than similar programs written in HLL. It's a magic! Isn't it?
Actually, no, because I also write on asm, my code also works well, and following the safe coding style allows me not to use the debugger.
Error detected in \Fresh\freshlib\FreshEdit\FreshEdit.asm, line# 500: unbalanced stack (return w/o pop esi)
KyberMax Error detected in \Fresh\freshlib\FreshEdit\FreshEdit.asm, line# 500: unbalanced stack (return w/o pop esi)
Yes, there is. But I will not fix it. The TFreshEdit component is actually not working, not finished and in the same time obsolete and superseded by TAsmEdit ( freshlib/gui/TAsmEdit.asm
) which uses TText ( freshlib/data/buffergap.asm
) as a text storage structures and has much higher performance.
And as a whole, the GUI part of FreshLibDev branch (that is currently merged into Fresh IDE) is also not finished and generally will be superseded soon.
The current development process of the GUI part of FreshLib (the directories gui/
and graphics/
) is performed into the branch NoCanvasGUI.
So, if you want to help to the process of GUI components development, please, examine the branch NoCanvasGUI. There are definitely bugs that need to be fixed.
johnfound ...I will not fix it. The TFreshEdit component is actually not working, not finished and in the same time obsolete...
Well, actually I found two more:
Error detected in \Fresh\freshlib\FreshEdit\FreshEdit.asm, line# 657: wrong register pop order
Error detected in \Fresh\freshlib\FreshEdit\FreshEdit.asm, line# 1019: unbalanced stack (pop eax w/o push)
I place them here only so that you pay attention to the type of these errors and take seriously the writing by me about your programming style.
johnfound ...if you want to help to the process of GUI components development...
I did not find these errors on purpose (however, like the first error in this thread). I just looked through your development and saw them by chance. If I look at the branch you have proposed, then only for obvious errors, you know why.
It is interesting that such an obvious thing had to be explained for almost a week. Obviously this is due to the poor English of Google translator, through which I write like Kraftwerk sings through the synthesizer. I know English poorly (in the future everyone will speak Russian only) but even I was funny from some Google translations. For example, "старинный знакомый" is not translated as "old cock" IMHO. But whether Google knows something about the great Australian humanist, or whether SkyNet trolls cyborg through Google - who knows?
Well, the mechanism of the first machine gun for shooting in the your leg is now obvious and its dismantling is also obvious and for the most part already described above. You can modify the prologue and epilogue (begin and return macros) as described above. If this is impossible or difficult, then it is necessary to reduce multiple returns to one in all procedures.
But the best way is to use both methods not only to eliminate the effect of accidental programmer errors, but also to ensure that the executable code is not clogged with numerous epilogues and does not look like HLL shit.
However, there is another machine gun, which is impossible not to see looking at your source. This, of course, using the stack top to temporarily save registers. This is a very common and dangerous method, and its danger increases in proportion to the distance between push and pop.
This machine gun is dangerous seeming ease of use and even easier to get an epic fail in the form of a shot through the leg. The cause of this is obvious: push/pop method requires increased attention and does not forgive errors. For example, it is very easy to get an unbalanced stack, just forgetting to pop the register out of the top stack.
You swing this machine gun right and left, watering all around in your source code by the push/pop bullets like Terminator, and you may already have shot your leg more than once without even noticing it. But it is even easier to shoot your leg just in the process of maintaining the code.
Fixing the problem is obvious as the problem itself: use local variables instead of register saving commands at the stack top. Of course, this is a more complex method than push/pop, but it is safe and also improves the readability of the code if you use informative names of local variables.
So, paraphrasing an expression from the excellent film "The Diamond Hand", we can summarize: "take care of your leg, Vanya".