First, sorry, I know this is long and people might not read it all, but I think it needs a very detailed explanation.
I'm trying to get long file names working on Chan Fat File on a Cortex M4 with FreeRTOS. I've got a weird thing going on where, for some reason, a pointer is getting overwritten by a seemingly unconnected piece of code. You'd expect a stack overflow (ha!), but my stack's massive and I've tried increasing further it from when I first encountered this issue, I really don't think it can be that.
I have this code:
uint16_t w, *lfn;
lfn = dj->lfn;
*tp = fno->lfname;
while ((w = *lfn++) != 0)
{ /* Get an LFN char */
if (i >= fno->lfsize - 1)
{
i = 0;
break;
} /* Buffer overflow, no LFN */
tp[i] = (TCHAR)w;
i++;
}
lfn
is a pointer to a 16bit value. w
is a 16-bit value.
The line tp[i] = (TCHAR)w;
is the following in assembler:
6A7B ldr r3, [r7, #0x24]
005B lsls r3, r3, #1
68FA ldr r2, [r7, #12]
4413 add r3, r2
897A ldrh r2, [r7, #10]
801A strh r2, [r3]
Everything is fine the first few times through the loop. lfn
increments from 0x20009c68 in jumps of 2, just as you'd expect. However, when lfn
gets to 0x20009c72 and the code gets to the line tp[i] = (TCHAR)w;
it goes haywire.
The first two lines of assembler take the value of i
, shift it left by one to get the correct offset.
The next two lines puts tp
's address into r2
, then adds the contents of r3
, which, again, is that requisite offset.
ldrh r2, [r7, #10] then puts w in r2
Finally,
strh r2, [r3]
stores w in to where r3
is pointing to, which is the requisite place where tp
points.
When lfn
gets to 0x20009c72 the line last line of assembler puts 0x20000061 into lfn
. This is the line that is causing the real issue. Previous to that, it correctly stores r2
, which is w
, into where r3
is pointing. r3
at this point contains 0x20009c48, r2
contains 0x00000061. However, unlike previous times, this corrupts lfn
, putting 0x20000061 in it. It is clearly affecting lfn
itself.
The stack pointer itself throughout the execution of this piece of code does not change.
I wonder whether it is a salient point that lfn
in dj->lfn
is a pointer to a uint16_t
and not a limited size array? dj
is a structure of type DIR which is defined below:
typedef struct {
FATFS* fs; /* Pointer to the owner file system object */
WORD id; /* Owner file system mount ID */
WORD index; /* Current read/write index number */
DWORD sclust; /* Table start cluster (0:Root dir) */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
WCHAR* lfn; /* Pointer to the LFN working buffer */
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
} DIR;
WCHAR equates to an unsigned 16-bit value.
User contributions licensed under CC BY-SA 3.0