? Strange Behaviour with PRGEDIT (Page 1) ● SmileBASIC Source Forums

Sign In

*Usernames are case-sensitive
Forgot my password

Strange Behaviour with PRGEDIT

  • #1 ✎ 122 amihart I don't know if this is a bug or not, it really depends on what the developers had intended, but I do find it to be some pretty strange behaviour which I don't quite understand the purpose of. Let's say we have code executing in a given slot, we'll call it slot A. We also will be working with another different slot, let's call it slot B. Slot A: PRGEDIT B PRGEDIT A The first line of the code above will execute just fine. We're allowed to edit the code in other slots. But the second line of code, such that we want to edit the slot our code is running in, crashes with an "Illegal function call error". Let's look at some more code. Slot A: USE B GOSUB STR$(B)+":@THIS" Slot B: @THIS PRGEDIT A PRGEDIT B Using "GOSUB" to another slot has the same effect as the first code. When we are in Slot B, "PRGEDIT A" works fine, since we're editing another slot, but "PRGEDIT B" crashes because again, we're trying to edit our own slot, the slot the code is running in, and this causes a crash. So, at first glance it seems to me the developers don't want code being able to read and edit itself. I have no clue why this wouldn't be allowed, but that's what it seems. However, we haven't tried one thing yet. What if we use "GOTO" instead of "GOSUB"? Slot A: USE B GOTO STR$(B)+":@THIS" Slot B: @THIS PRGEDIT A PRGEDIT B Surprisingly, this code throws no errors. If you "GOTO" another slot, modifying your own slot becomes perfectly valid. This also works from Direct Mode. I can type in the GOTO statement and execute code that way from Direct Mode, and that code now is allowed to use PRGEDIT on itself. However, you have to attempt to run the code first, let it crash, and then execute from Direct Mode, since it needs to load the symbol table into memory first before GOTOs will work from Direct Mode. Let's take a look at this. Put this code into Slot 0: @MAIN PRGEDIT 0 VAR I FOR I=0 TO PRGSIZE()-1 PRINT PRGGET$(); NEXT Try to run the code normally. It will crash with an error when it hits "PRGEDIT 0" because that's not allowed. However, by running the code we've now loaded the symbol table into memory. So go to Direct Mode and type: GOTO "0:@MAIN The code will now execute just fine. It will read its own code and then print out to the screen. But, there's more interesting behaviour than this. The code that SmileBASIC interprets is not the code that is within the slot. SmileBASIC first loads the code from the slot into another location in memory and then executes it from there. We can see this using this code: @MAIN PRGEDIT 0 PRGDEL -1 VAR I=0 WHILE BUTTON()!=#X PRINT I INC I WEND So the WHILE loop of this code is simple, it just continues to count upwards forever until you press X. But look what's above the WHILE loop. Those two lines of code will delete all of the contents in Slot 0. But our code is stored within Slot 0. So at first you'd think, the code should delete itself, and then stop executing immediately, right? It will never reach the WHILE loop. But try it. Again type "RUN" in Direct Mode to get the error, then type the same GOTO statement mentioned before. The code will start counting away. It successfully executes, meaning it reached the WHILE loop. Now press X to stop the program. So, it reached the WHILE loop. Does that mean the program failed to delete itself? Open slot 0 now. You will find that it is empty. The code deletes itself successfully, but since it's not actually being executed from the slot itself but from another buffer in the 3DS's memory, let's call this "execution memory", it can continue executing even though it's deleted itself. So code can delete itself while continue to run. Using this knowledge, we can completely lift the restrictions from a program entirely while running it normally from Direct Mode like so: Slot A 1. Inject into Slot B so that it: - a. Deletes itself. - b. Jumps to line 4. 2. Use Slot B. 3. Jump to Slot B. 4. Some label here to signify the start of your code. Here's an example: 'Detect which slot we're in. VAR I FOR I=0 TO 3 IF PRGNAME$()==PRGNAME$(I) BREAK ENDIF NEXT 'Define our slots. VAR SLOT_A=I VAR SLOT_B=(SLOT_A+1) MOD 4 'Inject code into Slot B. PRGEDIT SLOT_B PRGDEL -1 PRGSET "@FIX" PRGSET "PRGEDIT "+STR$(SLOT_B) PRGSET "PRGDEL -1" PRGSET "GOTO "+CHR$(34)+STR$(SLOT_A)+":@MAIN"+CHR$(34) 'Execute the injected code. USE SLOT_B GOTO STR$(SLOT_B)+":@FIX" 'The main body of our program. @MAIN 'Print the code in the slot of the currently running program. PRGEDIT SLOT_A VAR I FOR I=0 TO PRGSIZE()-1 PRINT PRGGET$(); NEXT 'Delete itself. PRGDEL -1 What this will do, when loaded into any given slot, is first lift the restrictions of "PRGEDIT", then it will read its own source code and print it to the screen, and then it will delete itself so the program you just executed will disappear from the slot (it will also clear the slot it used to lift the restrictions). At first to me it seemed like SmileBASIC devs seemingly don't want code that can read and modify itself at runtime. Why else would you disallow code from reading and writing to its own slot? But then again you can easily lift these restrictions with a GOTO statement so I don't know why they're there in the first place. In fact on their website it states under PRGEDIT that "Specifying the SLOT currently running will give an error". But it doesn't, that is, if you entered that slot with a GOTO statement. I don't know if this is a bug in the sense they don't want you to be able to use PRGEDIT on a program's own slot and this is a way around it, or if there's some good technical reason to why it doesn't initially work but is acceptable after GOTO statements. Either way it's definitely some strange behaviour and I thought it was worth pointing out. Posted Edited by amihart
  • #2 ✎ 93 niconii Video Games I like to play video games! Hobbies Expert Programmer Programming no longer gives me any trouble. Come to me for help, if you like! Programming Strength Drawing I like to draw! Hobbies I don't find this surprising at all. Being able to edit code that's currently being run would open up a huge can of worms. Here's an example loaded into slot 0, with line numbers for clarity: 1 PRINT "HELLO" 2 GOSUB @FOO 3 PRINT "WORLD" 4 END 5 6 @FOO 7 PRGEDIT 0,2 8 PRGINS "PRINT 123" 9 RETURN The question here is, where does @FOO return to? Typically, GOSUB @FOO would push a pointer to the stack which points directly after it, then jump to @FOO. Then, when RETURN is reached, it pops that pointer off the stack and jumps back to right after GOSUB @FOO, where it can execute the next instruction. For simplicity, let's say it works with line numbers, so it pushes 3 to the stack. Then, stepping through it, this is what happens:
    1. "HELLO" is printed.
    2. 3 is pushed to the stack, and the program jumps to @FOO.
    3. The line "PRINT 123" is inserted before line 2, shifting everything below it down a line. Now the program looks like this: 1 PRINT "HELLO" 2 PRINT 123 3 GOSUB @FOO 4 PRINT "WORLD" 5 END 6 7 @FOO 8 PRGEDIT 0,2 9 PRGINS "PRINT 123" 10 RETURN
    4. 3 is popped off the stack, so it returns to line 3... which is now GOSUB @FOO again. Uh oh.
    5. And it just keeps going in an endless loop, inserting PRINT 123 forever until it inevitably runs out of space and crashes.
    And that's just one of the many ways things could go horribly wrong. Say you call FOO, which calls BAR, which deletes FOO and then returns. Now what? Of course, you could say that none of this is a problem in the end because SmileBASIC copies the program to another location before running it. But then, not only does this defeat the point of editing the current slot, allowing you to do it would just mislead people into thinking it works when it doesn't. It might be useful for making confusing programs, but I don't think that's the usecase SmileBoom had in mind.
  • #3 ✎ 1550 12Me21 Admin Syntax Highlighter Received for creating the code syntax highlighter on SBS Night Person I like the quiet night and sleep late. Express Yourself Second Year My account is over 2 years old Website There are cases where it would be useful to edit the current slot (and besides, Smileboom didn't do a good job of preventing it. It would be better to have more consistent behavior rather than relying on bugs) This library: http://smilebasicsource.com/page?pid=1053 has a loader program to generate the actual code that will run. Without being able to edit the current slot, it forces you to waste TWO slots to use it. Posted