No se puede compilar con GCC en Ubuntu 12.04

No se puede compilar con GCC en Ubuntu 12.04

Estoy intentando compilar y ejecutar el siguiente programa C en mis máquinas Ubuntu y Windows con GCC y VC9. Sin embargo, me enfrento a los siguientes problemas:

En la máquina Ubuntu:

GCC se compila bien, pero cuando se ejecuta, aparece este mensaje:

Segmentation Fault (Core Dump).

En una máquina con Windows:

VC9 se compila y funciona bien. GCC se compila bien, pero el proceso finaliza cuando se ejecuta el programa.

Necesita su ayuda experta aquí. Aquí está mi código:

#include <string.h>
#include <stdio.h>

int calc_slope(int input1,int input2)
{
    int sum=0;
    int start=input1;
    int end=input2;
    int curr=start;

    //some validation:
    if (input1>input2)
        return -1;


    while(curr<=end)
    {
        if (curr>100)
        {
            char *s="";
            int length;
            int left;
            int right;
            int cent;

            sprintf(s,"%d",curr);
            length=strlen(s);
            s++;
            do
            {
                //printf("curr=%d char=%c pointer=%d length=%d \n",curr,*s,s,length);
                left = *(s-1) - '0';
                cent = *s - '0';
                right = *(s+1) - '0';
                //printf("curr=%d l=%d c=%d r=%d\n",curr,left,cent,right);
                if ( (cent>left && cent>right) || (cent<left && cent<right) )
                {
                    sum+=1; //we have either a maxima or a minima.
                }

                s++;
            } while (*(s+1)!='\0');
        }
        curr++;
    }

    return sum;
}

int main()
{
    printf("%d",calc_slope(1,150));
    return 0;
}

Actualizar:

El crédito va aElíasno solo por ayudarme a rastrear el error, sino también por presentarme gdbsu herramienta de rastreo ( bt), que es muy útil para depurar un programa compilado de gcc. Aquí está la versión modificada, la preparé después de algunas pruebas y errores:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int calc_slope(int input1,int input2)
{
    int sum=0;
    int start=input1;
    int end=input2;
    int curr=start;

    //some validation:
    if (input1>input2)
        return -1;


    while(curr<=end)
    {
        if (curr>100)
        {
            int size=10;
            char *s=(char*)malloc((size+1) * sizeof(char));
            int left;
            int right;
            int cent;

            sprintf(s,"%d",curr);
            s++;
            do
            {
                left = *(s-1) - '0';
                cent = *s - '0';
                right = *(s+1) - '0';
                if ( (cent>left && cent>right) || (cent<left && cent<right) )
                {
                    sum+=1; //we have either a maxima or a minima.
                }

                s++;
            } while (*(s+1)!='\0');
        }
        curr++;
    }

    return sum;
}

int main()
{
    printf("%d",calc_slope(1,150));
    return 0;
}

Respuesta1

AFallo de segmentaciónOcurre cuando un programa intenta acceder a la memoria fuera del área que le ha sido asignada.

En este caso, un programador experimentado en C puede ver que el problema ocurre en la línea donde sprintfse llama. Pero si no puede saber dónde está ocurriendo su falla de segmentación, o si no quiere molestarse en leer el código paraintentarPara resolverlo, puede crear su programa con símbolos de depuración (con gcc, la -gbandera hace esto) y luego ejecutarlo a través de un depurador.

Copié tu código fuente y lo pegué en un archivo al que nombré slope.c. Luego lo construí así:

gcc -Wall -g -o slope slope.c

( -WallEs opcional. Es solo para que genere advertencias para más situaciones. Esto también puede ayudar a descubrir qué podría estar mal).

Luego ejecuté el programa en el depurador gdbejecutando primero gdb ./slopepara iniciar gdbcon el programa y luego, una vez en el depurador, dándole el runcomando al depurador:

ek@Kip:~/source$ gdb ./slope
GNU gdb (GDB) 7.5-ubuntu
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/ek/source/slope...done.
(gdb) run
Starting program: /home/ek/source/slope 
warning: Cannot call inferior functions, you have broken Linux kernel i386 NX (non-executable pages) support!

Program received signal SIGSEGV, Segmentation fault.
0x001a64cc in _IO_default_xsputn () from /lib/i386-linux-gnu/libc.so.6

(No se preocupe por mi mensaje you have broken Linux kernel i386 NX... support; no impide gdbque se use de manera efectiva para depurar este programa).

Esa información es muy críptica... y si no tiene símbolos de depuración instalados para libc, recibirá un mensaje aún más críptico que tiene una dirección hexadecimal en lugar del nombre de la función simbólica _IO_default_xsputn. Afortunadamente, no importa, porque lo que realmente queremos saber esdonde en tu programael problema está sucediendo.

Entonces, la solución es mirar hacia atrás, para ver qué llamadas a funciones tuvieron lugar antes de esa llamada a función en particular en una biblioteca del sistema donde SIGSEGVfinalmente se activó la señal.

gdb(y cualquier depurador) tiene esta característica incorporada: se llamaseguimiento de pilaorastrear. Utilizo el btcomando depurador para generar un seguimiento en gdb:

