1 
2 #include <assert.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 
7 #include "pub_core_basics.h"
8 #include "pub_core_libcbase.h"
9 #include "pub_core_libcassert.h"
10 #include "pub_core_libcprint.h"
11 
12 // I need this to avoid some signedness warnings, not sure why
13 // #define Char char
14 // jrs 19 Aug 2005: m_oset.c relies on Char being a signed char.
15 // It appears that plain 'char' on ppc32 is unsigned and so the
16 // above #define screws up the AVL tree balancing logic and
17 // leads to segfaults.  Commenting it out and using the standard
18 // definition of Char from pub_core_basics.h seems a good solution
19 // as that has the same signedness on all platforms.
20 
21 // Crudely redirect various VG_(foo)() functions to their libc equivalents.
22 #undef vg_assert
23 #define vg_assert(e)                   assert(e)
24 #undef vg_assert2
25 #define vg_assert2(e, fmt, args...)    assert(e)
26 
27 #define vgPlain_printf                 printf
28 #define vgPlain_memset                 memset
29 #define vgPlain_memcpy                 memcpy
30 #define vgPlain_memmove                memmove
31 #define vgPlain_strcmp                 strcmp
32 
33 // Crudely replace some functions (in m_xarray.c, but not needed for
34 // this unit test) by (hopefully) failing asserts.
35 #define vgPlain_ssort(a,b,c,d) assert(a)
36 #define vgPlain_vcbprintf(a,b,...) assert(a == b)
37 #include "coregrind/m_xarray.c"
38 #undef vgPlain_ssort
39 #undef vgPlain_vcbprintf
40 #include "coregrind/m_poolalloc.c"
41 #include "coregrind/m_oset.c"
42 
43 #define NN  1000       // Size of OSets being created
44 
45 
46 /* Consistent random number generator, so it produces the
47    same results on all platforms. */
48 
49 #define random error_do_not_use_libc_random
50 
51 static UInt seed = 0;
myrandom(void)52 static UInt myrandom( void )
53 {
54   seed = (1103515245 * seed + 12345);
55   return seed;
56 }
57 
allocate_node(const HChar * cc,SizeT szB)58 static void* allocate_node(const HChar* cc, SizeT szB)
59 { return malloc(szB); }
60 
free_node(void * p)61 static void free_node(void* p)
62 { return free(p); }
63 
64 
65 //---------------------------------------------------------------------------
66 // Word example
67 //---------------------------------------------------------------------------
68 
69 // This example shows that an element can be a single value (in this
70 // case a Word), in which case the element is also the key.
71 
72 __attribute__((unused))
wordToStr(const void * p)73 static const HChar *wordToStr(const void *p)
74 {
75    static HChar buf[32];
76    sprintf(buf, "%ld", *(Word*)p);
77    return buf;
78 }
79 
80 __attribute__((unused))
wordCmp(void * vkey,void * velem)81 static Word wordCmp(void* vkey, void* velem)
82 {
83    return *(Word*)vkey - *(Word*)velem;
84 }
85 
example1singleset(OSet * oset,char * descr)86 void example1singleset(OSet* oset, char *descr)
87 {
88    Int  i, n;
89    UWord v, prev;
90    UWord* vs[NN];
91    UWord *pv;
92    UWord  sorted_elts[NN]; // Used to test VG_(OSetGen_ResetIterAt)
93 
94    // Try some operations on an empty OSet to ensure they don't screw up.
95    vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
96    vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
97    vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
98    vg_assert( ! VG_(OSetGen_Next)(oset) );
99    vg_assert( 0 == VG_(OSetGen_Size)(oset) );
100 
101    // Create some elements, with gaps (they're all even) but no dups,
102    // and shuffle them randomly.
103    for (i = 0; i < NN; i++) {
104       vs[i] = VG_(OSetGen_AllocNode)(oset, sizeof(Word));
105       *(vs[i]) = 2*(i+1);
106       sorted_elts[i] = *(vs[i]);
107    }
108    seed = 0;
109    for (i = 0; i < NN; i++) {
110       UWord r1  = myrandom() % NN;
111       UWord r2  = myrandom() % NN;
112       UWord* tmp= vs[r1];
113       vs[r1]   = vs[r2];
114       vs[r2]   = tmp;
115    }
116 
117    // Insert the elements
118    for (i = 0; i < NN; i++) {
119       VG_(OSetGen_Insert)(oset, vs[i]);
120    }
121 
122    // Check the size
123    vg_assert( NN == VG_(OSetGen_Size)(oset) );
124 
125    // Check we can find all the elements we inserted
126    for (i = 0; i < NN; i++) {
127       assert( VG_(OSetGen_Contains)(oset, vs[i]) );
128    }
129 
130 #define FULLCHECKEVERY 20
131    // Check VG_(OSetGen_ResetIterAt) works before, at, and after each element.
132    // For some elements, we check all the successive elements.
133    for (i = 0; i < NN; i++) {
134       UWord k;
135       UWord *pval;
136       Int j;
137 
138       // check ResetIterAt just before an elt gives this elt.
139       k = sorted_elts[i] - 1;
140       VG_(OSetGen_ResetIterAt) (oset, &k);
141       // Check all elts till the end
142       for (j = i; j < NN; j++) {
143          pval = VG_(OSetGen_Next)(oset);
144          assert (*pval == sorted_elts[j]);
145          if (i % FULLCHECKEVERY != 0) break;
146       }
147 
148       // check ResetIterAt at an elt gives this elt.
149       k = sorted_elts[i];
150       VG_(OSetGen_ResetIterAt) (oset, &k);
151       // Check all elts till the end
152       for (j = i; j < NN; j++) {
153          pval = VG_(OSetGen_Next)(oset);
154          assert (*pval == sorted_elts[j]);
155          if (i % FULLCHECKEVERY != 0) break;
156       }
157 
158       // check ResetIterAt after an elt gives the next elt or nothing
159       // when we reset after the last elt.
160       k = sorted_elts[i] + 1;
161       VG_(OSetGen_ResetIterAt) (oset, &k);
162       if (i < NN - 1) {
163          for (j = i+1; j < NN; j++) {
164             pval = VG_(OSetGen_Next)(oset);
165             assert (*pval == sorted_elts[j]);
166             if (i % FULLCHECKEVERY != 0) break;
167          }
168       } else {
169          pval = VG_(OSetGen_Next)(oset);
170          assert (pval == NULL);
171       }
172 
173    }
174 
175    // Check we cannot find elements we did not insert, below, within (odd
176    // numbers), and above the inserted elements.
177    v = 0;
178    assert( ! VG_(OSetGen_Contains)(oset, &v) );
179    for (i = 0; i < NN; i++) {
180       v = *(vs[i]) + 1;
181       assert( ! VG_(OSetGen_Contains)(oset, &v) );
182    }
183    v = 2*(NN+1);
184    assert( ! VG_(OSetGen_Contains)(oset, &v) );
185 
186    // Check we can find all the elements we inserted, and the right values
187    // are returned.
188    for (i = 0; i < NN; i++) {
189       assert( vs[i] == VG_(OSetGen_Lookup)(oset, vs[i]) );
190    }
191 
192    // Check that we can iterate over the OSet elements in sorted order, and
193    // there is the right number of them.
194    n = 0;
195    pv = NULL;
196    prev = 0;
197    VG_(OSetGen_ResetIter)(oset);
198    while ( (pv = VG_(OSetGen_Next)(oset)) ) {
199       UWord curr = *pv;
200       assert(prev < curr);
201       prev = curr;
202       n++;
203    }
204    assert(NN == n);
205    vg_assert( ! VG_(OSetGen_Next)(oset) );
206    vg_assert( ! VG_(OSetGen_Next)(oset) );
207 
208    // Check that we can remove half of the elements, and that their values
209    // are as expected.
210    for (i = 0; i < NN; i += 2) {
211       pv = VG_(OSetGen_Remove)(oset, vs[i]);
212       assert( pv );
213       assert( pv == vs[i] );
214    }
215 
216    // Check the size
217    vg_assert( NN/2 == VG_(OSetGen_Size)(oset) );
218 
219    // Check we can find the remaining elements (with the right values).
220    for (i = 1; i < NN; i += 2) {
221       pv = VG_(OSetGen_LookupWithCmp)(oset, vs[i], NULL);
222       assert( pv );
223       assert( pv == vs[i] );
224    }
225 
226    // Check we cannot find any of the elements we removed.
227    for (i = 0; i < NN; i += 2) {
228       assert( ! VG_(OSetGen_Contains)(oset, vs[i]) );
229    }
230 
231    // Check that we can remove the remaining half of the elements, and that
232    // their values are as expected.
233    for (i = 1; i < NN; i += 2) {
234       pv = VG_(OSetGen_Remove)(oset, vs[i]);
235       assert( pv );
236       assert( pv == vs[i] );
237    }
238 
239    // Try some more operations on the empty OSet to ensure they don't screw up.
240    vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
241    vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
242    vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
243    vg_assert( ! VG_(OSetGen_Next)(oset) );
244    vg_assert( 0 == VG_(OSetGen_Size)(oset) );
245 
246    // Free a few elements
247    VG_(OSetGen_FreeNode)(oset, vs[0]);
248    VG_(OSetGen_FreeNode)(oset, vs[1]);
249    VG_(OSetGen_FreeNode)(oset, vs[2]);
250 
251    // Re-insert remaining elements, to give OSetGen_Destroy something to
252    // work with.
253    for (i = 3; i < NN; i++) {
254       VG_(OSetGen_Insert)(oset, vs[i]);
255    }
256 
257    // Print the list
258    OSet_Print(oset, descr, wordToStr);
259 
260 }
261 
example1(void)262 void example1(void)
263 {
264    OSet *oset, *oset_empty_clone;
265 
266    // Create a static OSet of UWords.  This one uses fast (built-in)
267    // comparisons.
268 
269    // First a single oset, no pool allocator.
270    oset = VG_(OSetGen_Create)(0,
271                               NULL,
272                               allocate_node, "oset_test.1", free_node);
273    example1singleset(oset, "single oset, no pool allocator");
274 
275    // Destroy the OSet
276    VG_(OSetGen_Destroy)(oset);
277 
278    // Then same, but with a group allocator
279    oset = VG_(OSetGen_Create_With_Pool)(0,
280                                         NULL,
281                                         allocate_node, "oset_test.1",
282                                         free_node,
283                                         101, sizeof(Word));
284    example1singleset(oset, "single oset, pool allocator");
285 
286    // Destroy the OSet
287    VG_(OSetGen_Destroy)(oset);
288 
289 
290    // Then two sets, sharing a group allocator.
291    oset = VG_(OSetGen_Create_With_Pool)
292       (0,
293        NULL,
294        allocate_node, "oset_test.1", free_node,
295        101, sizeof(Word));
296    oset_empty_clone = VG_(OSetGen_EmptyClone) (oset);
297    example1singleset(oset, "oset, shared pool");
298    example1singleset(oset_empty_clone, "cloned oset, shared pool");
299    // Destroy both OSet
300 
301    VG_(OSetGen_Destroy)(oset_empty_clone);
302    VG_(OSetGen_Destroy)(oset);
303 
304 }
305 
example1b(void)306 void example1b(void)
307 {
308    Int  i, n;
309    UWord v = 0, prev;
310    UWord vs[NN];
311 
312    // Create a static OSet of UWords.  This one uses fast (built-in)
313    // comparisons.
314    OSet* oset = VG_(OSetWord_Create)(allocate_node, "oset_test.2", free_node);
315 
316    // Try some operations on an empty OSet to ensure they don't screw up.
317    vg_assert( ! VG_(OSetWord_Contains)(oset, v) );
318    vg_assert( ! VG_(OSetWord_Remove)(oset, v) );
319    vg_assert( ! VG_(OSetWord_Next)(oset, (UWord *)&v) );
320    vg_assert( 0 == VG_(OSetWord_Size)(oset) );
321 
322    // Create some elements, with gaps (they're all even) but no dups,
323    // and shuffle them randomly.
324    for (i = 0; i < NN; i++) {
325       vs[i] = 2*i;
326    }
327    seed = 0;
328    for (i = 0; i < NN; i++) {
329       UWord r1  = myrandom() % NN;
330       UWord r2  = myrandom() % NN;
331       UWord tmp = vs[r1];
332       vs[r1]   = vs[r2];
333       vs[r2]   = tmp;
334    }
335 
336    // Insert the elements
337    for (i = 0; i < NN; i++) {
338       VG_(OSetWord_Insert)(oset, vs[i]);
339    }
340 
341    // Check the size
342    vg_assert( NN == VG_(OSetWord_Size)(oset) );
343 
344    // Check we can find all the elements we inserted
345    for (i = 0; i < NN; i++) {
346       assert( VG_(OSetWord_Contains)(oset, vs[i]) );
347    }
348 
349    // Check we cannot find elements we did not insert, below, within (odd
350    // numbers), and above the inserted elements.
351    v = 0xffffffff;
352    assert( ! VG_(OSetWord_Contains)(oset, v) );
353    for (i = 0; i < NN; i++) {
354       v = vs[i] + 1;
355       assert( ! VG_(OSetWord_Contains)(oset, v) );
356    }
357    v = NN*2;
358    assert( ! VG_(OSetWord_Contains)(oset, v) );
359 
360    // Check we can find all the elements we inserted.
361    for (i = 0; i < NN; i++) {
362       assert( VG_(OSetWord_Contains)(oset, vs[i]) );
363    }
364 
365    // Check that we can iterate over the OSet elements in sorted order, and
366    // there is the right number of them.
367    n = 0;
368    prev = 0;
369    VG_(OSetWord_ResetIter)(oset);
370    while ( VG_(OSetWord_Next)(oset, (UWord *)&v) ) {
371       UWord curr = v;
372       if (n == 0)
373          assert(prev == curr);
374       else
375          assert(prev < curr);
376       prev = curr;
377       n++;
378    }
379    assert(NN == n);
380    vg_assert( ! VG_(OSetWord_Next)(oset, (UWord *)&v) );
381    vg_assert( ! VG_(OSetWord_Next)(oset, (UWord *)&v) );
382 
383    // Check that we can remove half of the elements.
384    for (i = 0; i < NN; i += 2) {
385       assert( VG_(OSetWord_Remove)(oset, vs[i]) );
386    }
387 
388    // Check the size
389    vg_assert( NN/2 == VG_(OSetWord_Size)(oset) );
390 
391    // Check we can find the remaining elements (with the right values).
392    for (i = 1; i < NN; i += 2) {
393       assert( VG_(OSetWord_Contains)(oset, vs[i]) );
394    }
395 
396    // Check we cannot find any of the elements we removed.
397    for (i = 0; i < NN; i += 2) {
398       assert( ! VG_(OSetWord_Contains)(oset, vs[i]) );
399    }
400 
401    // Check that we can remove the remaining half of the elements.
402    for (i = 1; i < NN; i += 2) {
403       assert( VG_(OSetWord_Remove)(oset, vs[i]) );
404    }
405 
406    // Try some more operations on the empty OSet to ensure they don't screw up.
407    vg_assert( ! VG_(OSetWord_Contains)(oset, v) );
408    vg_assert( ! VG_(OSetWord_Remove)(oset, v) );
409    vg_assert( ! VG_(OSetWord_Next)(oset, (UWord *)&v) );
410    vg_assert( 0 == VG_(OSetWord_Size)(oset) );
411 
412    // Re-insert remaining elements, to give OSetWord_Destroy something to
413    // work with.
414    for (i = 3; i < NN; i++) {
415       VG_(OSetWord_Insert)(oset, vs[i]);
416    }
417 
418    // Print the list
419    OSet_Print(oset, "oset1b", wordToStr);
420 
421    // Destroy the OSet
422    VG_(OSetWord_Destroy)(oset);
423 }
424 
425 
426 //---------------------------------------------------------------------------
427 // Struct example
428 //---------------------------------------------------------------------------
429 
430 // This element shows that a key can be in the middle of the element, and
431 // be of arbitrary size and even span multiple (contiguous) fields.  It
432 // also demonstrates how an OSet can be used to implement a list of
433 // non-overlapping intervals.
434 
435 typedef struct {
436    Int   b1;
437    RegWord  first;
438    RegWord  last;
439    Int   b2;
440 }
441 Block;
442 
443 __attribute__((unused))
blockToStr(void * p)444 static HChar *blockToStr(void *p)
445 {
446    static HChar buf[32];
447    Block* b = (Block*)p;
448    sprintf(buf, "<(%d) %" FMT_REGWORD "u..%" FMT_REGWORD "u (%d)>",
449            b->b1, b->first, b->last, b->b2);
450    return buf;
451 }
452 
blockCmp(const void * vkey,const void * velem)453 static Word blockCmp(const void* vkey, const void* velem)
454 {
455    RegWord   key  = *(const RegWord*)vkey;
456    const Block* elem = (const Block*)velem;
457 
458    assert(elem->first <= elem->last);
459    if (key < elem->first) return -1;
460    if (key > elem->last)  return  1;
461    return 0;
462 }
463 
example2(void)464 void example2(void)
465 {
466    Int i, n;
467    RegWord a;
468    Block* vs[NN];
469    Block v, prev;
470    Block *pv;
471 
472    // Create a dynamic OSet of Blocks.  This one uses slow (custom)
473    // comparisons.
474    OSet* oset = VG_(OSetGen_Create)(offsetof(Block, first),
475                                     blockCmp,
476                                     allocate_node, "oset_test.3", free_node);
477 
478    // Try some operations on an empty OSet to ensure they don't screw up.
479    vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
480    vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
481    vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
482    vg_assert( ! VG_(OSetGen_Next)(oset) );
483    vg_assert( 0 == VG_(OSetGen_Size)(oset) );
484 
485    // Create some inputs, with gaps -- intervals are 1..3, 11..13, ... -- but
486    // no dups, and shuffle them randomly.
487    for (i = 0; i < NN; i++) {
488       vs[i] = VG_(OSetGen_AllocNode)(oset, sizeof(Block));
489       vs[i]->b1    = i;
490       vs[i]->first = i*10 + 1;
491       vs[i]->last  = vs[i]->first + 2;
492       vs[i]->b2    = i+1;
493    }
494    seed = 0;
495    for (i = 0; i < NN; i++) {
496       Int r1  = myrandom() % NN;
497       Int r2  = myrandom() % NN;
498       Block* tmp = vs[r1];
499       vs[r1]  = vs[r2];
500       vs[r2]  = tmp;
501    }
502 
503    // Insert the elements
504    for (i = 0; i < NN; i++) {
505       VG_(OSetGen_Insert)(oset, vs[i]);
506    }
507 
508    // Check the size
509    vg_assert( NN == VG_(OSetGen_Size)(oset) );
510 
511    // Check we can find all the elements we inserted, within the full range
512    // of each Block.
513    for (i = 0; i < NN; i++) {
514       a = vs[i]->first + 0;    assert( VG_(OSetGen_Contains)(oset, &a) );
515       a = vs[i]->first + 1;    assert( VG_(OSetGen_Contains)(oset, &a) );
516       a = vs[i]->first + 2;    assert( VG_(OSetGen_Contains)(oset, &a) );
517    }
518 
519    // Check we cannot find elements we did not insert, below and above the
520    // ranges of the inserted elements.
521    a = 0;
522    assert( ! VG_(OSetGen_Contains)(oset, &a) );
523    for (i = 0; i < NN; i++) {
524       a = vs[i]->first - 1;    assert( ! VG_(OSetGen_Contains)(oset, &a) );
525       a = vs[i]->first + 3;    assert( ! VG_(OSetGen_Contains)(oset, &a) );
526    }
527 
528    // Check we can find all the elements we inserted, and the right values
529    // are returned.
530    for (i = 0; i < NN; i++) {
531       a = vs[i]->first + 0;    assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
532       a = vs[i]->first + 1;    assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
533       a = vs[i]->first + 2;    assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
534       assert( vs[i] == VG_(OSetGen_LookupWithCmp)(oset, &a, blockCmp) );
535    }
536 
537    // Check that we can iterate over the OSet elements in sorted order, and
538    // there is the right number of them.
539    n = 0;
540    pv = NULL;
541    prev.last = 0;
542    VG_(OSetGen_ResetIter)(oset);
543    while ( (pv = VG_(OSetGen_Next)(oset)) ) {
544       Block curr = *pv;
545       assert(prev.last < curr.first);
546       prev = curr;
547       n++;
548    }
549    assert(NN == n);
550    vg_assert( ! VG_(OSetGen_Next)(oset) );
551    vg_assert( ! VG_(OSetGen_Next)(oset) );
552 
553    // Check that we can remove half of the elements, and that their values
554    // are as expected.
555    for (i = 0; i < NN; i += 2) {
556       a = vs[i]->first;    assert( vs[i] == VG_(OSetGen_Remove)(oset, &a) );
557    }
558 
559    // Check the size
560    vg_assert( NN/2 == VG_(OSetGen_Size)(oset) );
561 
562    // Check we can find the remaining elements (with the right values).
563    for (i = 1; i < NN; i += 2) {
564       a = vs[i]->first + 0;    assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
565       a = vs[i]->first + 1;    assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
566       a = vs[i]->first + 2;    assert( vs[i] == VG_(OSetGen_Lookup)(oset, &a) );
567    }
568 
569    // Check we cannot find any of the elements we removed.
570    for (i = 0; i < NN; i += 2) {
571       a = vs[i]->first + 0;    assert( ! VG_(OSetGen_Contains)(oset, &a) );
572       a = vs[i]->first + 1;    assert( ! VG_(OSetGen_Contains)(oset, &a) );
573       a = vs[i]->first + 2;    assert( ! VG_(OSetGen_Contains)(oset, &a) );
574    }
575 
576    // Check that we can remove the remaining half of the elements, and that
577    // their values are as expected.
578    for (i = 1; i < NN; i += 2) {
579       a = vs[i]->first;    assert( vs[i] == VG_(OSetGen_Remove)(oset, &a) );
580    }
581 
582    // Try some more operations on the empty OSet to ensure they don't screw up.
583    vg_assert( ! VG_(OSetGen_Contains)(oset, &v) );
584    vg_assert( ! VG_(OSetGen_Lookup)(oset, &v) );
585    vg_assert( ! VG_(OSetGen_Remove)(oset, &v) );
586    vg_assert( ! VG_(OSetGen_Next)(oset) );
587    vg_assert( 0 == VG_(OSetGen_Size)(oset) );
588 
589    // Re-insert all elements, to give OSetGen_Destroy something to work with.
590    for (i = 0; i < NN; i++) {
591       VG_(OSetGen_Insert)(oset, vs[i]);
592    }
593 
594    // Destroy the OSet
595    VG_(OSetGen_Destroy)(oset);
596 }
597 
598 //-----------------------------------------------------------------------
599 // main()
600 //-----------------------------------------------------------------------
601 
main(void)602 int main(void)
603 {
604    example1();
605    example1b();
606    example2();
607    return 0;
608 }
609