What is expected behavior of calling srand() and rand() if insufficient heap is available?

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
polluxpolaris
Level 1
Level 1
First reply posted First question asked First like given

Environment: PSoC Creator 4.4, CY8C4147AZI-S465

I'm going into the infinite IntDefaultHandler and seeing ENOMEM when calling srand() or rand() without heap.

Since I'm currently not doing any other dynamic memory allocation if I run the same code without calls to srand() and rand() the code runs fine, even without any heap.

Is it expected per the C standard?

I tried to run the exact same test of running srand() and rand() without heap on a TI F28002x and it runs fine, although of course rand() isn't actually returning a random number.

My fear is that srand() and rand() are unsafely using the heap in PSoC 4's implementation.

0 Likes
1 Solution

Hello!

http://www.sourceware.org/newlib/
Library newlib-nano is an open source project, so this is not a cypress problem. Most likely this is not even a problem, just do not use what does not suit you.

If you still want to use rand (), you need to provide enough heap for your project.
To protect yourself as much as possible from the lack of a heap
one of the variants for the initial code is as follows:

bad_value = rand ();  // this is 1481765933 (as you can see in disasm)
srand (some_seed);
if (bad_value == rand ()) printf ("with a heep of trouble");

Since memory from the heap is allocated only once (srand() + rand()), only one such check is needed,

Then rand() will work without problems.

View solution in original post

9 Replies
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

Hi,

I've looked and couldn't find any ANSI C requirement for srand() or rand() NOT to use heap.

Since these functions on the PSoC are in the stdlib and we don't have the source code for them, we can't verify whether they are coded to use the heap or not.   I suspect based on the runtime error you are getting that they are.

Your success on the TI F28002x may be conditional.  Although you did not allocate any heap, it is possible that the srand() and rand() functions in the TI stdlib are using a heap.  It might be that it is assuming a heap somewhere and using RAM memory, but you're not noticing it.

The PSoC apparently is flagging it in your case because it happens to check it.

The optimal situation is when a function gets compiled, it should internally determine is HEAP is used.  If so, it should flag an error in the link phase if NOHEAP is specified.  This would prevent code to be generated and loaded into a CPU where the HEAP is assumed but not present.  The designer can then determine if they want to use that function or rewrite it.

Suggestion:  If you insist on NOHEAP for your PSoC project, I would recommend finding or creating source code for  srand and rand() functions.   On most PSoCs, a PRS (Pseudo-Random-Sequence) component exists.  People have used this component for similar purposes.

UPDATE:

I just found this source code in an ATMEL rand.c file.

/*------------------------------------------------------------------------------
 *         Header
 *------------------------------------------------------------------------------*/

#include "board.h"

#include "rand.h"

/*------------------------------------------------------------------------------
 *         Global Variables
 *------------------------------------------------------------------------------*/

static uint32_t _dwRandNext = 1;

/*------------------------------------------------------------------------------
 *         Exported Functions
 *------------------------------------------------------------------------------*/

/**
 *  Initialize the seed for rand generator.
 *
 *  \param dwSeed rand initiation seed
 */
void srand(uint32_t dwSeed)
{
	_dwRandNext = dwSeed;
}

/**
 *  Return a random number, maxinum assumed to be 65536
 */
uint32_t rand(void)
{
	_dwRandNext = _dwRandNext * 1103515245 + 12345;

	return (uint32_t) (_dwRandNext / 131072) % 65536;
}

 

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
polluxpolaris
Level 1
Level 1
First reply posted First question asked First like given

AFAIK srand() and rand() always use heap.
What is in question, is how srand() and rand() should respond if there is insufficient heap available.

I don't think a solution could be triggered at compile time, because it's entirely possible that even if heap is being used per the absence of NOHEAP, the memory could still be allocated away at run-time using dynamic allocation.

I agree with you that creating my own rand() could be a sufficient workaround for me, but does that mean anyone who is simultaneously using rand() and dynamic-memory allocation on PSoC4 are at risk of ENOMEM? That's extremely risky and Cypress needs to address that.

It seems to me that it is patently impossible by definition that srand() is using heap if the linker file specifies that no heap exists. I am extremely confident that srand() and rand() are safe on TI F28002x if heap runs out, and pretty sure that it is unsafe on PSoC 4. However, you could possibly argue that it was using stack due to oversight, but I did confirm that the values from rand() were not correct while operating without heap in the linker file.

0 Likes

polluxpolaris,

It is my understanding that both the STACK and HEAP are pre-allocated at link-time.  The designer defines how much to use of each.

Allocation

STACK uses memory to store info about where in running program it was called from so that it will return correctly.  Additionally, variables only local to the function or interrupt are usually popped onto the stack with the exception of 'static' variables.  'static's get placed on the HEAP as a static link-time allocation.

If your RTOS has a dynamic memory allocation scheme (using malloc() or the equivalent) it will pull the memory requested from the HEAP.  In this case, the function doing the allocation should check for a NULL return.

Run-time Overruns

STACK overruns can occur for various reasons.  Usually due to too many nested function calls (highly recursive functions) or allowing interrupt nesting with highly active interrupts.  I am not aware of any compile-time tools to evaluate if your code is prone to stack-overruns.  That's why designers are encouraged to develop stack-overrun checking code or, if blessed, the RTOS you are using has one built in.

HEAP overruns, on the other hand, are different.  If the HEAP allocation is ONLY static, then there should be a link-time error or warning to alert to the possibility of insufficient HEAP memory allocated.  This would allow you to increase the HEAP size.

HEAP managers that use a dynamic memory allocation can only inform you at run-time.  That is why a NULL return from a malloc() is the only way to prevent data corrupt and, as I call it: "The train running off the track" event.  (That is why a Watchdog timer is beneficial.)

It is my understanding that the PSoC native code uses a static HEAP allocation.  If you are using an RTOS such as eMBed or FreeRTOS, then you can have access to a HEAP manager with dynamic allocation.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Check out the disassembly in Valk's response and you'll see the malloc() in rand() without a NULL check.

The risk is that if someone allocates all their heap, then call srand() and or rand(), they will ENOMEM and there's not much they can do about it.

0 Likes

Hello!

You should not use any malloc () functions internally in RTOS driven applications. RTOS has its own memory manager with its own API. Otherwise, interesting adventures await you)

0 Likes

Depends on the OS, some microkernels don't have memory managers.

0 Likes
VaIk_2708246
Level 3
Level 3
10 replies posted 5 replies posted 5 questions asked

I have some interests in this.

This is a rand() disasm on psoc4 (newlib-nano).

As we can see after malloc call there is no check of result to NULL.

Obviously, in case of memory allocation failure, the function will return a fixed number.

In general, it can also be seen that memory is needed to store the previous generated value.

Awesome find Valk. That lines up with my experiments.
Do you think this should be escalated up to Cypress for a patch?

0 Likes

Hello!

http://www.sourceware.org/newlib/
Library newlib-nano is an open source project, so this is not a cypress problem. Most likely this is not even a problem, just do not use what does not suit you.

If you still want to use rand (), you need to provide enough heap for your project.
To protect yourself as much as possible from the lack of a heap
one of the variants for the initial code is as follows:

bad_value = rand ();  // this is 1481765933 (as you can see in disasm)
srand (some_seed);
if (bad_value == rand ()) printf ("with a heep of trouble");

Since memory from the heap is allocated only once (srand() + rand()), only one such check is needed,

Then rand() will work without problems.