0

I have to integrate the code from tetgen (mesh generator), which is obviously used quite often. However, I have to use the old version (1.4.3 instead of 1.5) and this gives me a 'write access violation'. The relevant function is here:

void tetgenmesh::dummyinit(int tetwords, int shwords)
{
  unsigned long alignptr;

  // Set up 'dummytet', the 'tetrahedron' that occupies "outer space".
  dummytetbase = (tetrahedron *) new char[tetwords * sizeof(tetrahedron)
                                          + tetrahedrons->alignbytes];
  // Align 'dummytet' on a 'tetrahedrons->alignbytes'-byte boundary.
  alignptr = (unsigned long) dummytetbase;
  dummytet = (tetrahedron *)
    (alignptr + (unsigned long) tetrahedrons->alignbytes
     - (alignptr % (unsigned long) tetrahedrons->alignbytes));
  // Initialize the four adjoining tetrahedra to be "outer space". These
  //   will eventually be changed by various bonding operations, but their
  //   values don't really matter, as long as they can legally be
  //   dereferenced.
  dummytet[0] = (tetrahedron) dummytet;
  dummytet[1] = (tetrahedron) dummytet;
  dummytet[2] = (tetrahedron) dummytet;
  dummytet[3] = (tetrahedron) dummytet;
...
...
...
}

'dummytetbase' and 'dummytet' are both double*** pointers, tetrahedron is a double** pointer.

Example values are:

'tetwords' is : 12.

'(unsigned long)tetrahedrons->alignbytes' : 8.

'tetwords*sizeof( tetrahedron ) + tetrahedrons->alignbytes' is : 104.

'(alignptr % (unsigned long)tetrahedrons->alignbytes)' is : 0.

The code compiles fine, but when the pointer cast from 'dummytet' to 'dummytet[0]' should be done, I get this 'write access violation'.

So, dummytet gets the adress of dummytetbase + 8. And also dummytet[x] get all the same adress, but this leads to the write violation.

Any idea why this happens? Thanks!

sciloop
  • 1
  • 1
  • this is the original code from tetgen. I didn`t change a single word... – sciloop Apr 18 '17 at 11:43
  • I replaced 'unsigned long' with 'uint32_t', but the write access violation is still there... – sciloop Apr 18 '17 at 13:40
  • It's hard to tell really what's going on without debugging. Perhaps try to find who to email that maintains the library. – AndyG Apr 18 '17 at 13:47
  • Yes. Though, when debugging, vs simply tells that there is a 'write access violation' at the specific address. – sciloop Apr 18 '17 at 16:52
  • you can verify if the resulting pointer for dummytet is within the allocated memory. Also that the memory was indeed properly allocated and is big enough to hold a tetrahedron – AndyG Apr 18 '17 at 16:57
  • can you tell me how to do that? What I currently see is that the address of 'dummytet' is that of 'dummytetbase' plus 8 bytes. Moreover, the initial memory location of 'dummytet' makes no problem. Its the pointer conversion from 'dummytet' to 'dummytet[0]'. But how can that be? The address should be identical, right? – sciloop Apr 18 '17 at 22:16

1 Answers1

0

Simple: double*** and double** are totally different types. double*** points to a double** while double** points to a double*. Apply this logic recursively.

Now since both are pointers, the compiler will use 32 or 64 bits for both. You can tell the compiler to shut up, cast the difference away, and ignore this problem at compile time. That means your compile-time problem now has run-time symptoms.

Take a step back: If you have a T* ptr and need a T value, you don't write (T) ptr. You write *ptr, or ptr[5], or something like that. This still holds when T==double**.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • yes, I understand what you say. But this would mean that the tetgen code has a builtin error...This version is around for 7 years, has found its way into several programs...and nobody so far complained? So, you say, this technique of initializing the double** pointer with the address of the corresponding double*** pointer is generally invalid, right? If I now look it, that seems reasonable to me, too. – sciloop Apr 19 '17 at 13:34
  • @sciloop: Compilers are *incredibly* picky, so I'm going to be as well. "initializing the `double**` pointer with **the address of** the corresponding double*** pointer" is yet another question. The address of an `double***` is a `double****`. That's 4 stars, and a type we hadn't seen in this question before. You can't initialize a `double**` with either a `double***` or a `double****`. – MSalters Apr 19 '17 at 13:38
  • ah, yes sorry for the 'address of the double***...So, what was the intention of the tetgen creator if thats not possible. If I understood the code correctly, no memory was reserved for the double** pointers, right? Does this mean, that the code is generally not working? – sciloop Apr 19 '17 at 13:46
  • @sciloop: The code indeed appears to be invalid, and exhibiting Undefined Behavior. But it also looks like the problems might only surface under higher optimization levels, when the optimizer is applying logic like "this `double**` cannot point to that `double**`, since a `double**` can only point to a `double*`. So `dummytet[0]` cannot be equal to `dummytet`". Older compilers didn't have such smart optimizers, so that might explain why the code appeared to work in the past. – MSalters Apr 19 '17 at 13:56
  • ok, so there`s nothing I can do as the optimization is already set to 'Disabled (/Od)'. Thanks! – sciloop Apr 19 '17 at 14:49
  • I found another example where there`s a cast of a triple pointer to a double pointer so that a contiguous array can be used here: 'https://stackoverflow.com/questions/2438142/dynamic-memory-allocation-for-3d-array'. Look at 'void*** newarray(int icount, int jcount, int kcount, int type_size)'. Doesn`t this serve a similar purpose as the code from tetgen? – sciloop Apr 19 '17 at 21:39