[Ruby ext en C] [BUG] Bus Error | Segmentation fault

Le
pere.noel
déjà la différence entre Bus Error et Segmentation fault est-elle
significative ?

je suis tjs dans mon ext ruby en C, au 1ier appel de fonction
CoreFundation.

apparemment il y a un argument de la fonction
"CFURLCreateWithFileSystemPath" qui ne "passe pas" au run time :

VALUE m_raliasfile_init(VALUE self, VALUE alias_path)
{
///Users/yvon/Desktop/alias_good
printf("From C => alias_path : %s", StringValuePtr(alias_path));
rb_iv_set(self, "@alias_path", alias_path);
Boolean NO=(Boolean)Qfalse;
CFURLRef url = NULL;
url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
(CFStringRef)alias_path, 0, NO);
if (url != NULL) {
printf("From C => url != NULL");
}
return self;
}

c'est "(CFStringRef)alias_path" bien sûr j'ai essyé autre chose, par ex
"(CFStringRef)StringValuePtr(alias_path)" sans succes

--
une bévue
Vos réponses Page 1 / 2
Trier par : date / pertinence
luc
Le #488070
Une bévue
url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
(CFStringRef)alias_path, 0, NO);


Ta variable alias_path est de type VALUE, un pointeur opaque spécifique
à Ruby, que tu cast sauvagement en CFStringRef. Ca ne peut pas
fonctionner (un bon petit bouquin sur le C te dirait des tas de choses
intéressantes au sujet des pointeurs et des casts... :>).

Ce qu'il faut faire:

/* Créer une CFStringRef à partir de la VALUE */
/* (l'encoding peut varier) */
CFStringRef path = CFStringCreateWithCString(
kCFAllocatorDefault,
StringValuePtr(alias_path),
kCFStringEncodingUTF8);

/* Créer une CFURLRef à partir de la CFStringRef */
CFURLRef url = CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
path,
kCFURLPOSIXPathStyle,
false);

Ne pas oublier de faire le ménage avec:

CFRelease(path);
CFRelease(url);

PS: le cast sauvage de QFalse en Boolean est hautement suspect aussi (en
plus d'être totalement inutile ici, d'ailleurs).

--
Luc Heinrich

Eric Levenez
Le #488069
Le 15/08/06 8:50, dans

déjà la différence entre Bus Error et Segmentation fault est-elle
significative ?


Un Segmentation Fault indique un problème de MMU : le programme essaye
d'accéder à une zone mémoire non mappée en mémoire virtuelle du programme.
Donc typiquement mauvais pointeur. Pour la petite histoire les premiers unix
utilisaient de la mémoire segmentée alors qu'elle est maintenant mappée avec
des pages, mais le terme est resté.

Un Bus Error est une erreur d'entrée/sortie physique et dépend surtout du
type de périphérique à l'adresse pointée. Sur un bus PCI par exemple, cela
peut indiquer que le périphérique ne répond pas. Sur un bus mémoire, cela
peut-être une lecture à une adresse impaire... Cela dépend du CPU et du
périphérique.

--
Éric Lévénez -- Unix is not only an OS, it's a way of life.

pere.noel
Le #488068
Luc Heinrich
Ta variable alias_path est de type VALUE, un pointeur opaque spécifique
à Ruby, que tu cast sauvagement en CFStringRef. Ca ne peut pas
fonctionner (un bon petit bouquin sur le C te dirait des tas de choses
intéressantes au sujet des pointeurs et des casts... :>).


on vient de me donner une ref sur fr.comp.lang.c...
ben oui, je suis conscient de ça, je trouve qu'il a été nettement plus
difficile, pour moi, d'écrire une petite classe en C qu'en ObjC.

mais bon, je reste confiant, j'ai passé (avec beaucoup d'aides il est
vrai) les deux premiers barrages que je voyaient :

- une classe "squelette", qui ne faisait rien d'autre que retourner le
paramètre d'entrée et pour les autre méthodes des valeurs "bidons" mais
plausibles et conformes du point de vue type.

- utiliser une méthode CF### depuis C...



Ce qu'il faut faire:

/* Créer une CFStringRef à partir de la VALUE */
/* (l'encoding peut varier) */
CFStringRef path = CFStringCreateWithCString(
kCFAllocatorDefault,
StringValuePtr(alias_path),
kCFStringEncodingUTF8);


oui, c'est la solution.

/* Créer une CFURLRef à partir de la CFStringRef */
CFURLRef url = CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
path,
kCFURLPOSIXPathStyle,
false);

Ne pas oublier de faire le ménage avec:

CFRelease(path);
CFRelease(url);


oui, j'avais ça dans ma version ObjC, mais pas encore dans cette version
C ...

merci de m'y avoir fait penser.


PS: le cast sauvage de QFalse en Boolean est hautement suspect aussi (en
plus d'être totalement inutile ici, d'ailleurs).


