Anobium - 7 days ago

The problem

A string variable in GCBASIC has a fixed size, set when you declare it:

'Dim myString As String * 16'

When you assign a string to it, GCBASIC copies the whole string. It does not check whether the string fits. If the string is too long, the extra characters are written into the RAM after the variable.

That RAM belongs to other variables. There is no warning: the program compiles and runs, and something else goes wrong later.

Example on a PIC16F886:

#DEFINE LONGCONSTANT "12345678901234567890"
Dim myString1 As String * 16 = "ABC"
Dim myString2 As String * 16 = LONGCONSTANT

LONGCONSTANT has 20 characters, but myString2 holds 16. All 20 are copied, and the last 4 overwrite myString1. Afterwards myString1 is no longer "ABC".

This happens with:

  • a constant: myString = "a long text"
  • another string: myString = otherString
  • joined strings: myString = "abc" + otherString

The fix

The new build 1657 adds an option:

#option StringLimitCheck

With this option, a string is never copied past the end of the variable it goes into. A string that is too long is cut to fit.

In the example, myString2 becomes "1234567890123456" and myString1 stays "ABC".

How to use it

  1. Install the new build of the compiler.
  2. Add this line near the top of your program, with your other #option lines:

#option StringLimitCheck

  1. Compile as usual. You do not need to change anything else.

What it covers

  • Assigning a constant to a string.
  • Copying one string to another.
  • Joining strings with +. Each part only gets the space that is left.

It does not cover:

  • A string passed to a sub by reference.
  • Writing single characters yourself, for example myString(20) = 65.

Which chips

  • PIC18: yes.
  • PIC16, for example the 16F886 and 16F1827: yes.
  • 12-bit PICs, for example the 16F57: yes for constants. String variables on these chips have problems with or without the option, and the compiler already warns about this.
  • AVR: yes.

What it costs

  • About one instruction for each string assignment.
  • No extra RAM on PIC18 and AVR, and one byte on other PICs.

USB programs can even get smaller. The USB libraries no longer need Left() for their name strings when the option is on.

Also in this build

  • Strings use less RAM. The compiler no longer reserves temporary strings it does not use, and sizes the others to fit. One test program went from 1936 to 1502 bytes of RAM.
  • The .asm file now lists the length of every string variable, under ;STRING LENGTHS, for exEQU 16.

Questions

If a string still overflows with the option on, please reply with the chip and a short program example.


This now works as expected.

#CHIP 16f886
#option Explicit
#OPTION StringLimitCheck

#DEFINE USART_BAUD_RATE 9600
#DEFINE USART_TX_BLOCKING
#DEFINE USART_DELAY OFF

#DEFINE LONGCONSTANT "12345678901234567890"   
// #DEFINE LONGCONSTANT "12345678901234567"
// #DEFINE LONGCONSTANT "1234567890123456"

Dim myString1 As String * 2 = "ABC"                   // RAM too small for StringRAM too small for assignment
Dim myString2 As String * 16 = LONGCONSTANT           // 

Hserprint myString1
HserSend 13
HserSend 10
Hserprint myString2
 
👍
1