Desreferenciar un puntero fuera de límite que contiene la dirección de un objeto (matriz de matriz)

5 minutos de lectura

Desreferenciar un puntero fuera de limite que contiene la direccion
chico curioso

¿Está bien definida la siguiente, para diferentes valores de REF?

#include <stdio.h>

#define REF 1
#define S 1

int main(void) {
    int a[2][S] = {{1},{2}};
    int *q = REF ? a[1] : 0;
    int *p = a[0] + S;
    memcpy (&q, &p, sizeof q);
    printf ("q[0] = %d\n", q[0]);
    return 0;
}

Tenga en cuenta que p apunta al después del último elemento de a[0]no a un elemento en la matriz a[0], por lo tanto no desreferenciable. Pero la dirección almacenada en p es la dirección de a[1][0]. p semánticamente (¿intencionalmente?) apunta “a” (bueno, fuera de) a[0] pero físicamente apunta a a[1].

¿Puede una copia del patrón de bits de un puntero apuntar semánticamente a un objeto cuando el original solo lo hace físicamente?

VER TAMBIÉN

He hecho esencialmente la misma pregunta de C/C++ con un “ángulo” diferente:

  • ¿Las variables de puntero son solo números enteros con algunos operadores o son “místicas”?
  • ¿Memcpy de un puntero es lo mismo que asignación?
  • Sobrescribir un objeto con un objeto del mismo tipo (solo C++)

  • a no es realmente una matriz de matrices, es una matriz que tiene acceso bidimensional. En este caso, la memoria se asignará como un bloque y se manejará internamente como un bloque unidimensional.

    – Sami Kuhmonen

    17 de agosto de 2015 a las 6:17

  • @SamiKuhmonen Entonces, ¿está diciendo que no hay límite de matriz, siempre que me quede dentro de un bloque? Entonces a[0][1] ¿está bien?

    – chico curioso

    17 de agosto de 2015 a las 6:20

  • No diría que está bien, ya que todavía se está superando semánticamente, pero con un puntero sin procesar puede acceder a la memoria de forma consecutiva. Tratando de encontrar un documento de estufa de autor sobre esta asignación

    – Sami Kuhmonen

    17 de agosto de 2015 a las 6:23


  • Si apunta uno más allá de una matriz, ¡es muy posible que haya alguna otra variable allí! Como el puntero no es desreferenciable, no debería importarle.

    – Bo Person

    17 de agosto de 2015 a las 7:27

  • @BoPersson aquí elimino la referencia del pasador de un puntero de matriz, hay un objeto allí y mi intención es cambiarlo.

    – chico curioso

    17 de agosto de 2015 a las 7:36

Dado

int blah(int x, int y)
{
  int a[2][5];
  a[1][0] = x;
  a[0][y] = 9;
  return a[1][0];
}

nada en el Estándar prohibiría a un compilador recodificar eso como int blah(int x, int y) { return x; }ni atrapar (o hacer cualquier cosa) cuando y>=5ya que a[0] y a[1] son arreglos distintos de cinco elementos cada uno. En los casos en que el último elemento de una estructura a la que se accede indirectamente es una matriz de un solo elemento, los compiladores generalmente incluyen código para permitir que la aritmética de punteros en esa matriz proporcione un puntero al almacenamiento fuera de la estructura. Si bien dicha aritmética de punteros estaría prohibida por el estándar, permite construcciones útiles que no podrían implementarse en la práctica de ninguna manera compatible con el estándar antes de C99.

Tenga en cuenta que sumando 5 a a[0] produciría un int* que se compara idéntico a a[1], pero el hecho de que un puntero de “un pasado” se compare con un puntero que identifica el siguiente objeto en la memoria no implica que pueda usarse de forma segura para acceder al último objeto. Dichos accesos a menudo pueden funcionar, pero eso no significa que los compiladores estén obligados a hacerlo.

  • Entiendo que los punteros con igual valor numérico pueden tener distintos valores semánticos, pero copio el valor numérico con memcpy. Es memcpy ¿magia? ¿Puede transferir el valor semántico?

    – chico curioso

    18 de agosto de 2015 a las 21:08

  • @curiousguy: la teoría moderna del compilador parece sugerir que los compiladores son libres de tener memcpy o memmove traer consigo la procedencia de un puntero o no, según les parezca. El único tipo de “depuración” que conozco que se requiere que realice memcpy es resolver cualquier problema de alias estricto con respecto al contenido copiado. Dado void *p=malloc(sizeof (long)); long *lp=p; short *sp=p; *lp=1234; memmove(sp,lp,sizeof(short)); printf("%d",*sp); los memmove haría el acceso a *sp bien definido. Sin memmove sería Comportamiento indefinido. Tenga en cuenta que memcpy produciría UB directamente.

    – Super gato

    18 de agosto de 2015 a las 23:24

1647641886 298 Desreferenciar un puntero fuera de limite que contiene la direccion
Grzegorz Szpetkowski

¿Puede una copia del patrón de bits de un puntero apuntar semánticamente a un objeto cuando el original solo lo hace físicamente?

No hay tal distinción efectivamente, porque a[0] + S es lo mismo que a[1]asumiendo que la matriz interna se declara con S Talla.

La siguiente:

int a[2][S];

declara una matriz de dos elementos, donde cada elemento es una matriz de S-elementos de tipo int. Los arreglos se almacenan juntos y no hay relleno antes/entre/después de sus elementos.

Probaremos, que a[0] + S == a[1] sostiene Se puede reescribir como:

*(a + 0) + S == *(a + 1)

Por aritmética de punteros, RHS agrega 1 * sizeof(*a) bytes a a, que es el mismo que el tamaño de la matriz interna. LHS es un poco más complejo, ya que la suma se realiza después desreferencia de apor lo que agrega:

S * sizeof(**a) bytes,

Se garantiza que ambos lados son iguales cuando apuntan al mismo objeto (la misma ubicación de memoria), del mismo tipo. Por lo tanto, podría reescribirlo en forma “absoluta” de un byte como:

(char *)a + S * sizeof(**a) == (char *)a + sizeof(*a)

Esto se reduce a:

S * sizeof(**a) == sizeof(*a)

Sabemos, esa sub-matriz *a posee S elementos de tipo de **a (es decir int), por lo que ambos desplazamientos son iguales. QED

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad