Uninitalised memory when copying String with embedded NUL character

Open
#111 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
35/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Stale
Tech stack
cpp
Domain
embedded-iot

Research direction

Start by reproducing the supplied Arduino sketch and inspect the String copy and assignment paths involved in sGlobal = sLocal. Compare the behavior with the proposed fix in issue #97, focusing on the embedded NUL case. Done means copying preserves the full 12-byte value, including the bytes after the NUL, without uninitialized data.

Written by the indexing model from the issue text.

Description

When you create a String object with an embedded NUL character, and you copy this String, the memory after the NUL byte is not copied, leading to uninitialised memory being used.

Here's sample code to show the error:

String sGlobal;

void dumpString(const String &s)
{
  Serial.print("Got a string of length ");
  Serial.println(s.length());
  Serial.print(">");
  for (size_t t = 0; t < s.length(); ++t) {
    if (s.charAt(t) != '\0' && isascii(s.charAt(t))) {
      Serial.print(s.charAt(t));
    } else if (s.charAt(t) == '\0') {
      Serial.print("\\0");
    } else {
      Serial.print("\\x");
      Serial.print(s.charAt(t), HEX);
    }
  }
  Serial.print("<");

  Serial.println();
}

void encode(String &s)
{
  while (s.length() < 12)
  {
    s += ' ';
  }

  Serial.println("s in encode is, after filling with spaces:");
  dumpString(s);

  s.setCharAt(11, '!');
  s.setCharAt(10, 'd');
  s.setCharAt(9, 'l');
  s.setCharAt(8, 'r');
  s.setCharAt(7, 'o');
  s.setCharAt(6, 'w');
  s.setCharAt(5, '\0');
  s.setCharAt(4, 'o');
  s.setCharAt(3, 'l');
  s.setCharAt(2, 'l');
  s.setCharAt(1, 'e');
  s.setCharAt(0, 'H');
  
  Serial.println("s in encode is, after setting its chars:");
  dumpString(s);

}

void test() {
  String sLocal;
  Serial.println("sLocal in test is, after init:");
  dumpString(sLocal);
  Serial.println("sGlobal in test is, after init:");
  dumpString(sGlobal);
  
  encode(sLocal);
  Serial.println("sLocal in test is, after encode:");
  dumpString(sLocal);
  Serial.println("sGlobal in test is, after encode:");
  dumpString(sGlobal);

  sGlobal = sLocal;
  Serial.println("sGlobal in test is, after assignment:");
  dumpString(sGlobal);
}

void setup()
{
  Serial.begin(115200);

  test();
}

void loop()
{
}

Output of the code:

Local in test is, after init:
Got a string of length 0
><
sGlobal in test is, after init:
Got a string of length 0
><
s in encode is, after filling with spaces:
Got a string of length 12
>            <
s in encode is, after setting its chars:
Got a string of length 12
>Hello\0world!<
sLocal in test is, after encode:
Got a string of length 12
>Hello\0world!<
sGlobal in test is, after encode:
Got a string of length 0
><
sGlobal in test is, after assignment:
Got a string of length 12
>Hello\0n\xFFFFFFEF\xFFFFFFD6\xFFFFFFFF\<

Please merge #97 to fix this issue, or at least use memcpy() instead of strcpy() to initialise the data.

Dominant language
C++
Stars
306
Forks
150
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from arduino/ArduinoCore-API

All issues in arduino/ArduinoCore-API

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.