(gdb) bt
#0  0x001a64cc in _IO_default_xsputn () from /lib/i386-linux-gnu/libc.so.6
#1  0x00178e04 in vfprintf () from /lib/i386-linux-gnu/libc.so.6
#2  0x0019b234 in vsprintf () from /lib/i386-linux-gnu/libc.so.6
#3  0x0017ff7b in sprintf () from /lib/i386-linux-gnu/libc.so.6
#4  0x080484cc in calc_slope (input1=1, input2=150) at slope.c:26
#5  0x08048578 in main () at slope.c:52
(gdb)

Puede ver que su mainfunción llama a la calc_slopefunción (que pretendía) y luego calc_slopellama a sprintf, que se implementa (en este sistema) con llamadas a un par de otras funciones de biblioteca relacionadas.

Lo que generalmente le interesa es la llamada a función.en tu programaque llama a una funciónfuera de tu programa. A menos que haya un error en la biblioteca o bibliotecas que está utilizando (en este caso, la biblioteca C estándar libcproporcionada por el archivo de biblioteca libc.so.6), el error que causa el bloqueo está en su programa ya menudoestará en o cerca de la última llamadaen su programa.

En este caso, eso es:

#4  0x080484cc in calc_slope (input1=1, input2=150) at slope.c:26

Ahí es donde llama su programa sprintf. Lo sabemos porque sprintfes el siguiente paso. Pero incluso sin decir eso, lo sabes porqueeso es lo que pasa en la línea 26, y dice:

... at slope.c:26

En su programa, la línea 26 contiene:

            sprintf(s,"%d",curr);

(Siempre debe usar un editor de texto que muestre automáticamente los números de línea, al menos para la línea en la que se encuentra actualmente. Esto es muy útil para interpretar tanto los errores en tiempo de compilación como los problemas en tiempo de ejecución revelados al usar un depurador).

Como se discutió enLa respuesta de Dennis Kaarsemaker, ses una matriz de un byte. (No es cero, porque el valor que le has asignado, "", tiene una longitud de un byte, es decir, es igual a { '\0' }, de la misma manera que "Hello, world!\n"es igual a { 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n', '\0' }.)

Entonces por quépodría¿Esto todavía funciona en alguna plataforma (y aparentemente funciona cuando se compila con VC9 para Windows)?

La gente suele decir que cuando asignas memoria y luego intentas acceder a la memoria fuera de ella, se produce un error. Pero eso no es realmente cierto. Según los estándares técnicos C y C++, lo que esto realmente produce escomportamiento indefinido.

En otras palabras, ¡cualquier cosa puede pasar!

Aún así, algunas cosas son más probables que otras. ¿Por qué una pequeña matriz en la pila, en algunas implementaciones, parecerá funcionar como una matriz más grande en la pila?

Esto se reduce a cómo se implementa la asignación de pila, que puede variar de una plataforma a otra. Su ejecutable puede asignar más memoria a su pila de la que realmente está destinada a usarse en un momento dado. A veces esto puede permitirle escribir en ubicaciones de memoria que no tieneexplícitamentereclamado en su código. Es muy probable que esto sea lo que sucede cuando crea su programa en VC9.

Sin embargo,No deberías confiar en este comportamiento ni siquiera en VC9.Potencialmente, podría depender de diferentes versiones de bibliotecas que podrían existir en diferentes sistemas Windows. Peroaún más probableEl problema es que el espacio de pila adicional se asigna con la intención de que realmente se utilice, por lo queen realidad puede usarse.Luego experimentas toda la pesadilla del "comportamiento indefinido", donde, en este caso, más de una variable podría terminar almacenada en el mismo lugar, donde escribir en una sobrescribe la otra... pero no siempre, porque a veces se escribe en variables. se almacenan en caché en registros y en realidad no se realizan inmediatamente (o las lecturas de variables pueden almacenarse en caché, o se puede suponer que una variable es la misma que antes porque el compilador sabe que la memoria asignada a ella no se ha escrito a través de la propia variable).

Y eso me lleva a la otra posibilidad probable de por qué el programa funcionó cuando se creó con VC9. Es posible, y algo probable, quealguna matriz u otra variableen realidad fue asignado por su programa (lo que puede incluir ser asignado por una biblioteca que su programa esté usando) para usar el espacio después de la matriz de un byte s. Entonces, tratarlo scomo una matriz de más de un byte tendría el efecto de acceder al contenido de esa/esas variables/matrices, lo que también podría ser malo.

En conclusión, cuando cometes un error como este, esafortunadopara obtener un error como "Fallo de segmentación" o "Fallo de protección general". Cuando ustednoSi lo tiene, es posible que no se dé cuenta hasta que sea demasiado tarde de que su programa tienecomportamiento indefinido.

Respuesta2

¡Hola desbordamiento del buffer!

char *s="";
sprintf(s,"%d",curr);
length=strlen(s);

Asigna un byte para una cadena en la pila y luego procede a escribirle más de un byte. Y para colmo, lees más allá del final de esa matriz. Lea un manual de C y especialmente la sección sobre cadenas y asignación de memoria para ellas.

información relacionada