malloc(): memory corruption (fast) after adding vars to object

Hi,



I don't really know if this is a C++ or a generic linux (gcc) issue, so please excuse me if the question is offtopic here.

I am trying to expand an existing application (in C++) that does voip/radio-over-ip for ham-radio and I have a very strange problem I do not really understand.

This is the first time I use C++, so it might be something I do wrong.

The original application ("thelinkbox", http://sourceforge.net/apps/mediawiki/cqinet/index.php?title=Linkbox-url) uses OSS and I want to add support for portaudio as I have issues with the OSS-emulation layer on the raspberry pi.

The problem is this:
I have added my code to support portaudio, and now the application crashes during startup. It gives this error:
*** glibc detected *** ./linkbox/tlb: malloc(): memory corruption (fast): 0x086c4ab0 ***

What I do not understand is that the application actually crashes in the beginning of the application (reading the configuration file), while almost all of the code-change I have written are not yet executed.

The only change I have made -at the point where the application crashes- is that I have added a number of variables to the object and I initialise them in the object creator.

Even more strange is
- the application crashes on code that is part of the original code and that works OK in the original code

- the code actually crashes on this:
--- hier knippen --- hier knippen --- hier knippen ---
(...)
if((pPort = new CPort) == NULL) {
LOG_ERROR(("%s#%d: new failed.\n",__FUNCTION__,__LINE__));
Ret = ERR_CONFIG_FILE;
break;
}
pPort->NodeName = strdup(Arg);
--- hier knippen --- hier knippen --- hier knippen ---

It bombs on the "strdup".

I replace the strdup with the following debug-code:
--- hier knippen --- hier knippen --- hier knippen ---
char * zzz;
zzz=NULL; // just to be sure
zzz = (char *)malloc(strlen(Arg)+1);
if (zzz) {
strcpy(zzz,Arg);
}; // end if

pPort->NodeName = zzz;
--- hier knippen --- hier knippen --- hier knippen ---

It turns out the code bombs on the "malloc" ???
Why on earth would an application crash on a malloc?


Based on what I found on the net, this error seams to indicate a problem with the heap-memory; but I do not understand why I get this error, while the original code ran just fine.
As said, the only difference I have (at that point) is adding some variables to the object and initialise them.


Is there something else that needs to be done when you modify an objact (like adding variables?)

BTW. I posted my code on github:
https://github.com/on1arf/thelinkbox-on1arf.git

But there are some things you need to do, to activate my code in it (overwrite a Makefile) so that the problem can be demonstrated.

If somebody is interested, I can explain it that in a different message.


I have the same issue on i386 linux and on (ARM) Raspberry pi so I think it is not an architecture-related bug.


Many thanks in advance from a first-time C++ programmer.

Cheerio! Kr. Bonne.
> It turns out the code bombs on the "malloc" ???
zzz = (char *)malloc(strlen(Arg)+1);
¿what value are you sending to `malloc()'?


> if((pPort = new CPort) == NULL)
that gets on my nerves.
new throws an exception on failure. new (std::nothrow) returns NULL
however, I doubt that that dynamic allocation is justified


> But there are some things you need to do, to activate my code in it (overwrite a Makefile)
> so that the problem can be demonstrated.
> If somebody is interested, I can explain it that in a different message.
go ahead.
Last edited on
Hi,

OK. I'm sorry. I forgot to add this.

This part of the code is executed after the error-checking. So the values that are passed are OK.

The issue is not related to wrong invalid data. (that's the first check I did :-) )

Some debug-code and gdb traces:

1267 if((pPort = new CPort) == NULL) {
(...)
1274 fprintf(stderr,"p_pPort = %X \n",pPort);
p_pPort = 80AA468

1273 fprintf(stderr,"Arg = *%s* \n",Arg);
Arg = *2meters*

1282 zzz=NULL;
1283 fprintf(stderr,"zzz = %X, strlen(arg) = %d \n",zzz,strlen(Arg));
zzz = 0, strlen(arg) = 7
1284 zzz = (char *)malloc(strlen(Arg)+1);
*** glibc detected *** /home/kristoff/ham/thelinkbox-on1arf/linkbox/tlb: malloc(): memory corruption (fast): 0x080aaab0 ***



Note that the original code runs with exactly the same code (with the exception of the additional variables in the object and the code to initialise them) and exactly the same configuration-file is read does work OK.
That's why I find this all so strange!


One additional thing to add:
My code also links to the "portaudio" libraries ("-l portaudio"), which is something that the original code (of course) does not do.
But, as said, at that point, no portaudio APIs have been called. That all happens much further down in the execution of the program.

Could this be an issue of linking a C++ object with the portaudio libraries?


Earlier, I did try out some quick code to try out portaudio in C+ (and especially the callback function). This did work OK and that code was linked to the portaudio-libraries.


Cheerio! Kr. Bonne.
closed account (Dy7SLyTq)
well whats probably happening then is your writing to more memory than you have access too.
I have added my code to support portaudio, and now the application crashes during startup. It gives this error:
*** glibc detected *** ./linkbox/tlb: malloc(): memory corruption (fast): 0x086c4ab0 ***


This means that, during a call to malloc, it was detected that memory was corrupt. It does not mean the call to malloc corrupted the memory. It does mean that memory was already corrupt, and that you should look to previous manipulations of memory (in possibly other areas of the code) to find the place it happens.
Hi,

First of all, thanks for replying.

This is getting more and more strange.

After the different replies here in this group, I descided to use the "remove code untill error goes away" methode and I find that the error is related not to CODE, but to data-definition.

In the definition of the object, I add a couple of variables I need for the portaudio-related code.
When I remove all code from the source-code, but only leave the additional variable-declarations in the code, I still have the "glibc" error.
When I remove these decleration, the code passes.

This is the code I added:

(line 325 of linkbox/ports.h and further)
#ifdef __NEEDPORTAUDIO__
PaStreamParameters outputParameters;
PaStreamParameters inputParameters;

pashared_str pa; // data shared between object and portaudio callback function

// is PortAudio initialised?
int pa_active;

// tempory buffer for pa_getaudio
int i_tmpbuffer_c;
int i_framesize;

// tempory buffer for pa_queueaudio
int16_t *o_tmpbuffer;
int o_tmpbuffer_c;
int o_framesize;
#endif

This is all part of the declaration of the object "CPort"


It turns out that when I remove the declaration of the variables "inputParameters" and "outputParameters" (of the type "PaStreamParameters") and the variable "pa" (of the type "pashared_str"). I do not have the error anymore.
If I leave any of of them in the source-code, I get the "memory-corruption" error.

Even more, if I only declare the "pa" variable and limit the pashared_str structure to only 4 integer, the code also passes! No memory-corruption error.


So I am really puzzled here.
What is going on?


Are there special rules on how to incorperate structures in an C++ object? Or is there a limit on size of the heap that is playing here?

And, if it a issue of size of the memory in the heap, why do I get the error memory-corruption when doing a malloc and not an error when creating the object?


Cheerio! Kr. Bonne.
Maybe stack overflow, if `PaStreamParameters' is quite big
iirc you may test with `ulimit -s unlimited'


Still waiting for the `things you need to do, to activate my code in it (overwrite a Makefile) '
Hi "ne555"
I like that name! :-) ... Electronics fan?