tjs dans la version ObjC j'utilisait NO directement pensant que c'est
une constante, en C ca ne va pas, par contre, à la place de "NO" j'ai
mis "bêtement" Qfalse,: et ça roule :

url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_ref, 0,
Qfalse);

c'est curieux que la constante "kCFAllocatorDefault" soit retrouvée mais
pas "NO"

mais je n'ai fait qu'un "#include "CFURL.h""...

--
une bévue

pere.noel
Le #488067
Eric Levenez

Un Segmentation Fault indique un problème de MMU : le programme essaye
d'accéder à une zone mémoire non mappée en mémoire virtuelle du programme.
Donc typiquement mauvais pointeur. Pour la petite histoire les premiers unix
utilisaient de la mémoire segmentée alors qu'elle est maintenant mappée avec
des pages, mais le terme est resté.

Un Bus Error est une erreur d'entrée/sortie physique et dépend surtout du
type de périphérique à l'adresse pointée. Sur un bus PCI par exemple, cela
peut indiquer que le périphérique ne répond pas. Sur un bus mémoire, cela
peut-être une lecture à une adresse impaire... Cela dépend du CPU et du
périphérique.


OK, merci pour cette longue et précise réponse.
--
une bévue

luc
Le #488065
Une bévue
url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_ref, 0,
Qfalse);
c'est curieux que la constante "kCFAllocatorDefault" soit retrouvée mais
pas "NO"


Non, ce n'est pas curieux, c'est normal. YES/NO sont spécifiques à
Objective-C, QFalse/QTrue sont spécifique à Ruby, etc. Et chacun
définissant des valeurs dans leur coin pour ces deux constantes, il est
plus qu'hasardeux de les utiliser de manière interchangeable.

Quand une methode doit recevoir un BOOL il vaut mieux passer un BOOL et
pas autre chose, quand une fonction doit recevoir un Boolean il vaut
mieux passer un Boolean et pas autre chose, etc, etc. Et pour passer
d'un type à un autre, le cast n'est *absolument pas* suffisant.

Pourquoi ?

Le runtime Objective-C définit le type BOOL et les constantes YES et NO
de la manière suivante:

typedef signed char BOOL;
#define NO (BOOL)0
#define YES (BOOL)1

Ruby définit le type VALUE et les constantes QTrue est QFalse de la
manière suivante:

typedef unsigned long VALUE;
#define Qfalse ((VALUE)0)
#define Qtrue ((VALUE)2)

On peut déjà remarquer les types ne sont pas compatibles quand à leur
"taille". Qu'en est il de leur valeurs ? Un petit exemple:

#include
typedef signed char BOOL;
#define NO (BOOL)0
#define YES (BOOL)1

typedef unsigned long VALUE;
#define Qfalse ((VALUE)0)
#define Qtrue ((VALUE)2)

int main(int argc, char const* argv[])
{
BOOL true1 = YES;
VALUE true2 = Qtrue;

if (true1 == true2)
{
printf("YES == Qtruen");
}
else
{
printf("YES != Qtruen");
}

return 0;
}

Hé oui -> YES != Qtrue

mais je n'ai fait qu'un "#include "CFURL.h""...


#include
--
Luc Heinrich

pere.noel
Le #487829
Luc Heinrich

Non, ce n'est pas curieux, c'est normal. YES/NO sont spécifiques à
Objective-C, QFalse/QTrue sont spécifique à Ruby, etc. Et chacun
définissant des valeurs dans leur coin pour ces deux constantes, il est
plus qu'hasardeux de les utiliser de manière interchangeable.

Quand une methode doit recevoir un BOOL il vaut mieux passer un BOOL et
pas autre chose, quand une fonction doit recevoir un Boolean il vaut
mieux passer un Boolean et pas autre chose, etc, etc. Et pour passer
d'un type à un autre, le cast n'est *absolument pas* suffisant.

Pourquoi ?


OK, merci, pigé, donc à la page
<http://developer.apple.com/documentation/Cocoa/Conceptual/LowLevelFileM
gmt/Tasks/ResolvingAliases.html>

Apple est fautif (???) car il passe un (BOOL)NO à un CF### qui réclame
un Booléan ???

ou y a t'il entre patoit Apple un auto-boxing ?

[...]


Hé oui -> YES != Qtrue

mais je n'ai fait qu'un "#include "CFURL.h""...


#include

oui, c'était fait ça, mais n'est-ce qu'une convention comme le dit
systématiquement le "path" de recherche est utilisé dans le cas des <>
pas dans le cas des "" (user) ?

et d'ailleurs ce path-là on le retrouve en ENV vars ???

--
une bévue


Eric Levenez
Le #487828
Le 15/08/06 15:38, dans

Luc Heinrich

mais je n'ai fait qu'un "#include "CFURL.h""...


#include

oui, c'était fait ça, mais n'est-ce qu'une convention comme le dit
systématiquement le "path" de recherche est utilisé dans le cas des <>
pas dans le cas des "" (user) ?


En C on peut faire :

#include <nom>
#include "nom"
#include token

