We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 3875 - SDL_NewAudioStream() fails if calloc(0, xx) returns NULL
Summary: SDL_NewAudioStream() fails if calloc(0, xx) returns NULL
Status: RESOLVED FIXED
Alias: None
Product: SDL
Classification: Unclassified
Component: audio (show other bugs)
Version: HG 2.0
Hardware: All All
: P2 normal
Assignee: Ryan C. Gordon
QA Contact: Sam Lantinga
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-10-12 08:33 UTC by Ozkan Sezer
Modified: 2017-10-12 15:13 UTC (History)
0 users

See Also:


Attachments
SDL_malloc patch (718 bytes, patch)
2017-10-12 11:32 UTC, Ozkan Sezer
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ozkan Sezer 2017-10-12 08:33:52 UTC
Since recent changes, I have been getting out of memory errors upon
trying to initialize audio on OS/2.  With the Dart implementation I
am using, I am hitting (device->spec.samples != obtained->samples)
in SDL_audio.c:open_audio_device() so it sets build_stream = SDL_TRUE
and calls SDL_NewAudioStream().  SDL_audiocvt.c:ResamplerPadding()
returns 0 because inrate == outrate, that results in SDL_calloc()
returning NULL for retval->resampler_padding_samples which results
in the failure return from SDL_NewAudioStream().

It is legal for malloc() or calloc() to return NULL for a 0 size arg,
and obviously Watcom runtime does exactly that.  I don't exactly know
which particular changeset opened the way for this failure.  I made a
hack like below and it works for me (TM):


--- a/src/audio/SDL_audiocvt.c
+++ b/src/audio/SDL_audiocvt.c
@@ -1260,6 +1260,7 @@ SDL_NewAudioStream(const SDL_AudioFormat
     const int packetlen = 4096;  /* !!! FIXME: good enough for now. */
     Uint8 pre_resample_channels;
     SDL_AudioStream *retval;
+    int nelem; /* for calloc() */
 
     retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
     if (!retval) {
@@ -1285,7 +1286,11 @@ SDL_NewAudioStream(const SDL_AudioFormat
     retval->packetlen = packetlen;
     retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
     retval->resampler_padding_samples = ResamplerPadding(retval->src_rate, retval->dst_rate) * pre_resample_channels;
-    retval->resampler_padding = (float *) SDL_calloc(retval->resampler_padding_samples, sizeof (float));
+    nelem = retval->resampler_padding_samples;
+    if (nelem == 0) {
+        nelem = 1;
+    }
+    retval->resampler_padding = (float *) SDL_calloc(nelem, sizeof (float));
 
     if (retval->resampler_padding == NULL) {
         SDL_FreeAudioStream(retval);
@@ -1313,7 +1318,7 @@ SDL_NewAudioStream(const SDL_AudioFormat
 #endif
 
         if (!retval->resampler_func) {
-            retval->resampler_state = SDL_calloc(retval->resampler_padding_samples, sizeof (float));
+            retval->resampler_state = SDL_calloc(nelem, sizeof (float));
             if (!retval->resampler_state) {
                 SDL_FreeAudioStream(retval);
                 SDL_OutOfMemory();


Of course there might be other ways of working around this, which
I leave to you guys.
Comment 1 Ozkan Sezer 2017-10-12 11:32:15 UTC
Created attachment 2979 [details]
SDL_malloc patch

An alternative (possibly better?) soulution would be making sure that
SDL_malloc(0) or SDL_calloc(0, x) doesn't return NULL, like below:
(also attached).

# HG changeset patch
# User Ozkan Sezer <sezero@users.sourceforge.net>
# Date 1507807685 -10800
#      Thu Oct 12 14:28:05 2017 +0300
# Node ID bee06d420e14cadddfee53da5a8ff40508e9dfd5
# Parent  0f2de8f6c959f98264ac99869038a7999f96f5f0
make sure that SDL_malloc(0) or SDL_calloc(0,x) doesn't return NULL.

diff --git a/src/stdlib/SDL_malloc.c b/src/stdlib/SDL_malloc.c
--- a/src/stdlib/SDL_malloc.c
+++ b/src/stdlib/SDL_malloc.c
@@ -33,11 +33,17 @@
 
 void *SDL_malloc(size_t size)
 {
+    if (!size) {
+        return malloc(1);
+    }
     return malloc(size);
 }
 
 void *SDL_calloc(size_t nmemb, size_t size)
 {
+    if (!size || !nmemb) {
+        return calloc(1,1);
+    }
     return calloc(nmemb, size);
 }
Comment 2 Sam Lantinga 2017-10-12 15:13:29 UTC
I like the idea of making SDL_malloc() and friends have consistent zero size alloc behavior.
https://hg.libsdl.org/SDL/rev/22fe56a64c6f

Thanks!