First of all. I tried the "ulimit" but that did not help anything.


I just uploaded the changed debug-code to github:
https://github.com/on1arf/thelinkbox-on1arf.git

After cloning it, you'll need to change one thing first:

Edit the file testit/tlb-pa.conf
There is a line that says:
WorkingDir = /home/kristoff/ham/thelinkbox-on1arf/testit

You'll need to change that to make it fit your directory structure


After that:

* TEST 1: original code:

$ ./configure
$ make clean
$ make

This will compile the original code! (without the "portaudio" changes I made)

Note there is quite a bit of debug-code in there, so ignore the warning in configvars
configvars.cpp:1266:39: warning: format ‘%X’ expects argument of type ‘unsigned int’, but argument 3 has type ‘CPort*’ [-Wformat]

These are the result of the "fprintf("%X", ..." debug code so can be ignore.

run it:
--- cut here --- cut here --- cut here --- cut here ---
$ ./linkbox/tlb -f testit/tlb-pa.conf

thelinkbox Version 0.53 compiled Dec 19 2013 08:31:58
CreatePort = (null), x = 0
CreatePort = 2meters, x = 0
p_pPort = 0
before: Arg = *2meters*
p_pPort = A011448
addr pPort->NodeName = A01144C
zzz = 0
zzz = 0, strlen(arg) = 7
zzz = A011A90
if zzz =
zzz = 2meters
addr pPort->NodeName = A01144C
After: Arg = 2meters
LoadCommands: Unable to open "tlb.cmds" - No such file or directory (2)

