Port driver memory free

Casper <>
Fri Mar 18 11:04:57 CET 2005


Raimo,

Actually I allocate a binary. Here's what I do,

----------------------- C Port -----------------------------
int gen_reply(char **rbuf, int rlen, int *rindex, void *buffer, int buflen)
{
	ErlDrvBinary 	*drv_binary;
	char 			*p;

	*rindex = 0;
	........
	........
	for (p = NULL;;) {
		if (ei_encode_version(p, rindex)
				|| ei_encode_tuple_header(p, rindex, 2)
				|| ei_encode_atom(p, rindex, "ok")
				|| ei_encode_binary(p, rindex, buffer,
buflen)) {
			DBG("ei_encode failed");
			return((int) ERL_DRV_ERROR_ERRNO);
		}
		if (p)
			break;
		//if (*rindex > rlen) {
			*rbuf = driver_alloc_binary(*rindex);
		//}
		drv_binary = (ErlDrvBinary *) *rbuf;
		p = drv_binary->orig_bytes;
		*rindex = 0;
	}

	drv_binary->orig_size = *rindex;
	........
----------------------------------------------------------

I had to comment out the "(*rindex > rlen)" part since when it was there,
what I received in the emulator side was garbage after 8th char position.

------------------------- Emulator -----------------------
case catch binary_to_term(erlang:port_control(Port, Command,
term_to_binary(Args))) of 
	{'EXIT', Reason} ->
	.......
----------------------------------------------------------

On the emulator side binary_to_term BIF didn't give any error. But once
receive the term, the binary part contain incorrect data after 8th char pos.


Thanks!
- Eranga


-----Original Message-----
From: 
[mailto:] On Behalf Of Raimo Niskanen
Sent: Friday, March 18, 2005 2:31 PM
To: 
Subject: Re: Port driver memory free

Yes, you do it wrong. The returned value _must_ be a binary, 
(or NULL for R10B or later). The code that takes care of the value
assumes it is a binary, so you have introduced something in your
system that is assumed to be a binary, but is actually stack allocated
plain memory. The emulator will probably crash much later because
memory has been trashed. 

You will get partially correct behaviour because the receiving code 
looks for the contents of the binary, and finds something there. 
Unfortunately the header is not correct and it has not been allocated 
with driver_alloc_binary(), but will later be freed with 
driver_free_binary(), and both the contents and header will be
overwritten with garbage as soon as the emulator C stack grows.

Do not do that - you will get hurt!



 (Casper) writes:

> Hi,
> 
> Today I noticed a funny thing with Port drivers "control" call.
> 
> I set the mode to PORT_CONTROL_FLAG_BINARY and use **rbuf as it is
(without
> reinitializing), since the space I need to output the binary message is
less
> than 64 bytes.
> 
> When I decode the received binary message in the emulator side, up to 7
> bytes were exactly as I encoded in the C Port side. After that 8 position
> onward I get some other value.
> 
> Then I created a new binary using driver_alloc_binary, even though the
> output (encoded, total) is less than 64 bytes and tried, and viola, the
> correct message came to emulator side.
> 
> If that a bug or something I do wrong?
> 
> Thanks!
> - Eranga
> 
> 
> 
> -----Original Message-----
> From: 
> [mailto:] On Behalf Of Raimo Niskanen
> Sent: Thursday, March 17, 2005 2:17 PM
> To: 
> Subject: Re: Port driver memory free
> 
> The short answer is: do not free! 
> 
> To elaborate:
> * In binary mode, you must return a binary:
>     ErlDrvBinary *binp = driver_alloc_binary(len);
>     /* Copy len bytes of data to to binp->orig_bytes */
>     *rbuf = (char *)binp;
>     return len;
>   The caller (the emulator) will increment the refcount and take care 
>   of deallocation when the binary is no longer used.
> * In list mode, if the supplied result buffer is too small, you
>   should allocate a new result buffer using driver_alloc(size),
>   and the caller (the emulator) will free it it has fetched the
>   result from it. Otherwise just write the result in the supplied
>   result buffer. The emulator compares the returned buffer address
>   with the supplied buffer address to see if you return an allocated
>   buffer. So, if you set *rbuf, it _must_ be to something allocated 
>   with driver_alloc(size), because it _will_ be freed with 
>   driver_free(*rbuf). You can of course return an allocated buffer
>   for any size, also less than 64 bytes.
> 
> 
> 
>  (Casper) writes:
> 
> > Hi All,
> > 
> > There are 2 parameters, **rbuf and rlen in Port Driver entry "control.
In
> > PORT_CONTROL_FLAG_BINARY mode, I should pass a driver_binary in **rbuf.
> > Usually rlen is 64, which mean **rbuf has 64 bytes, if I need to use
that
> > without creating a new ErlDrvBinary. My questions are,
> > 
> > 1. If my final ErlDrvBinary size is < 64 bytes and I use **rbuf without
> > allocating a new ErlDrvBinary, should I still call driver_free_binary or
> > driver_free to free that **rbuf memory before "control" function
returns?
> > 
> > 2. If my final ErlDrvBinary size is > 64 bytes and I allocate a new
> > driver_binary and assign to **rbuf, what will happen to the previous 64
> > buffer which was in **rbuf? Will the port or erlang garbage collecter
free
> > that? Or do I need to free it inside the "control" function by calling
> > driver_free_binary or driver_free?
> > 
> > 3. I (2) above, what will be the case if I use driver_realloc or
> > driver_realloc_binary? Will the previous 64 byes get released?
> > 
> > 4. I (2) above, I still need to call driver_free_binary to free the
newly
> > created driver_binary inside "control" function, correct?
> > 
> > 5. If I call "set_port_control_flags(dd->port, 0)" to set the port
output
> to
> > non-binary, do I need to free or clear the non-used space of **rbuf?
> > 
> > 6. In above cased which free function, driver_free_binary or driver_free
> and
> > which allocation function, driver_alloc, driver_alloc_binary,
> > driver_realloc, driver_realloc_binary should I use?
> > 
> > Thanks in advance!
> > - Eranga
> > 
> > 
> 
> -- 
> 
> / Raimo Niskanen, Erlang/OTP, Ericsson AB
> 

-- 

/ Raimo Niskanen, Erlang/OTP, Ericsson AB




More information about the erlang-questions mailing list