Dans le dernier cas, le token doit être une macro qui va retourner un des 2
cas du dessus.

Le "nom" est une chaîne qui sera transcodée comme l'en-tête à include (pas
forcément un nom de fichier).

Sous unix, il est de tradition que "nom" soit directement un nom de fichier
(dont le PATH est défini dans le compilateur) contenant l'en-tête à inclure.

Sous unix, il est aussi de tradition que la seconde syntaxe inclut plus de
répertoires dans le PATH.

Vu l'historique de "cc" et de "gcc", pour faire un beau code sous unix, et
donc sous Mac OS X, on utilise <> pour les includes système et "" pour les
includes utilisateur.

Les options type -I servent à bidouiller le comportement des 2 types
d'includes.

--
Éric Lévénez -- Unix is not only an OS, it's a way of life.



pere.noel
Le #487825
Eric Levenez

En C on peut faire :

#include <nom>
#include "nom"
#include token
[...]

Sous unix, il est de tradition que "nom" soit directement un nom de fichier
(dont le PATH est défini dans le compilateur) contenant l'en-tête à inclure.

Sous unix, il est aussi de tradition que la seconde syntaxe inclut plus de
répertoires dans le PATH.


ah bon tu veux bien dire la version #include "nom", j'aurais cru que le
path inclurait moins de répetoires, donc tu veux dire que ça inclus "."
et ce qui est déjà inclus dans path pour la version #include <nom> ???

--
une bévue

pere.noel
Le #487562
Luc Heinrich
typedef unsigned long VALUE;
#define Qfalse ((VALUE)0)
#define Qtrue ((VALUE)2)

int main(int argc, char const* argv[])
{
BOOL true1 = YES;
VALUE true2 = Qtrue;

if (true1 == true2)
{
printf("YES == Qtruen");
}
else
{
printf("YES != Qtruen");
}

return 0;
}

Hé oui -> YES != Qtrue


OK, donc j'ai regardé ça "d'un peu plus près"...

dans "RUBY_EXT" je lis :

Data in Ruby are represented by C type `VALUE'.

dans "ruby.h" j'ai :

/* special contants - i.e. non-zero and non-fixnum constants */
#define Qfalse ((VALUE)0)
#define Qtrue ((VALUE)2)
#define Qnil ((VALUE)4)
#define Qundef ((VALUE)6) /* undefined value for placeholder */

ailleurs :

The following Ruby constants can be referred from C.

Qtrue
Qfalse

Boolean values. Qfalse is false in C also (i.e. 0).

Qnil

Ruby nil in C scope.


et Mister Apple dit que :

CFBooleanGetValue
Obtains the value of the specified CFBoolean object as the standard C
type Boolean.
Boolean CFBooleanGetValue (
CFBooleanRef boolean
);
Parameter Descriptions
boolean
The CFBoolean object whose value you wish to obtain.
function result The value of the specified CFBoolean object.
Availability
Available in CarbonLib v1.0 and later. Available in Mac OS X v10.0 and
later.


donc, si j'ai bien compris ce qui précède dans :

CFURLCreateWithFileSystemPath

Creates a CFURL object using a local file system path string.

CFURLRef CFURLCreateWithFileSystemPath (
CFAllocatorRef allocator,
CFStringRef filePath,
CFURLPathStyle pathStyle,
Boolean isDirectory
);


le "Boolean isDirectory" est du standard C (???)

et à la page
<http://developer.apple.com/documentation/Cocoa/Conceptual/LowLevelFileM
gmt/index.html?http://developer.apple.com/documentation/Cocoa/Conceptual
/LowLevelFileMgmt/Tasks/ResolvingAliases.html>

l'appel à cette fonction ce fait en ObjC par :

url = CFURLCreateWithFileSystemPath(NULL /*allocator*/,
(CFStringRef)path, kCFURLPOSIXPathStyle, NO /*isDirectory*/);

donc une constante NO realtive à ObjC dont tu dis quelle est définie par
:


Le runtime Objective-C définit le type BOOL et les constantes YES et NO
de la manière suivante:

typedef signed char BOOL;
#define NO (BOOL)0
#define YES (BOOL)1


là la page en question est fautive alors de passer ce "NO" ???

c'est un "coup de bol" si ça marche (ie parce que c'est un NO qui est
passé) avec un YES ça n'aurait pas marché ???

Conclusion dans mon cas où j'utilise Qfalse et Qtrue, pas de problème ni
avec les CF### ni avec C ???

me goure-je ?
--
une bévue

Eric Levenez
Le #487561
Le 15/08/06 18:32, dans

ah bon tu veux bien dire la version #include "nom", j'aurais cru que le


Pourquoi croyais-tu cela ?

path inclurait moins de répetoires, donc tu veux dire que ça inclus "."
et ce qui est déjà inclus dans path pour la version #include <nom> ???


C'est typiquement le comportement de gcc, oui.

--
Éric Lévénez -- Unix is not only an OS, it's a way of life.

Publicité
Poster une réponse
Anonyme