From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 109fba,582dff0b3f065a52 X-Google-Attributes: gid109fba,public X-Google-Thread: 1014db,582dff0b3f065a52 X-Google-Attributes: gid1014db,public X-Google-Thread: 103376,bc1361a952ec75ca X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2001-08-06 23:11:08 PST Path: archiver1.google.com!newsfeed.google.com!newsfeed.stanford.edu!sn-xit-01!supernews.com!newshub2.rdc1.sfba.home.com!news.home.com!news1.rdc1.bc.home.com.POSTED!not-for-mail From: kaz@ashi.footprints.net (Kaz Kylheku) Newsgroups: comp.lang.ada,comp.lang.c,comp.lang.c++ Subject: Re: How Ada could have prevented the Red Code distributed denial of service attack. References: <3b690498.1111845720@news.worldonline.nl> <9kbu15$9bj@augusta.math.psu.edu> <3b6a453c.1193942215@news.worldonline.nl> <9keejl$fhj@augusta.math.psu.edu> <3c30da40.0108060848.796d9bd9@posting.google.com> <3B6F3216.F410BBFF@home.com> <3B6F3FAE.B9B9FFCF@globetrotter.qc.ca> <3B6F5BB2.A879B933@worldnet.att.net> Organization: Psycho-Neurotic Institute for the Very, Very Nervous Reply-To: kaz@ashi.footprints.net User-Agent: slrn/0.9.6.3 (Linux) Message-ID: <%DLb7.26505$B37.537792@news1.rdc1.bc.home.com> Date: Tue, 07 Aug 2001 06:11:07 GMT NNTP-Posting-Host: 24.68.85.82 X-Complaints-To: abuse@home.net X-Trace: news1.rdc1.bc.home.com 997164667 24.68.85.82 (Mon, 06 Aug 2001 23:11:07 PDT) NNTP-Posting-Date: Mon, 06 Aug 2001 23:11:07 PDT Xref: archiver1.google.com comp.lang.ada:11453 comp.lang.c:72620 comp.lang.c++:80568 Date: 2001-08-07T06:11:07+00:00 List-Id: In article <3B6F5BB2.A879B933@worldnet.att.net>, James Rogers wrote: >Specifically, how would you code the C++ program to contain all the >checks built in by the Ada compiler, including the checks done at >compile time? How would you, without overwhelming work, convert >an Ada multi-tasking program using Ada protected objects for >asynchronous task communication, into C++? Since you don't have tasking in C++, you'd have to define some classes for tasking and be prepared to port them. Or you could use an existing framework for multitasking like ACE. Lastly, you could define your implementaion language as being C++ plus POSIX, and use POSIX threads. There are some portable POSIX threads implementations for non-POSIX platforms, like Win32. >For example, how would you, without overwhelming work, convert the >following Ada code: >----------------------------------------------------------------------------- >-- Inventory >-- Protected object for use of production lines >----------------------------------------------------------------------------- > generic > > Max_Size : Positive; > type Items is private; > > package Inventory is > > subtype Buf_Index is Positive range 1..Max_Size; > type Parts_Buffer is array(Buf_Index) of Items; > > protected type Parts_Buf is > Entry Put(Item : in Items); > Entry Get(Item : out Items); > private > Buffer : Parts_Buffer; > Oldest : Positive := 1; > Newest : Positive := 1; > Size : Natural := 0; > end Parts_Buf; > > type Parts_Buf_Ptr is access Parts_Buf; > > end Inventory; > > > package body Inventory is > > --------------- > -- Parts_Buf -- > --------------- > protected body Parts_Buf is > > --------- > -- Get -- > --------- > > entry Get (Item : out Items) when Size > 0 is > begin > Item := Buffer(Oldest); > if Oldest < Buffer'Last then > Oldest := Oldest + 1; > else > Oldest := Buffer'First; > end if; > Size := Size - 1; > end Get; > > --------- > -- Put -- > --------- > > entry Put (Item : in Items) when Size < Buffer'Last is > begin > Buffer(Newest) := Item; > if Newest < Buffer'Last then > Newest := Newest + 1; > else > Newest := Buffer'First; > end if; > Size := Size + 1; > end Put; > > end Parts_Buf; > end Inventory; > >You will need to implement the full functionality of protected objects >including entry queuing, object locking, and boundary conditions. Not really. I just need some class representing a mutex and conditoin variable, call them Mutex and Condition. Let's assume I have these classes. #include // for size_t namespace Inventory { template class PartsBuffer { private: Item itemBuf[BufferSize]; size_t oldestItem; size_t newestItem; size_t numItemsInBuffer; Mutex mutex; // not standard C++, ah well Condition cond; private: bool BufferIsFull() { numItemsInBuffer == BufferSize; } bool BufferIsEmpty() { numItemsInBuffer == 0; } public: PartsBuffer() : oldestItem(0) , newestItem(0) , numItemsInBuffer(0) { } void Put(Item it) { mutex.Lock(); while (BufferIsFull()) mutex.Wait(&cond); itemBuf[newestItem] = it; newestItem = (newestItem + 1) % BufferSize; numItemsInBuffer++; mutex.Unlock(); cond.Broadcast(); } Item Get() { mutex.Lock(); while (BufferIsEmpty()) mutex.Wait(&cond); Item returnedItem = itemBuf[oldestItem]; oldestItem = (oldestItem + 1) % BufferSize; numItemsInBuffer--; mutex.Unlock(); cond.Broadcast(); return returnedItem; } }; } >if you could also define arrays with a beginning index of 1 rather >than 0, but you would probably assert that 0 based indexing is What advantage is there in indexing a buffer starting at 1? A circular buffer is hardly a data structure that requires 1 based arrays. There is no significance to the absolute value of the array index of a circular buffer, that's why it's called circular. >Oh yes, when calling the Put and Get entries, your code must execute >in the calling thread. That thread must suspend until the entry >executes. > >The entry may only execute when the boundary condition is true, and >no other entry is concurrently accessing the protected object. All done by the mutex and condition waits. >You will have to implement the protected object as a template to be >equivalent. This means that you must find some way to specify that >one of the generic parameters is an integer greater than or equal to >1. If the parameter does not meet this requirement the code must not >compile. Putting the check in runtime code is not equivalent. In the C++ code, this translates to a need to verify that the BufferSize template parameter is greater than zero. The constraint on array declarations will take care of this for me: If the parameter is zero or negative, the array will be declared as having zero or negative elements. (The parameter can't be negative because it's an unsigned type, size_t). (In general, you can write a compile_time_assert() macro which exploits array constraint checks in order to verify some predicate over a constant expression. I learned this trick from Chris Torek of BSDi, Inc). >To make the code truly equivalent you must not define your data to >be dynamically allocated. All items placed on the buffer must be >statically allocated. Done: it's a simple low-level array that's integrated into the objects. No std::vector or similar braindamage. It doesn't have range checks, but then the array indices are under control of the class, and can be verified to be correct, and the *user* of the class can't cause any harm using Put/Get, which are the only public functions other than the constructor. The purpose of this class is to provide a safe ring buffer; we have built a safe thing out of some unsafe elements.