This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Strange problem with malloc()

Hello,

I am working with C5515 eZDSP USB Stick. Heap size is:  -heap  0x14000  /* HEAP AREA SIZE  */

** With this code:

void main(void) {
        short *a;
        a = (short*) malloc(sizeof(short) * 70000);

        printf("Address A: ");
        printf("%p\n", a);

        free(a);
}

malloc run well and return the first address of the allocated array.


** But with this code:
void main(void) {
	short *a;
	a = (short*) malloc(sizeof(short) * 50000);

	printf("Address A: ");
	printf("%p\n", a);

	free(a);
}

a is a null pointer 0x00000000


** And with this code:

void main(void) {
	short *a, *b;
	a = (short*) malloc(sizeof(short) * 32000);
	b = (short*) malloc(sizeof(short) * 32000);

	printf("Address A: ");
	printf("%p\n", a);

	printf("Address B: ");
	printf("%p\n", b);

	free(a);
	free(b);
}

'a' is the address of the allocated memory, but 'b' is null pointer 0x00000000


I tested with large and huge memory model for these code, same problem happened.

Please explain and help me to solve this problem, thanks.

  • Both short and char are 16 bits on C55x; therefore sizeof(short)==1

    0x14000 equals 81920.

    When you use the -heap linker option, you are expressing 8-bit units, so you're only getting 40960 16-bit chars.

    There simply isn't enough room to allocate 70000 or 50000 shorts, so the first two examples should fail.  I'm not sure why you're getting a non-NULL return from malloc in the first case.  I'll bet you are not using huge model.  If you use huge model with the first example, does it return NULL?  If you're using any object of size larger than 32767, including an object allocated with malloc, you should use huge model.

    In the last example, there should be enough room to satisfy the first allocation but not the second, which is what you observe.

  • You are right, I tested to malloc 70000 shorts and it returned NULL (huge model). But it will return an address if I use large model (???)

    Anyway, I increased the heap size to 0x28000 and it's working as expected. But there is one thing I noticed, if I set

    -stack      0x4000   /* PRIMARY STACK SIZE    */
    -sysstack   0x4000   /* SECONDARY STACK SIZE  */
    -heap       0x28000  /* HEAP AREA SIZE        */

    the code in previous post seems break out at the first malloc function. If i reduce the stack size:

    -stack      0x2000   /* PRIMARY STACK SIZE    */
    -sysstack   0x2000   /* SECONDARY STACK SIZE  */
    -heap       0x28000  /* HEAP AREA SIZE        */

    It's work properly.

    Please explain or give me some documents to understand about these things. Thanks!

  • When you use large mode, the type of size_t changes to 16 bits, which cannot hold the value 70000.   When you assign 70000 to an unsigned 16 bit size_t, you get 4464, which allocates successfully.  Your call to malloc succeeded, but it allocated far less memory than you thought it did.  Use the --issue_remarks compiler option, and the compiler should warn you about the integer truncation.

    That size stack seems sufficiently generous in either to execute your program.  I doubt it directly has an effect.  It could perhaps be the case that the particular position of the stack is affecting adjacent memory, which shouldn't normally happen if your stack and heap are large enough.  Could you post a complete test case, including compiler options, that demonstrates the problem?  Exactly what do you mean by "break out at the first malloc function" ?

  • Exactly what do you mean by "break out at the first malloc function" ?

    Well, I run the code in debug mode, line by line. The CCS v6 highlights the current line.

    When the program move to this line (the line is highlight)

    a = (short*) malloc(sizeof(short) * 32000);

    and I press F6 to run that line of code. If it works as expect, the next line will be highlight. But it's not. The program not running anymore.

    I attached the project, please take a look at it. Thanks.5047.Test.rar

  • Tiep Duong Man said:
    I attached the project, please take a look at it. Thanks.5047.Test.rar

    I ran the program in a VC5505 eZDSP USB stick (don't have a C5515) and the program single stepped in the debugger, with the malloc calls returning a pointer in each case. i.e. can't repeat the problem.

    Tiep Duong Man said:
    and I press F6 to run that line of code. If it works as expect, the next line will be highlight. But it's not. The program not running anymore.

    If you suspend the debugger after the failure to step to the next line, which is the reported stack backtrace?

  • Sorry, I attached the wrong project file. Please check new file here 1830.Test.rar

    Chester Gillon said:
    If you suspend the debugger after the failure to step to the next line, which is the reported stack backtrace?

    It said "No source available for [some address]". It seems the program does not terminate. I think it loops forever. After suspend, I can resume, and then suspend ... I can see it runs assembly code in the Disassembly panel.

    The program run fine if I change stack to 0x2000 as below

    -stack      0x2000   /* PRIMARY STACK SIZE    */
    -sysstack   0x2000   /* SECONDARY STACK SIZE  */
    -heap       0x28000  /* HEAP AREA SIZE        */

  • Tiep Duong Man said:
    Sorry, I attached the wrong project file. Please check new file here 1830.Test.rar

    OK, I can repeat the failure with that project.

    Single stepping the start-up code shows an incorrect value of XSP (Extended data stack pointer) being set. After the first instruction is executed the XSP has the correct value of 0x1E000:

    However, after the next instruction has been executed, which sets the value of XSSP, the value of XSP has been set to the corrupt value of 0x2E000:

    The reason is that on the C55xx CPU the data stack pointer and system stack pointer must be in the same 64K word page, due to the SPH register holding the 7 most significant bits of the data stack pointer and system stack pointer.

    In this example the linker command file is such that initial value of the data stack pointer and system stack pointer are in different 64K word pages - leading to an incorrect data stack pointer which leads to a program crash.

    To prevent the crash, the C5515.cmd linker command file can be modified to reduce the size of the system stack by one word. e.g. change from:

    -sysstack 0x4000 /* SECONDARY STACK SIZE */

    To:
    -sysstack 0x3FFE /* SECONDARY STACK SIZE */
    With this change the initial value of the data stack pointer and the system system pointer are in the same 64K word page, and the crash no longer occurs.

    A question for the TI compiler team is that the C5500 v4.4.1 linker doesn't warn about such an invalid initial stack configuration. Should the linker produce a warning?

  • Tiep Duong Man said:
    Sorry, I attached the wrong project file. Please check new file here 1830.Test.rar

    Also, in the C5515.cmd linker command file within attached project the size of the on-chip SARAM is set at 050000h (320 Kbytes) which is too large for the C5515. It should be set to 040000h (256K bytes) to match the actual size of the SARAM.

    [This error isn't currently causing a problem, since the linker map shows the program is currently only using the first 0x305be bytes in the SARAM - but should be corrected to avoid future problems]

  • Please explain more clearly about 64K word page memory. I read this many time in the document about compiler optimizing. But I didn't get it. Another question is, why there are two stacks (stack and sysstack)?

  • There is a check in the linker:

    error: ".stack" (0x100) and ".sysstack" (0x40000) must be on the same page

    However, the linker only checks the start of these sections; it should also check the ends of the sections.  In fast stack mode, if the stack start and end, and sysstack start and end aren't all on the same page, you run the risk of corrupting SPH.

    However again, in large model, if the stack is in lockstep mode, it's legal for the start and end of .stack to be on different pages.  Lockstep mode cannot be detected by the linker - it can be changed at runtime.  Still, it seems like a warning would be appropriate.

    The workaround is to make sure that your .stack and .sysstack start and end on the same page; that is, that both .stack and .sysstack fit entirely within one 64k-word aligned memory page.

  • Tiep Duong Man said:
    why there are two stacks (stack and sysstack)?

    For backward compatibility with C54x assembly programs.  Unless you have C54x assembly code, it's not worth tying to understand why.  Just understand that the "stack" is split in half; the halves grow and shrink together, more or less.

  • Tiep Duong Man said:
    Please explain more clearly about 64K word page memory. I read this many time in the document about compiler optimizing. But I didn't get it.

    There's a lot of detail to that topic, and I don't really want to write a thesis about it here.  The short story is that older C55x devices had only 16-bit address calculation units, so they could not perform pointer arithmetic which carried above 16 bits.  Thus, the memory was naturally divided into 64k-word chunks (pow(2,16)=64k).  You couldn't have an array straddling an aligned page boundary, because a pointer iterating through the array would wrap around to the start of the page, instead of moving to the next page.  This restriction carries through to some aspects of the most recent hardware, even though it can perform 23-bit address arithmetic.  For instance, as mentioned earlier, the XSP and XSSP share the upper 7 bits (SPH).Do you have a more specific question about pages?

  • So, a page is a block of memory whose address from X to (X + 64K - 1)?

    If it's correct. When I define the stack size as:

    -stack      0x4000   /* PRIMARY STACK SIZE    */
    -sysstack   0x4000   /* SECONDARY STACK SIZE  */

    Then in map file we have:

    They're on same page 0. Otherwise, we have a total 2000 + 2000 = 4000 words = 4K words of addresses. Thus, stack and sysstack on same page?

    Please correct me.

    One question about the map file: why there are two lines of each section (as in the picture), one is UNINITIALIZED and another one is HOLE? They are same size and same addresses?!

    Thank you, I am newbie in this ezDSP kit.

  • Tiep Duong Man said:
    a page is a block of memory whose address from X to (X + 64K - 1)?

    The block must also be aligned to 64k; for instance, 0x10000 - 0x1ffff

    Regarding the word "page," unfortunately it is used in different ways in the linker.  In TI linkers, traditionally page "0" is the .text address space.  Some targets, such as C54x, put the program data in a separate memory space, page "1".  These pages are unrelated to the 64k pages we have been talking about.  For this discussion, ignore the "page" column in the linker map file.

    For your map file, both .stack and .sysstack are on 64k-word page 1 because their upper 7 bits are 0x01.

    You are correct to observe that all of the contents of .stack and .sysstack are on page 1, and I'm sorry I overlooked that detail last time.  The problem is that the boot routine needs to set XSP and XSSP to one word past the end of .stack and .sysstack because of the way C55x does push/pop.  For this reason, not only should the linker make sure that the start/end of stack/sysstack fall on the same page, but also that the address after the end of stack/sysstack also falls on the same page, for the problem you are seeing.

    Chester's suggested workaround is the right workaround for that problem.  You'll still want to make sure everything falls on the same page.

    A suggestion: unless you using C54x assembly code in your project, you probably aren't using lockstep stack mode, in which case you can make sysstack much smaller.  Typically only register push/pop at function boundaries increase sysstack usage.  Function-local variables usually go on .stack, which means stack usage will grow at a faster rate than sysstack usage.