Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix longFilename NULL pointer dereference #20115

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 31 additions & 32 deletions Marlin/src/sd/SdBaseFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1109,8 +1109,8 @@ int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) {
// We can't reconvert to UTF-8 here as UTF-8 is variable-size encoding, but joining LFN blocks
// needs static bytes addressing. So here just store full UTF-16LE words to re-convert later.
uint16_t idx = (n + i) * 2; // This is fixed as FAT LFN always contain UTF-16LE encoding
longFilename[idx] = utf16_ch & 0xFF;
longFilename[idx+1] = (utf16_ch >> 8) & 0xFF;
longFilename[idx] = utf16_ch & 0xFF;
longFilename[idx + 1] = (utf16_ch >> 8) & 0xFF;
#else
// Replace all multibyte characters to '_'
longFilename[n + i] = (utf16_ch > 0xFF) ? '_' : (utf16_ch & 0xFF);
Expand All @@ -1122,45 +1122,44 @@ int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) {
}
}

// Return if normal file or subdirectory
// Post-process normal file or subdirectory longname, if any
if (DIR_IS_FILE_OR_SUBDIR(dir)) {
#if ENABLED(UTF_FILENAME_SUPPORT)
// Convert filename from utf-16 to utf-8 as Marlin expects
#if LONG_FILENAME_CHARSIZE > 2
// Add warning for developers for currently not supported 3-byte cases (Conversion series of 2-byte
// codepoints to 3-byte in-place will break the rest of filename)
#error "Currently filename re-encoding is done in-place. It may break the remaining chars to use 3-byte codepoints."
#endif
uint16_t currentPos = 0;
LOOP_L_N(i, (LONG_FILENAME_LENGTH / 2)) {
uint16_t idx = i * 2; // This is fixed as FAT LFN always contain UTF-16LE encoding

uint16_t utf16_ch = longFilename[idx] | (longFilename[idx + 1] << 8);
if (0xD800 == (utf16_ch & 0xF800)) // Surrogate pair - encode as '_'
longFilename[currentPos++] = '_';
else if (0 == (utf16_ch & 0xFF80)) // Encode as 1-byte utf-8 char
longFilename[currentPos++] = utf16_ch & 0x007F;
else if (0 == (utf16_ch & 0xF800)) { // Encode as 2-byte utf-8 char
longFilename[currentPos++] = 0xC0 | ((utf16_ch >> 6) & 0x1F);
longFilename[currentPos++] = 0x80 | (utf16_ch & 0x3F);
}
else {
#if LONG_FILENAME_CHARSIZE > 2 // Encode as 3-byte utf-8 char
longFilename[currentPos++] = 0xE0 | ((utf16_ch >> 12) & 0x0F);
longFilename[currentPos++] = 0xC0 | ((utf16_ch >> 6) & 0x3F);
longFilename[currentPos++] = 0xC0 | (utf16_ch & 0x3F);
#else // Encode as '_'
longFilename[currentPos++] = '_';
#endif
}

if (0 == utf16_ch) break; // End of filename
}
return currentPos;
#else
return n;
// Is there a long filename to decode?
if (longFilename) {
// Reset n to the start of the long name
n = 0;
for (uint16_t idx = 0; idx < (LONG_FILENAME_LENGTH) / 2; idx += 2) { // idx is fixed since FAT LFN always contains UTF-16LE encoding
uint16_t utf16_ch = longFilename[idx] | (longFilename[idx + 1] << 8);
if (0xD800 == (utf16_ch & 0xF800)) // Surrogate pair - encode as '_'
longFilename[n++] = '_';
else if (0 == (utf16_ch & 0xFF80)) // Encode as 1-byte UTF-8 char
longFilename[n++] = utf16_ch & 0x007F;
else if (0 == (utf16_ch & 0xF800)) { // Encode as 2-byte UTF-8 char
longFilename[n++] = 0xC0 | ((utf16_ch >> 6) & 0x1F);
longFilename[n++] = 0x80 | ( utf16_ch & 0x3F);
}
else {
#if LONG_FILENAME_CHARSIZE > 2 // Encode as 3-byte UTF-8 char
longFilename[n++] = 0xE0 | ((utf16_ch >> 12) & 0x0F);
longFilename[n++] = 0xC0 | ((utf16_ch >> 6) & 0x3F);
longFilename[n++] = 0xC0 | ( utf16_ch & 0x3F);
#else // Encode as '_'
longFilename[n++] = '_';
#endif
}
if (0 == utf16_ch) break; // End of filename
} // idx
} // longFilename
#endif
}
return n;
} // DIR_IS_FILE_OR_SUBDIR
}
}

Expand Down