src/audio/disk/SDL_diskaudio.c
author Sam Lantinga
Thu, 16 May 2013 00:43:22 -0700
changeset 7180 3733e68edbc3
parent 7038 7f22b9ba218f
child 7366 38c6f26bb010
permissions -rw-r--r--
Fixed bug 1846 - _allmul implementation in SDL_stdlib.c doesn't clean up the stack

Colin Barrett

I see this manifest itself (VS2012 x86) as:

"Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention."

in the first call to SDL_GetTicks in my application. The disassembly at the problem line is:

hires_now.QuadPart *= 1000;
00AD0792 push 0
00AD0794 push 3E8h
00AD0799 mov eax,dword ptr [ebp-10h]
00AD079C push eax
00AD079D mov ecx,dword ptr [hires_now]
00AD07A0 push ecx
00AD07A1 call _allmul (0AE7D40h)
00AD07A6 mov dword ptr [hires_now],eax
00AD07A9 mov dword ptr [ebp-10h],edx

Apparently _allmul should be popping the stack but isn't (other similar functions in SDL_stdlib.c - _alldiv and whatnot - DO pop the stack).

A 'ret 10h' at the end of _allmul appears to do the trick
slouken@68
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
slouken@68
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@68
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@68
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@68
    20
*/
slouken@1402
    21
#include "SDL_config.h"
slouken@68
    22
slouken@6044
    23
#if SDL_AUDIO_DRIVER_DISK
slouken@6044
    24
slouken@68
    25
/* Output raw audio data to a file. */
slouken@68
    26
slouken@1465
    27
#if HAVE_STDIO_H
slouken@68
    28
#include <stdio.h>
slouken@1465
    29
#endif
slouken@68
    30
slouken@1465
    31
#include "SDL_rwops.h"
slouken@1358
    32
#include "SDL_timer.h"
slouken@68
    33
#include "SDL_audio.h"
slouken@1361
    34
#include "../SDL_audiomem.h"
slouken@1361
    35
#include "../SDL_audio_c.h"
slouken@68
    36
#include "SDL_diskaudio.h"
slouken@68
    37
slouken@68
    38
/* environment variables and defaults. */
slouken@68
    39
#define DISKENVR_OUTFILE         "SDL_DISKAUDIOFILE"
slouken@68
    40
#define DISKDEFAULT_OUTFILE      "sdlaudio.raw"
slouken@68
    41
#define DISKENVR_WRITEDELAY      "SDL_DISKAUDIODELAY"
slouken@68
    42
#define DISKDEFAULT_WRITEDELAY   150
slouken@68
    43
slouken@1895
    44
static const char *
icculus@2049
    45
DISKAUD_GetOutputFilename(const char *devname)
slouken@68
    46
{
icculus@2049
    47
    if (devname == NULL) {
icculus@2049
    48
        devname = SDL_getenv(DISKENVR_OUTFILE);
icculus@2049
    49
        if (devname == NULL) {
icculus@2049
    50
            devname = DISKDEFAULT_OUTFILE;
slouken@1895
    51
        }
slouken@1895
    52
    }
icculus@2049
    53
    return devname;
slouken@68
    54
}
slouken@68
    55
slouken@68
    56
/* This function waits until it is possible to write a full sound buffer */
slouken@1895
    57
static void
icculus@2049
    58
DISKAUD_WaitDevice(_THIS)
slouken@68
    59
{
slouken@1895
    60
    SDL_Delay(this->hidden->write_delay);
slouken@68
    61
}
slouken@68
    62
slouken@1895
    63
static void
icculus@2049
    64
DISKAUD_PlayDevice(_THIS)
slouken@68
    65
{
slouken@3253
    66
    size_t written;
slouken@68
    67
slouken@1895
    68
    /* Write the audio data */
slouken@1895
    69
    written = SDL_RWwrite(this->hidden->output,
slouken@1895
    70
                          this->hidden->mixbuf, 1, this->hidden->mixlen);
slouken@68
    71
slouken@1895
    72
    /* If we couldn't write, assume fatal error for now */
slouken@3253
    73
    if (written != this->hidden->mixlen) {
slouken@1895
    74
        this->enabled = 0;
slouken@1895
    75
    }
slouken@68
    76
#ifdef DEBUG_AUDIO
slouken@1895
    77
    fprintf(stderr, "Wrote %d bytes of audio data\n", written);
slouken@68
    78
#endif
slouken@68
    79
}
slouken@68
    80
slouken@1895
    81
static Uint8 *
icculus@2049
    82