Come on now, your email address isn't "w1aw@arrl.net" is it?
The email address is optional, please either delete the entry
or provide a valid email address.
--- cut here --- cut here --- cut here --- cut here ---


This is normal. The test configuration-file is not correct so the application stops there.

But the important element is that the "CreatePort" code is executed and executed correctly.
(BTW, there are indeed two "sleep" commands in the debug-session).

Let me explain a little bit how the application seams to work:

As you can see, the "thelinkbox" application (which is an application for voice-over-ip/radio-over-ip for ham-radio) has a configuration file (as specified by the -f argument):
In my case, it is "testit/tlb-pa.conf"

The main configuration file contains the line:
--- cut here --- cut here ---
include port0-pa.conf
--- cut here --- cut here ---

This includes "port0-pa.conf", which is a configuration-file per port (i.e. a radio-interface).


This port-configuration file starts with this line:
--- cut here --- cut here ---
CreatePort=2meters
--- cut here --- cut here ---


The code in the application behind this works as follows:

There is a function "Createport" (found in linkbox/configvars.cpp) which:
- it creates an object "CPorts" with the name "pPort".
- it initialised some data
- one of the initiailisation is that it copies the name of the port (in this case: "2meters") to pPort->Nodename)

In the original code, this work OK.

(For some reason, the code is called twice, but the first call has an empty argument; tat is rejected in the code).


The application that continues to read port-configuration file, then returns to the main configuration file, when it stops on the line:
"EmailAdr = w1aw@arrl.net"

(which is the email-adress of one of the original authors. As this is clearly not correct, the application stops here).


* TEST 2:
implement my changes:
$ cp testit/linkbox_Makefile linkbox/Makefile

This will add the lines the following lines in Makefiile
-D__PORTAUDIO__
-lportaudio

In ports.h, look for __NEEDPORTAUDIO__ instead


As a result, my portaudio code will be added in the code and portaudio library will be linked
(NO ./configure!)
$ make clean
$ make

Now, run again:

$ ./linkbox/tlb -f testit/tlb-pa.conf
thelinkbox Version 0.53 compiled Dec 19 2013 08:58:30
CreatePort = (null), x = 0
CreatePort = 2meters, x = 0
p_pPort = 0
before: Arg = *2meters*
p_pPort = 86C4468
addr pPort->NodeName = 86C446C
zzz = B74DDAEF
zzz = 0, strlen(arg) = 7
*** glibc detected *** ./linkbox/tlb: malloc(): memory corruption (fast): 0x086c4ab0 ***

(you will probably need to do "killall -9 tlb" in another window to get the application to stop).

So, the application crashes on a "glibc memory corruption detection" error.


In the code that is now on github, the almost all of my changes have been removed:
I changed the "__PORTAUDIO__" or "__NEEDPORTAUDIO__" with "__PORTAUDIODEBUG__" or "__NEEDPORTAUDIODEBUG__" so they are not included in the source.

In fact, the only lines that are included are:
* linkbox/ports.cpp (lines 305-320):
include "portaudio.h" + define some values

* linkbox/ports.h (line 177-190):
define structure pashare_str

* linkbox/ports.h (line 324-341):
Declare vars in object

The key to this all seams to be these three lines:
PaStreamParameters outputParameters;
PaStreamParameters inputParameters;
pashared_str pa; // data shared between object and portaudio callback function


If you comment them out, recompile the code ("make clean && make"), the application does work. If you include them in the source-code, the application crashes on the glibc error.

BTW. I also tested this on an old mac-mini running debian today. Same problem.
So I have this issue on three different platforms: i386, ARM (Raspi) and PowerPC (macmini G3).


I am really puzzled here!


Cheerio! Kr. Bonne.
In the original code
ctcss.c: In function ‘UpdateCTCSSInternal’:
ctcss.c:503:24: warning: operation on ‘ptdet->zIndex’ may be undefined [-Wsequence-point]
          ptdet->zIndex = (++ptdet->zIndex) % 4;


> These are the result of the "fprintf("%X", ..." debug code so can be ignore.
annoying. Also, you've got fprintf(stderr,"if zzz = %s \n",zzz); which is bad as what `zzz' points is not initialized (it is not a null terminated string)


After making your changes, and running through valgrind
$ valgrind --read-var-info=yes ./linkbox/tlb -f testit/tlb-pa.conf
==32321== Memcheck, a memory error detector
==32321== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==32321== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==32321== Command: ./linkbox/tlb -f testit/tlb-pa.conf
==32321== 
CreatePort = (null), x = 0 
CreatePort = 2meters, x = 0 
p_pPort = 0 
==32321== Invalid write of size 4
==32321==    at 0x40321C: CPort::CPort() (ports.cpp:470)
==32321==    by 0x40E11A: CreatePort(config_entry*, char*, AfCmd, int) (configvars.cpp:1267)
==32321==    by 0x43588F: ParseConfigLine (configfile.c:201)
==32321==    by 0x435BAE: parse_configfile (configfile.c:298)
==32321==    by 0x435B67: parse_configfile (configfile.c:294)
==32321==    by 0x435C81: read_config (configfile.c:328)
==32321==    by 0x40DD58: DoConfigPass (configvars.cpp:1147)
==32321==    by 0x431914: ReadConfig (thebridge.c:566)
==32321==    by 0x431A41: StartRunning (thebridge.c:415)
==32321==    by 0x402F42: main (thebridge.c:381)
==32321==  Address 0x6766234 is 20 bytes after a block of size 2,016 alloc'd
==32321==    at 0x4C27CC2: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32321==    by 0x40E10F: CreatePort(config_entry*, char*, AfCmd, int) (configvars.cpp:1267)
==32321==    by 0x43588F: ParseConfigLine (configfile.c:201)
==32321==    by 0x435BAE: parse_configfile (configfile.c:298)
==32321==    by 0x435B67: parse_configfile (configfile.c:294)
==32321==    by 0x435C81: read_config (configfile.c:328)
==32321==    by 0x40DD58: DoConfigPass (configvars.cpp:1147)
==32321==    by 0x431914: ReadConfig (thebridge.c:566)
==32321==    by 0x431A41: StartRunning (thebridge.c:415)
==32321==    by 0x402F42: main (thebridge.c:381)
(...)
I tried to use placement new in a bigger buffer and it worked.
Then found something weird:
in `configvars.cpp' sizeof(CPort) is 2016
in `ports.cpp' sizeof(CPort) is 2400

I suppose that they hold different definitions of the class, maybe an error in the makefile that compiles them with incorrect flags.


Edit: seeing the output of the preprocessor (-E flag), when compiling `configvars.cpp' it is not defined the macro __NEEDPORTAUDIO__ so lines 325--340 of ports.h are ignored

After fixing that, in runs find through valgrind (well it still complains about your bad format string with `fprintf()' )
Last edited on
Hi triple5,

Yep. I think you nailed it.

ports.h is indeed used in several places. Actually, it is used to generate 4 different objects. Due to the way I set the "#ifdef"s, the class has more variables in ports.o then in the three other objects. This probably caused the issue.


And it was MY code! Mea culpa, mea culpa, mea maxima culpa! :-(


Pfff! Thanks! This is something I found never have found myself.

I did try valgrind myself, but I have completely no experience with it. So I didn't see that.

If you ever are in Belgium, I'll buy you a beer (real Belgian beer, that is!)
OK?


Cheerio! Kr. Bonne.
Topic archived. No new replies allowed.