esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
16.07k stars 13.33k forks source link

malloc(0) returns 0 #8354

Closed ohyeaah closed 3 years ago

ohyeaah commented 3 years ago

Basic Infos

Platform

Settings in IDE

Problem Description

The problem is malloc(0) returns 0. I think this is not valid C nor CPP. Because of this new CLASS[0] becomes 0 when returned in a function (but not if used as a local value). That's not valid CPP behaviour. I am very sure new CLASS[0] may never be 0.

MCVE Sketch

#include <Arduino.h>

char* testNewZero();

void setup()
{
  Serial.begin(9600);

  Serial.println("Please wait 3 seconds so the serial monitor has time to initialize...");
  delay(3000);

  char* s = (char*)malloc(0);
  if (s)
  {
    Serial.println("malloc(0) may not return 0. This is not valid CPP!");
    free(s);
  }
  else // this will happen
    Serial.println("malloc(0) may not return 0. This is not valid CPP!");

  s = testNewZero();
  if (s)
  {
    Serial.println("testNewZero() did not return 0. Everything OK!");
    delete[] s;
  }
  else // this will happen
    Serial.println("testNewZero() did return 0! This is not valid CPP!");

  s = new char[0]; // if used as local variable, everything is ok 
  if (s) // this will happen
  {
    Serial.println("new char[0] did not return 0. Everything OK!");
    delete[] s;
  }
  else
    Serial.println("new char[0] did return 0! This is not valid CPP!");
}

void loop()
{

}

/* if you use new char[0] as local variable it is not zero.
 * but if you return it in a function like this it becomes 0
 * very strange... the reason may be that malloc(0) returns 0.
 */
char* testNewZero()
{
  return new char[0];
}

Debug Messages

Debug messages go here
earlephilhower commented 3 years ago

This behavior has been there since the earliest days of the core, so I'm a little confused by the issue.

Could you please point out where in the C++ spec that new[0] or malloc(0) can't return nullptr? And what is the specific problem if it does?

You should be able to call any non-virtual members of the object as long as they're static, but by definition you're not going to be able to use anything via the this (i.e. member variables, vtable functions, non-static fcns, etc.).

It's not a big deal to add a if (!size) size=1; to the malloc wrapper, but without a good reason it's hard to justify opening up that code...

TD-er commented 3 years ago

See also Stackoverflow - C++ new int[0] -- will it allocate memory?

I think it should return a nullptr, simply because behavior is undefined if you try to dereference the returned pointer.

If your code needs to work also with allocating nothing but basing its success on the pointer not being a nullptr, I guess you should have another look at that code. (or am I missing your point here?) If however the allocation is throwing an exception, then I guess you have a point here, but I don't think it is doing that, right?

ohyeaah commented 3 years ago

Thank you for this information. I've read on die.net that malloc(0) may return 0. Also I've read on stackoverflow that it's not reliable to use new CLASS[0].