Bug when using OS_TASK_OPT_STK_CLR with OSTaskCreateExt()

I recently wrapped up an investigation of strange behavior in a customer’s program on a Rabbit 3000 product. It took some time to track it down to using the OS_TASK_OPT_STK_CLR option with OSTaskCreateExt(). Both Dynamic C 9 and 10 were erasing the wrong memory area.

In the case of Dynamic C 9, it was inefficiently using 16-bit writes and ultimately erasing one byte beyond the end of the stack allocated for the task. In this customer’s situation, a stack ending at 0x6FFFF would end up erasing the byte at 0x60000 due to usage of the LDP opcode.

In Dynamic C 10, it calculated the incorrect starting address for the stack, and would erase one byte before the stack and leave the last byte untouched.

Due to licensing issues, Digi International wasn’t able to include the uC/OS-II source code in the GitHub repository when they released Dynamic C libraries and samples as Open Source. This change will be a part of the Dynamic C 10.72E installer whenever we release it. I intend to include it as a patch on GitHub for both Dynamic C 9 and 10.

Here’s the patch for Dynamic C 9:


--- a/Lib/UCOS2/OS_TASK.C
+++ b/Lib/UCOS2/OS_TASK.C
@@ -439,8 +439,6 @@
     auto INT8U    err;
     auto INT16U   i;
     auto INT16U   pbos;
-    auto INT8U    upper_nibble;
-    auto INT16U   lower_16;
     auto INT16U   stk_size;
     auto INT32U   PhysAddr;

@@ -460,25 +458,9 @@
         if (opt & OS_TASK_OPT_STK_CHK) {          // See if stack checking has been enabled
             if (opt & OS_TASK_OPT_STK_CLR) {      // See if stack needs to be cleared
                                                   // Yes, fill the stack with zeros
-                lower_16 = (INT16U)PhysAddr;
-                upper_nibble = (INT8U)(PhysAddr >> 16);
-                for (i = stk_size; i > 0; i--) {
-                    #asm
-  							 ld	hl,@sp+upper_nibble
-							 add	hl,sp
-	                   ld   a,(hl)	         ;a gets high nibble
-							 ld	hl,@sp+lower_16
-							 add	hl,sp
-                      ld   hl,(hl)	         ;hl has lower 16 bits
-                      push ix
-                      ld   ix,hl             ;a:ix 20-bit phys addr for stack
-                      bool hl
-                      ld   l,h               ;zero hl
-                      ldp  (ix),hl           ;write zero into stack
-                      pop  ix
-                    #endasm
-                    lower_16--;
-                }
+                // PhysAddr is the last address of the stack (e.g., ...FF), so it's
+                // necessary to add 1 to get to the starting address of the stack.
+                xmemset(PhysAddr - stk_size + 1, 0, stk_size);
             }
         }


And for Dynamic C 10:


--- a/Lib/Rabbit4000/UCOS2/OS_TASK.C
+++ b/Lib/Rabbit4000/UCOS2/OS_TASK.C
@@ -479,7 +479,9 @@
         if (opt & OS_TASK_OPT_STK_CHK) {          // See if stack checking has been enabled
             if (opt & OS_TASK_OPT_STK_CLR) {      // See if stack needs to be cleared
                                                   // Yes, fill the stack with zeros
-                _f_memset((void __far *)(PhysAddr - stk_size), 0, stk_size);
+                // PhysAddr is the last address of the stack (e.g., ...FF), so it's
+                // necessary to add 1 to get to the starting address of the stack.
+                _f_memset((void __far *)(PhysAddr - stk_size + 1), 0, stk_size);
             }
         }


Please let me know if you have any questions about the original bug, or the patches.

Patches to resolve this bug are provided in the question above.