DISKAUD_GetDeviceBuf(_THIS)
slouken@68
    83
{
slouken@1895
    84
    return (this->hidden->mixbuf);
slouken@68
    85
}
slouken@68
    86
slouken@1895
    87
static void
icculus@2049
    88
DISKAUD_CloseDevice(_THIS)
slouken@68
    89
{
icculus@2049
    90
    if (this->hidden != NULL) {
icculus@2049
    91
        if (this->hidden->mixbuf != NULL) {
icculus@2049
    92
            SDL_FreeAudioMem(this->hidden->mixbuf);
icculus@2049
    93
            this->hidden->mixbuf = NULL;
icculus@2049
    94
        }
icculus@2049
    95
        if (this->hidden->output != NULL) {
icculus@2049
    96
            SDL_RWclose(this->hidden->output);
icculus@2049
    97
            this->hidden->output = NULL;
icculus@2049
    98
        }
icculus@2049
    99
        SDL_free(this->hidden);
icculus@2049
   100
        this->hidden = NULL;
slouken@1895
   101
    }
slouken@68
   102
}
slouken@68
   103
slouken@1895
   104
static int
icculus@2049
   105
DISKAUD_OpenDevice(_THIS, const char *devname, int iscapture)
slouken@68
   106
{
icculus@2049
   107
    const char *envr = SDL_getenv(DISKENVR_WRITEDELAY);
icculus@2049
   108
    const char *fname = DISKAUD_GetOutputFilename(devname);
icculus@2049
   109
icculus@2049
   110
    this->hidden = (struct SDL_PrivateAudioData *)
slouken@2060
   111
        SDL_malloc(sizeof(*this->hidden));
icculus@2049
   112
    if (this->hidden == NULL) {
icculus@7038
   113
        return SDL_OutOfMemory();
icculus@2049
   114
    }
slouken@2060
   115
    SDL_memset(this->hidden, 0, sizeof(*this->hidden));
slouken@68
   116
slouken@1895
   117
    /* Open the audio device */
slouken@1895
   118
    this->hidden->output = SDL_RWFromFile(fname, "wb");
slouken@1895
   119
    if (this->hidden->output == NULL) {
icculus@2049
   120
        DISKAUD_CloseDevice(this);
icculus@7038
   121
        return -1;
slouken@1895
   122
    }
slouken@68
   123
slouken@1895
   124
    /* Allocate mixing buffer */
slouken@1895
   125
    this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
slouken@1895
   126
    if (this->hidden->mixbuf == NULL) {
icculus@2049
   127
        DISKAUD_CloseDevice(this);
icculus@7038
   128
        return -1;
slouken@1895
   129
    }
icculus@2049
   130
    SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
icculus@2049
   131
icculus@2049
   132
    this->hidden->mixlen = this->spec.size;
icculus@2049
   133
    this->hidden->write_delay =
icculus@2049
   134
        (envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
icculus@2049
   135
icculus@2049
   136
#if HAVE_STDIO_H
icculus@2049
   137
    fprintf(stderr,
icculus@2049
   138
            "WARNING: You are using the SDL disk writer audio driver!\n"
icculus@2049
   139
            " Writing to file [%s].\n", fname);
icculus@2049
   140
#endif
slouken@68
   141
slouken@1895
   142
    /* We're ready to rock and roll. :-) */
icculus@7038
   143
    return 0;
slouken@68
   144
}
slouken@68
   145
icculus@2049
   146
static int
slouken@2060
   147
DISKAUD_Init(SDL_AudioDriverImpl * impl)
icculus@2049
   148
{
icculus@2049
   149
    /* Set the function pointers */
icculus@2049
   150
    impl->OpenDevice = DISKAUD_OpenDevice;
icculus@2049
   151
    impl->WaitDevice = DISKAUD_WaitDevice;
icculus@2049
   152
    impl->PlayDevice = DISKAUD_PlayDevice;
icculus@2049
   153
    impl->GetDeviceBuf = DISKAUD_GetDeviceBuf;
icculus@2049
   154
    impl->CloseDevice = DISKAUD_CloseDevice;
icculus@2049
   155
icculus@3699
   156
    return 1;   /* this audio target is available. */
icculus@2049
   157
}
icculus@2049
   158
icculus@2049
   159
AudioBootStrap DISKAUD_bootstrap = {
icculus@5594
   160
    "disk", "direct-to-disk audio", DISKAUD_Init, 1
icculus@2049
   161
};
icculus@2049
   162
slouken@6044
   163
#endif /* SDL_AUDIO_DRIVER_DISK */
slouken@6044
   164
slouken@1895
   165
/* vi: set ts=4 sw=4 expandtab: */