Why is value getting overwritten?


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; 
    }   /* Buffer overflow, no LFN */
    tp[i] = (TCHAR)w;

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 


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.

asked on Stack Overflow Sep 16, 2014 by DiBosco • edited Sep 16, 2014 by DiBosco

0 Answers

Nobody has answered this question yet.

User contributions licensed under CC BY-SA 3.0